docs(core): add Chinese comments to types module
Add detailed Chinese comments explaining Rust derive macros, FromStr/Display traits, serde serialization, and core data types. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -1,112 +1,252 @@
|
|||||||
|
// ─── types.rs ─────────────────────────────────────────────────────────────────
|
||||||
|
// 这个文件定义了 log-viewer-core 库中使用的核心数据类型(数据模型)。
|
||||||
|
// 包括:日志级别(LogLevel)、日志条目(LogEntry)、搜索结果(SearchResult)、
|
||||||
|
// 搜索查询(SearchQuery)、搜索过滤器(SearchFilter)、书签(Bookmark)、
|
||||||
|
// 文件会话(FileSession)等。
|
||||||
|
//
|
||||||
|
// 这些类型是整个应用的"通用语言",各个模块(io、parser、tui 等)都依赖它们
|
||||||
|
// 来传递和处理数据。
|
||||||
|
// ──────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
// HashMap — 哈希表(字典)类型,用于存储键值对。
|
||||||
|
// 这里用于存储日志条目中除 timestamp/level 之外的其他 JSON 字段。
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
// fmt — 格式化模块,提供 Display trait(自定义 .to_string() 行为)。
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
// FromStr — 字符串解析 trait,允许从字符串解析为自定义类型(如 "INFO" → LogLevel::Info)。
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
// serde 是 Rust 中最流行的序列化/反序列化框架。
|
||||||
|
// - Serialize: 将 Rust 数据结构转换为其他格式(如 JSON、TOML)。
|
||||||
|
// - Deserialize: 将其他格式(如 JSON、TOML)转换回 Rust 数据结构。
|
||||||
|
// 这样 LogLevel、LogEntry 等类型就可以被序列化为 JSON 保存,或从 JSON 反序列化恢复。
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
// serde_json::Value — 可以表示任意 JSON 值的枚举类型。
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
|
// ─── LogLevel 枚举 ──────────────────────────────────────────────────────────
|
||||||
/// 日志级别
|
/// 日志级别
|
||||||
|
///
|
||||||
|
/// 表示一条日志的严重程度。不同日志系统使用不同的级别名称,
|
||||||
|
/// 这里统一定义为 5 个标准级别 + 1 个"未知"级别。
|
||||||
|
///
|
||||||
|
/// # 派生属性说明
|
||||||
|
/// - `Debug`: 允许用 `{:?}` 格式化打印,用于调试。
|
||||||
|
/// - `Clone`: 允许克隆(深拷贝)该值。
|
||||||
|
/// - `PartialEq`: 允许用 `==` 和 `!=` 比较两个值是否相等。
|
||||||
|
/// - `Eq`: 表示"完全相等"关系(PartialEq 的增强版,要求满足等价关系的数学性质)。
|
||||||
|
/// - `Hash`: 允许将该值用作 HashMap 的键(需要 Eq + Hash 配合)。
|
||||||
|
/// - `Serialize`: 允许序列化为 JSON 等格式(如 `"Info"` → JSON 字符串 `"Info"`)。
|
||||||
|
/// - `Deserialize`: 允许从 JSON 等格式反序列化(如 JSON 字符串 `"Info"` → `LogLevel::Info`)。
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub enum LogLevel {
|
pub enum LogLevel {
|
||||||
Error,
|
// 每个变体代表一种日志级别,从严重到轻微排列:
|
||||||
Warn,
|
Error, // 错误:程序出现了问题,需要关注。
|
||||||
Info,
|
Warn, // 警告:潜在的问题,不一定需要立即处理。
|
||||||
Debug,
|
Info, // 信息:一般的运行信息(最常用的级别)。
|
||||||
Trace,
|
Debug, // 调试:用于开发调试的详细信息。
|
||||||
|
Trace, // 跟踪:非常详细的调试信息(比 Debug 更细粒度)。
|
||||||
|
// Unknown 是一个"带数据的变体"(tuple variant),包含一个 String。
|
||||||
|
// 当日志级别不在上述 5 种之内时,用 Unknown 保存原始的级别字符串。
|
||||||
|
// 例如日志级别为 "CRITICAL" 时,会被解析为 Unknown("CRITICAL")。
|
||||||
Unknown(String),
|
Unknown(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── FromStr 实现:从字符串解析为 LogLevel ──────────────────────────────────
|
||||||
|
// `impl FromStr for LogLevel` 为 LogLevel 实现 FromStr trait。
|
||||||
|
// 这使得可以使用 `"INFO".parse::<LogLevel>()` 或 `str::parse::<LogLevel>(s)`
|
||||||
|
// 将字符串解析为 LogLevel 枚举值。
|
||||||
|
//
|
||||||
|
// FromStr trait 要求定义两个东西:
|
||||||
|
// 1. type Err — 解析失败时的错误类型。
|
||||||
|
// 2. fn from_str(s: &str) -> Result<Self, Self::Err> — 解析逻辑。
|
||||||
impl FromStr for LogLevel {
|
impl FromStr for LogLevel {
|
||||||
|
// `type Err = std::convert::Infallible` — 错误类型设为 Infallible("不可失败的")。
|
||||||
|
// Infallible 是一个空枚举(没有变体),表示"这个解析永远不会失败"。
|
||||||
|
// 因为对于未知的日志级别,我们返回 Unknown(...) 而不是报错,
|
||||||
|
// 所以解析操作确实不可能失败。
|
||||||
type Err = std::convert::Infallible;
|
type Err = std::convert::Infallible;
|
||||||
|
|
||||||
|
// `fn from_str(s: &str) -> Result<Self, Self::Err>` — 解析函数。
|
||||||
|
// 接收一个字符串切片 &str,返回 Result<LogLevel, Infallible>。
|
||||||
|
// 由于 Err 类型是 Infallible,实际上返回值总是 Ok(LogLevel)。
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
// `s.to_uppercase()` — 将字符串转换为大写,实现不区分大小写的匹配。
|
||||||
|
// 例如 "info"、"Info"、"INFO" 都会被转换为 "INFO"。
|
||||||
|
// 返回一个新的 String(堆分配)。
|
||||||
|
//
|
||||||
|
// `.as_str()` — 将 String 转换回 &str(字符串切片引用)。
|
||||||
|
// 因为 match 需要匹配 &str 而不是 String。
|
||||||
match s.to_uppercase().as_str() {
|
match s.to_uppercase().as_str() {
|
||||||
|
// `|` 在 match 分支中表示"或"(multiple patterns)。
|
||||||
|
// "ERROR" | "ERR" | "SEVERE" | "FATAL" 都匹配到 LogLevel::Error。
|
||||||
"ERROR" | "ERR" | "SEVERE" | "FATAL" => Ok(LogLevel::Error),
|
"ERROR" | "ERR" | "SEVERE" | "FATAL" => Ok(LogLevel::Error),
|
||||||
"WARN" | "WARNING" | "WRN" => Ok(LogLevel::Warn),
|
"WARN" | "WARNING" | "WRN" => Ok(LogLevel::Warn),
|
||||||
"INFO" | "INFORMATION" => Ok(LogLevel::Info),
|
"INFO" | "INFORMATION" => Ok(LogLevel::Info),
|
||||||
"DEBUG" | "DBG" => Ok(LogLevel::Debug),
|
"DEBUG" | "DBG" => Ok(LogLevel::Debug),
|
||||||
"TRACE" | "TRC" => Ok(LogLevel::Trace),
|
"TRACE" | "TRC" => Ok(LogLevel::Trace),
|
||||||
|
// `_` 是通配符,匹配所有未被上面分支捕获的值。
|
||||||
|
// 对于未知级别,包装为 Unknown 并保存原始字符串。
|
||||||
|
// s.to_string() 将 &str 转换为 String(注意这里用原始的 s,不是大写后的)。
|
||||||
_ => Ok(LogLevel::Unknown(s.to_string())),
|
_ => Ok(LogLevel::Unknown(s.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Display 实现:自定义 LogLevel 的显示格式 ────────────────────────────────
|
||||||
|
// `impl fmt::Display for LogLevel` 实现 Display trait,
|
||||||
|
// 定义了用 `{}` 格式化(即 .to_string())时的输出。
|
||||||
impl fmt::Display for LogLevel {
|
impl fmt::Display for LogLevel {
|
||||||
|
// `fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result`
|
||||||
|
// - &self: 对自身的不可变引用。
|
||||||
|
// - f: &mut fmt::Formatter 是格式化输出"写入器",用于写入输出字符串。
|
||||||
|
// <'_> 是生命周期省略语法,表示 Formatter 借用了一个短生命周期的引用。
|
||||||
|
// - fmt::Result: 结果类型,成功返回 Ok(()),失败返回 Err(极少见)。
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
// `write!(f, "ERROR")` — 向格式化写入器写入字符串 "ERROR"。
|
||||||
|
// write! 是一个宏(注意感叹号),类似于 println!,但写入到指定的 f 而不是标准输出。
|
||||||
LogLevel::Error => write!(f, "ERROR"),
|
LogLevel::Error => write!(f, "ERROR"),
|
||||||
LogLevel::Warn => write!(f, "WARN"),
|
LogLevel::Warn => write!(f, "WARN"),
|
||||||
LogLevel::Info => write!(f, "INFO"),
|
LogLevel::Info => write!(f, "INFO"),
|
||||||
LogLevel::Debug => write!(f, "DEBUG"),
|
LogLevel::Debug => write!(f, "DEBUG"),
|
||||||
LogLevel::Trace => write!(f, "TRACE"),
|
LogLevel::Trace => write!(f, "TRACE"),
|
||||||
|
// `{s}` 是格式化占位符,将 s 的值插入到输出字符串中。
|
||||||
|
// 例如 Unknown("custom") → "UNKNOWN(custom)"。
|
||||||
LogLevel::Unknown(s) => write!(f, "UNKNOWN({s})"),
|
LogLevel::Unknown(s) => write!(f, "UNKNOWN({s})"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── LogEntry 结构体 ────────────────────────────────────────────────────────
|
||||||
/// 一行解析后的日志
|
/// 一行解析后的日志
|
||||||
|
///
|
||||||
|
/// 表示日志文件中经过解析器处理后的一行内容。
|
||||||
|
/// 包含原始文本、行号、时间戳、日志级别以及其他 JSON 字段。
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct LogEntry {
|
pub struct LogEntry {
|
||||||
|
// `pub` 表示字段是公开的,外部代码可以直接访问。
|
||||||
|
// 如果不加 pub,字段只能在定义该结构体的模块内访问。
|
||||||
|
/// 行号(从 0 开始)
|
||||||
pub line_number: u64,
|
pub line_number: u64,
|
||||||
|
|
||||||
|
/// 原始行内容(未经处理的完整文本)
|
||||||
pub raw_line: String,
|
pub raw_line: String,
|
||||||
|
|
||||||
|
/// 时间戳(如果日志中有时间字段)。Option<String> 表示时间戳可能不存在。
|
||||||
|
/// Some("2024-01-01T00:00:00Z") 表示有时间戳,None 表示没有。
|
||||||
pub timestamp: Option<String>,
|
pub timestamp: Option<String>,
|
||||||
|
|
||||||
|
/// 日志级别(如果日志中有级别字段)。Option<LogLevel> 表示级别可能不存在。
|
||||||
pub level: Option<LogLevel>,
|
pub level: Option<LogLevel>,
|
||||||
|
|
||||||
|
/// 其他 JSON 字段(除 timestamp 和 level 外的所有字段)。
|
||||||
|
/// HashMap<String, Value> 是一个字典,键是字段名,值是 JSON 值。
|
||||||
|
/// 例如 {"message": "hello", "request_id": "abc123"}。
|
||||||
pub fields: HashMap<String, Value>,
|
pub fields: HashMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── SearchResult 结构体 ────────────────────────────────────────────────────
|
||||||
/// 搜索匹配结果
|
/// 搜索匹配结果
|
||||||
|
///
|
||||||
|
/// 记录一次搜索匹配在文件中的位置信息:
|
||||||
|
/// 在哪一行的哪个字符范围内匹配到了搜索内容。
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct SearchResult {
|
pub struct SearchResult {
|
||||||
|
/// 匹配所在的行号
|
||||||
pub line_number: u64,
|
pub line_number: u64,
|
||||||
|
/// 匹配开始处的字符偏移量(从 0 开始)
|
||||||
pub match_start: usize,
|
pub match_start: usize,
|
||||||
|
/// 匹配结束处的字符偏移量(不包含,即左闭右开区间 [match_start, match_end))
|
||||||
pub match_end: usize,
|
pub match_end: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── SearchQuery 枚举 ──────────────────────────────────────────────────────
|
||||||
/// 搜索查询
|
/// 搜索查询
|
||||||
|
///
|
||||||
|
/// 表示用户输入的搜索内容,支持两种模式:
|
||||||
|
/// - Regex: 正则表达式搜索(模式匹配)
|
||||||
|
/// - Keyword: 关键词搜索(精确文本查找)
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum SearchQuery {
|
pub enum SearchQuery {
|
||||||
|
// Regex(String) — "元组变体"(tuple variant),包含一个正则表达式字符串。
|
||||||
|
// 例如 SearchQuery::Regex("error|warn")。
|
||||||
Regex(String),
|
Regex(String),
|
||||||
|
// Keyword(String) — 包含一个关键词字符串。
|
||||||
|
// 例如 SearchQuery::Keyword("connection timeout")。
|
||||||
Keyword(String),
|
Keyword(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── SearchFilter 结构体 ────────────────────────────────────────────────────
|
||||||
/// 搜索过滤器
|
/// 搜索过滤器
|
||||||
|
///
|
||||||
|
/// 用于在搜索基础上进一步过滤结果,可以按日志级别和/或时间范围筛选。
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct SearchFilter {
|
pub struct SearchFilter {
|
||||||
|
/// 按日志级别过滤。None 表示不过滤级别;Some(vec![...]) 表示只保留这些级别。
|
||||||
|
/// Option<Vec<LogLevel>> 意味着这个过滤器字段是可选的。
|
||||||
pub levels: Option<Vec<LogLevel>>,
|
pub levels: Option<Vec<LogLevel>>,
|
||||||
|
|
||||||
|
/// 按时间范围过滤。None 表示不过滤时间;Some(("起始时间", "结束时间")) 表示只保留此范围内的日志。
|
||||||
|
/// (String, String) 是一个元组(tuple),包含起始和结束时间字符串。
|
||||||
pub time_range: Option<(String, String)>,
|
pub time_range: Option<(String, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Bookmark 结构体 ────────────────────────────────────────────────────────
|
||||||
/// 书签
|
/// 书签
|
||||||
|
///
|
||||||
|
/// 用户可以在日志中标记某一行作为书签,方便后续快速跳转。
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Bookmark {
|
pub struct Bookmark {
|
||||||
|
/// 被标记的行号
|
||||||
pub line_number: u64,
|
pub line_number: u64,
|
||||||
|
/// 书签标签(用户自定义的名称)。None 表示没有标签。
|
||||||
pub label: Option<String>,
|
pub label: Option<String>,
|
||||||
|
/// 书签创建时间(字符串形式的时间戳,如 "2024-01-01T12:00:00")
|
||||||
pub created_at: String,
|
pub created_at: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── FileSession 结构体 ─────────────────────────────────────────────────────
|
||||||
/// 打开的文件会话信息
|
/// 打开的文件会话信息
|
||||||
|
///
|
||||||
|
/// 表示当前打开的日志文件的基本信息(元数据),
|
||||||
|
/// 用于在 UI 中显示文件名、大小、行数等信息。
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct FileSession {
|
pub struct FileSession {
|
||||||
|
/// 文件路径
|
||||||
pub file_path: std::path::PathBuf,
|
pub file_path: std::path::PathBuf,
|
||||||
|
/// 用于在 UI 中显示的文件名(通常是文件名部分,不包含目录)
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
|
/// 文件总行数
|
||||||
pub total_lines: u64,
|
pub total_lines: u64,
|
||||||
|
/// 文件大小(字节)
|
||||||
pub file_size: u64,
|
pub file_size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── 单元测试 ────────────────────────────────────────────────────────────────
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
// 测试:ERROR 级别的各种写法都能正确解析。
|
||||||
|
// .parse::<LogLevel>() 利用 FromStr trait 将字符串解析为 LogLevel。
|
||||||
|
// ::<LogLevel> 是 turbofish 语法,指定泛型参数。
|
||||||
fn test_from_str_error_variants() {
|
fn test_from_str_error_variants() {
|
||||||
|
// 大写 "ERROR"
|
||||||
assert_eq!("ERROR".parse::<LogLevel>(), Ok(LogLevel::Error));
|
assert_eq!("ERROR".parse::<LogLevel>(), Ok(LogLevel::Error));
|
||||||
|
// 小写 "error" — 不区分大小写
|
||||||
assert_eq!("error".parse::<LogLevel>(), Ok(LogLevel::Error));
|
assert_eq!("error".parse::<LogLevel>(), Ok(LogLevel::Error));
|
||||||
|
// 缩写 "ERR"
|
||||||
assert_eq!("ERR".parse::<LogLevel>(), Ok(LogLevel::Error));
|
assert_eq!("ERR".parse::<LogLevel>(), Ok(LogLevel::Error));
|
||||||
|
// "SEVERE" — Java 日志中常用的严重级别
|
||||||
assert_eq!("SEVERE".parse::<LogLevel>(), Ok(LogLevel::Error));
|
assert_eq!("SEVERE".parse::<LogLevel>(), Ok(LogLevel::Error));
|
||||||
|
// "FATAL" — 表示致命错误
|
||||||
assert_eq!("FATAL".parse::<LogLevel>(), Ok(LogLevel::Error));
|
assert_eq!("FATAL".parse::<LogLevel>(), Ok(LogLevel::Error));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
// 测试:WARN 级别的各种写法。
|
||||||
fn test_from_str_warn_variants() {
|
fn test_from_str_warn_variants() {
|
||||||
assert_eq!("WARN".parse::<LogLevel>(), Ok(LogLevel::Warn));
|
assert_eq!("WARN".parse::<LogLevel>(), Ok(LogLevel::Warn));
|
||||||
assert_eq!("warn".parse::<LogLevel>(), Ok(LogLevel::Warn));
|
assert_eq!("warn".parse::<LogLevel>(), Ok(LogLevel::Warn));
|
||||||
@@ -115,6 +255,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
// 测试:INFO 级别的各种写法。
|
||||||
fn test_from_str_info_variants() {
|
fn test_from_str_info_variants() {
|
||||||
assert_eq!("INFO".parse::<LogLevel>(), Ok(LogLevel::Info));
|
assert_eq!("INFO".parse::<LogLevel>(), Ok(LogLevel::Info));
|
||||||
assert_eq!("info".parse::<LogLevel>(), Ok(LogLevel::Info));
|
assert_eq!("info".parse::<LogLevel>(), Ok(LogLevel::Info));
|
||||||
@@ -122,6 +263,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
// 测试:DEBUG 级别的各种写法。
|
||||||
fn test_from_str_debug_variants() {
|
fn test_from_str_debug_variants() {
|
||||||
assert_eq!("DEBUG".parse::<LogLevel>(), Ok(LogLevel::Debug));
|
assert_eq!("DEBUG".parse::<LogLevel>(), Ok(LogLevel::Debug));
|
||||||
assert_eq!("debug".parse::<LogLevel>(), Ok(LogLevel::Debug));
|
assert_eq!("debug".parse::<LogLevel>(), Ok(LogLevel::Debug));
|
||||||
@@ -129,6 +271,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
// 测试:TRACE 级别的各种写法。
|
||||||
fn test_from_str_trace_variants() {
|
fn test_from_str_trace_variants() {
|
||||||
assert_eq!("TRACE".parse::<LogLevel>(), Ok(LogLevel::Trace));
|
assert_eq!("TRACE".parse::<LogLevel>(), Ok(LogLevel::Trace));
|
||||||
assert_eq!("trace".parse::<LogLevel>(), Ok(LogLevel::Trace));
|
assert_eq!("trace".parse::<LogLevel>(), Ok(LogLevel::Trace));
|
||||||
@@ -136,20 +279,25 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
// 测试:无法识别的级别字符串应该解析为 Unknown 变体。
|
||||||
fn test_from_str_unknown() {
|
fn test_from_str_unknown() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"FOOBAR".parse::<LogLevel>(),
|
"FOOBAR".parse::<LogLevel>(),
|
||||||
|
// .into() 在这里将 &str 转换为 String。
|
||||||
Ok(LogLevel::Unknown("FOOBAR".into()))
|
Ok(LogLevel::Unknown("FOOBAR".into()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
// 测试:LogLevel 的 Display 输出格式是否正确。
|
||||||
fn test_display_output() {
|
fn test_display_output() {
|
||||||
assert_eq!(LogLevel::Error.to_string(), "ERROR");
|
assert_eq!(LogLevel::Error.to_string(), "ERROR");
|
||||||
assert_eq!(LogLevel::Warn.to_string(), "WARN");
|
assert_eq!(LogLevel::Warn.to_string(), "WARN");
|
||||||
assert_eq!(LogLevel::Info.to_string(), "INFO");
|
assert_eq!(LogLevel::Info.to_string(), "INFO");
|
||||||
assert_eq!(LogLevel::Debug.to_string(), "DEBUG");
|
assert_eq!(LogLevel::Debug.to_string(), "DEBUG");
|
||||||
assert_eq!(LogLevel::Trace.to_string(), "TRACE");
|
assert_eq!(LogLevel::Trace.to_string(), "TRACE");
|
||||||
|
// Unknown 变体的显示格式是 "UNKNOWN(原始字符串)"。
|
||||||
|
// .into() 将 &str 转换为 String。
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LogLevel::Unknown("custom".into()).to_string(),
|
LogLevel::Unknown("custom".into()).to_string(),
|
||||||
"UNKNOWN(custom)"
|
"UNKNOWN(custom)"
|
||||||
@@ -157,10 +305,14 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
// 测试:LogEntry 结构体的构造和字段访问。
|
||||||
fn test_log_entry_construction() {
|
fn test_log_entry_construction() {
|
||||||
|
// 创建一个 HashMap 并插入一个键值对。
|
||||||
let mut fields = HashMap::new();
|
let mut fields = HashMap::new();
|
||||||
|
// .insert() 向 HashMap 中插入键值对。
|
||||||
fields.insert("key".to_string(), Value::String("value".to_string()));
|
fields.insert("key".to_string(), Value::String("value".to_string()));
|
||||||
|
|
||||||
|
// 使用结构体字面量语法创建 LogEntry 实例。
|
||||||
let entry = LogEntry {
|
let entry = LogEntry {
|
||||||
line_number: 42,
|
line_number: 42,
|
||||||
raw_line: "test line".to_string(),
|
raw_line: "test line".to_string(),
|
||||||
@@ -169,10 +321,12 @@ mod tests {
|
|||||||
fields,
|
fields,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 逐字段验证。
|
||||||
assert_eq!(entry.line_number, 42);
|
assert_eq!(entry.line_number, 42);
|
||||||
assert_eq!(entry.raw_line, "test line");
|
assert_eq!(entry.raw_line, "test line");
|
||||||
assert_eq!(entry.timestamp, Some("2024-01-01T00:00:00".to_string()));
|
assert_eq!(entry.timestamp, Some("2024-01-01T00:00:00".to_string()));
|
||||||
assert_eq!(entry.level, Some(LogLevel::Info));
|
assert_eq!(entry.level, Some(LogLevel::Info));
|
||||||
|
// fields.get("key") 返回 Option<&Value>(值的引用)。
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
entry.fields.get("key"),
|
entry.fields.get("key"),
|
||||||
Some(&Value::String("value".to_string()))
|
Some(&Value::String("value".to_string()))
|
||||||
@@ -180,6 +334,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
// 测试:SearchResult 结构体的构造和字段访问。
|
||||||
fn test_search_result_construction() {
|
fn test_search_result_construction() {
|
||||||
let result = SearchResult {
|
let result = SearchResult {
|
||||||
line_number: 10,
|
line_number: 10,
|
||||||
|
|||||||
Reference in New Issue
Block a user