[Lore] Line层最简实现与测试

21 阅读2分钟

预导入

use super::content::Content;
use super::content::parse_content;

每一行的信息包括其缩进和数据

struct Line<'f> {
    indent: usize,
    content: Content<'f>,
}

为了方便测试,为 Line 实现 Display

impl<'f> std::fmt::Display for Line<'f> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}{}", "  ".repeat(self.indent), self.content)
    }
}

借助 take_while()parse_content() ,简洁地实现格式识别。

fn parse_line(raw_line: &str) -> Line<'_> {
    let indent = raw_line
        .chars()
        .take_while(|&c| c == ' ')
        .count() / 2;
    let content = parse_content(raw_line.trim_start());

    Line {
        content,
        indent,
    }
}

测试模块如此。测试结果与预期一致。

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_line_no_indent_element() {
        let line = parse_line("simple element");
        assert!(matches!(line.content, Content::Element("simple element")));
        assert_eq!(line.indent, 0);
    }

    #[test]
    fn test_parse_content_domain() {
        let content = parse_content("+ domain text");
        assert!(matches!(content, Content::Domain("domain text")));
    }

    #[test]
    fn test_parse_content_element_with_plus_no_space() {
        let content = parse_content("+no space");
        assert!(matches!(content, Content::Element("+no space")));
    }

    #[test]
    fn test_parse_content_empty() {
        let content = parse_content("");
        assert!(matches!(content, Content::Element("")));
    }

    #[test]
    fn test_parse_line_no_indent_domain() {
        let line = parse_line("+ domain line");
        assert!(matches!(line.content, Content::Domain("domain line")));
        assert_eq!(line.indent, 0);
    }

    #[test]
    fn test_parse_line_with_indent_element() {
        let line = parse_line("  indented element");
        assert!(matches!(line.content, Content::Element("indented element")));
        assert_eq!(line.indent, 1);
    }

    #[test]
    fn test_parse_line_with_indent_domain() {
        let line = parse_line("    + indented domain");
        assert!(matches!(line.content, Content::Domain("indented domain")));
        assert_eq!(line.indent, 2); // 4 spaces = 2 indent levels
    }

    #[test]
    fn test_parse_line_only_spaces() {
        let line = parse_line("    ");
        assert!(matches!(line.content, Content::Element("")));
        assert_eq!(line.indent, 2);
    }

    #[test]
    fn test_display_line_element_no_indent() {
        let line = Line {
            content: Content::Element("element"),
            indent: 0,
        };
        assert_eq!(format!("{}", line), "element");
    }

    #[test]
    fn test_display_line_element_with_indent() {
        let line = Line {
            content: Content::Element("element"),
            indent: 2,
        };
        assert_eq!(format!("{}", line), "    element");
    }

    #[test]
    fn test_display_line_domain_no_indent() {
        let line = Line {
            content: Content::Domain("domain"),
            indent: 0,
        };
        assert_eq!(format!("{}", line), "+ domain");
    }

    #[test]
    fn test_display_line_domain_with_indent() {
        let line = Line {
            content: Content::Domain("domain"),
            indent: 1,
        };
        assert_eq!(format!("{}", line), "  + domain");
    }

    #[test]
    fn test_integration_parse_and_display() {
        let test_cases = vec![            ("no indent", "no indent"),            ("  two space indent", "  two space indent"),            ("+ domain", "+ domain"),            ("  + indented domain", "  + indented domain"),            ("    four space element", "    four space element"),        ];

        for (input, expected) in test_cases {
            let line = parse_line(input);
            assert_eq!(format!("{}", line), expected);
        }
    }

    #[test]
    fn test_odd_number_spaces_rounds_down() {
        let line = parse_line("     odd spaces");
        assert_eq!(line.indent, 2);
    }
}