grep_table_converter/
generator.rs1use anyhow::Result;
2use anyhow::anyhow;
3
4#[derive(Debug, PartialEq)]
5pub enum Mode {
6 CSV,
7 MARKDOWN,
8 TEXTILE,
9}
10
11impl Mode {
12 fn header(&self) -> String {
13 match self {
14 Mode::CSV => "file_name,line_num,content\n".to_string(),
15 Mode::MARKDOWN => "| file_name | line_num | content |\n| --- | --- | --- |\n".to_string(),
16 Mode::TEXTILE => "|file_name|line_num|content|\n".to_string(),
17 }
18 }
19
20 pub fn from(input: &str) -> Result<Mode> {
21 match input.to_lowercase().as_str() {
22 "csv" => Ok(Mode::CSV),
23 "markdown" => Ok(Mode::MARKDOWN),
24 "textile" => Ok(Mode::TEXTILE),
25 _ => Err(anyhow!("mode must be csv or markdown or textile.")),
26 }
27 }
28
29 pub fn extension(&self) -> &str {
30 match self {
31 Mode::CSV => ".csv",
32 Mode::MARKDOWN => ".md",
33 Mode::TEXTILE => ".textile",
34 }
35 }
36}
37
38#[derive(Debug)]
39struct Line<'a> {
40 file_path: &'a str,
41 line_num: &'a str,
42 remaining: &'a str,
43}
44
45impl Line<'_> {
46 fn format(&self, mode: &Mode) -> String {
47 match mode {
48 Mode::CSV => format!("{},{},{}\n", self.file_path, self.line_num, self.remaining),
49 Mode::MARKDOWN => format!("| {} | {} | {} |\n", self.file_path, self.line_num, self.remaining),
50 Mode::TEXTILE => format!("|{}|{}|{}|\n", self.file_path, self.line_num, self.remaining),
51 }
52 }
53}
54
55pub fn generate_table(content: &str, mode: &Mode) -> Result<String> {
56 let mut result = String::from(mode.header());
57 for line in content.lines() {
58 let splitted_line: Vec<&str> = line.split(":").collect();
59
60 if splitted_line.len() < 3 {
61 return Err(anyhow!("Invalid format.\nexpected: [file path]:[line number]:[code]\ngiven: {}", &content));
62 }
63
64 let line_data = Line {
65 file_path: &splitted_line[0],
66 line_num: &splitted_line[1],
67 remaining: &splitted_line[2..].join(":").to_string(),
68 };
69
70 result += line_data.format(mode).as_str();
71 }
72 Ok(result)
73}
74
75#[cfg(test)]
76mod test {
77 use super::*;
78
79 #[test]
80 fn export_mode_enum() {
81 let mode = Mode::MARKDOWN;
82 assert_eq!("MARKDOWN", format!("{:?}", &mode))
83 }
84
85 #[test]
86 fn mode_from_valid_string() {
87 let mode1 = Mode::from("CsV");
88 let mode2 = Mode::from("markDoWN");
89 let mode3 = Mode::from("TEXtile");
90 if let Ok(mode) = mode1 {
91 assert_eq!(Mode::CSV, mode);
92 } else {
93 assert!(false);
94 }
95 if let Ok(mode) = mode2 {
96 assert_eq!(Mode::MARKDOWN, mode);
97 } else {
98 assert!(false);
99 }
100 if let Ok(mode) = mode3 {
101 assert_eq!(Mode::TEXTILE, mode);
102 } else {
103 assert!(false);
104 }
105 }
106
107 #[test]
108 fn mode_fron_invalid_string() {
109 let mode = Mode::from("invalid");
110 if let Ok(_) = mode {
111 assert!(false);
112 } else {
113 assert!(true);
114 }
115 }
116
117 #[test]
118 fn get_extension() {
119 let csv_mode = Mode::CSV;
120 let md_mode = Mode::MARKDOWN;
121 let txtile_mode = Mode::TEXTILE;
122
123 assert_eq!(".csv", csv_mode.extension());
124 assert_eq!(".md", md_mode.extension());
125 assert_eq!(".textile", txtile_mode.extension());
126 }
127
128 #[test]
129 fn debug_print_line() {
130 let line = Line { file_path: "src/test.rs", line_num: "124", remaining: "this is test code." };
131 assert_eq!("Line { file_path: \"src/test.rs\", line_num: \"124\", remaining: \"this is test code.\" }", format!("{:?}", line));
132 }
133
134 #[test]
135 fn csv_result() {
136 let mode = Mode::CSV;
137 let content = r#"test.rs:155:this is test
138test.rs:201:TestCrate::test_method();
139modules/hoge_module.rs:14:println!("this is test String.");"#;
140 let expect = r#"file_name,line_num,content
141test.rs,155,this is test
142test.rs,201,TestCrate::test_method();
143modules/hoge_module.rs,14,println!("this is test String.");
144"#;
145 assert_eq!(expect, generate_table(&content, &mode).unwrap());
146 }
147
148 #[test]
149 fn markdown_result() {
150 let mode = Mode::MARKDOWN;
151 let content = r#"test.rs:155:this is test
152test.rs:201:TestCrate::test_method();
153modules/hoge_module.rs:14:println!("this is test String.");"#;
154 let expect = r#"| file_name | line_num | content |
155| --- | --- | --- |
156| test.rs | 155 | this is test |
157| test.rs | 201 | TestCrate::test_method(); |
158| modules/hoge_module.rs | 14 | println!("this is test String."); |
159"#;
160 assert_eq!(expect, generate_table(&content, &mode).unwrap());
161 }
162
163 #[test]
164 fn textile_result() {
165 let mode = Mode::TEXTILE;
166 let content = r#"test.rs:155:this is test
167test.rs:201:TestCrate::test_method();
168modules/hoge_module.rs:14:println!("this is test String.");"#;
169 let expect = r#"|file_name|line_num|content|
170|test.rs|155|this is test|
171|test.rs|201|TestCrate::test_method();|
172|modules/hoge_module.rs|14|println!("this is test String.");|
173"#;
174 assert_eq!(expect, generate_table(&content, &mode).unwrap());
175 }
176
177 #[test]
178 fn invalid_format() {
179 let mode = Mode::CSV;
180 let content = "This is a test for invalid format error.";
181 let expected_errmsg = format!("Invalid format.\nexpected: [file path]:[line number]:[code]\ngiven: {}", &content);
182 if let Err(e) = generate_table(&content, &mode) {
183 assert_eq!(expected_errmsg, format!("{:?}", e));
184 } else {
185 assert!(false, "result should be error");
186 }
187 }
188}