aboutsummaryrefslogtreecommitdiff
path: root/tools/src
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-02-03 19:34:35 +0000
committerAleksey Kladov <[email protected]>2018-02-03 19:34:35 +0000
commit9b3d806b0dbfcf76ff707aa86daba83454227720 (patch)
treebfefe85725b772a44a9abf3823128d08344a6b66 /tools/src
parent9435ea4b8e990521ee7a6206b6106bb3ce392746 (diff)
Add infra for inline tests
Diffstat (limited to 'tools/src')
-rw-r--r--tools/src/bin/collect-tests.rs134
1 files changed, 134 insertions, 0 deletions
diff --git a/tools/src/bin/collect-tests.rs b/tools/src/bin/collect-tests.rs
new file mode 100644
index 000000000..c54059e79
--- /dev/null
+++ b/tools/src/bin/collect-tests.rs
@@ -0,0 +1,134 @@
1extern crate file;
2extern crate walkdir;
3extern crate itertools;
4
5use walkdir::WalkDir;
6use itertools::Itertools;
7
8use std::path::{PathBuf, Path};
9use std::collections::HashSet;
10use std::fs;
11
12fn main() {
13 let verify = ::std::env::args().any(|arg| arg == "--verify");
14
15 let d = grammar_dir();
16 let tests = tests_from_dir(&d);
17 let existing = existing_tests();
18
19 for t in existing.difference(&tests) {
20 panic!("Test is deleted: {}\n{}", t.name, t.text);
21 }
22
23 let new_tests = tests.difference(&existing);
24 for (i, t) in new_tests.enumerate() {
25 if verify {
26 panic!("Inline test is not recorded: {}", t.name);
27 }
28
29 let name = format!("{:04}_{}.rs", existing.len() + i + 1, t.name);
30 println!("Creating {}", name);
31 let path = inline_tests_dir().join(name);
32 file::put_text(&path, &t.text).unwrap();
33 }
34}
35
36
37#[derive(Debug, Eq)]
38struct Test {
39 name: String,
40 text: String,
41}
42
43impl PartialEq for Test {
44 fn eq(&self, other: &Test) -> bool {
45 self.name.eq(&other.name)
46 }
47}
48
49impl ::std::hash::Hash for Test {
50 fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
51 self.name.hash(state)
52 }
53}
54
55fn tests_from_dir(dir: &Path) -> HashSet<Test> {
56 let mut res = HashSet::new();
57 for entry in WalkDir::new(dir) {
58 let entry = entry.unwrap();
59 if !entry.file_type().is_file() {
60 continue
61 }
62 if entry.path().extension().unwrap_or_default() != "rs" {
63 continue
64 }
65 let text = file::get_text(entry.path())
66 .unwrap();
67
68 for test in collect_tests(&text) {
69 if let Some(old_test) = res.replace(test) {
70 panic!("Duplicate test: {}", old_test.name)
71 }
72 }
73 }
74 res
75}
76
77fn collect_tests(s: &str) -> Vec<Test> {
78 let mut res = vec![];
79 let prefix = "// ";
80 let comment_blocks = s.lines()
81 .map(str::trim_left)
82 .group_by(|line| line.starts_with(prefix));
83
84 for (is_comment, block) in comment_blocks.into_iter() {
85 if !is_comment {
86 continue;
87 }
88 let mut block = block.map(|line| &line[prefix.len()..]);
89 let first = block.next().unwrap();
90 if !first.starts_with("test ") {
91 continue
92 }
93 let name = first["test ".len()..].to_string();
94 let text: String = itertools::join(block.chain(::std::iter::once("")), "\n");
95 assert!(!text.trim().is_empty() && text.ends_with("\n"));
96 res.push(Test { name, text })
97 }
98 res
99}
100
101fn existing_tests() -> HashSet<Test> {
102 let mut res = HashSet::new();
103 for file in fs::read_dir(&inline_tests_dir()).unwrap() {
104 let file = file.unwrap();
105 let path = file.path();
106 if path.extension().unwrap_or_default() != "rs" {
107 continue
108 }
109 let name = path.file_name().unwrap().to_str().unwrap();
110 let name = name["0000_".len()..name.len() - 3].to_string();
111 let text = file::get_text(&path).unwrap();
112 res.insert(Test { name, text });
113 }
114 res
115}
116
117fn inline_tests_dir() -> PathBuf {
118 let res = base_dir().join("tests/data/parser/inline");
119 if !res.is_dir() {
120 fs::create_dir_all(&res).unwrap();
121 }
122 res
123}
124
125fn grammar_dir() -> PathBuf {
126 base_dir().join("src/parser/event_parser/grammar")
127}
128
129fn base_dir() -> PathBuf {
130 let dir = env!("CARGO_MANIFEST_DIR");
131 PathBuf::from(dir).parent().unwrap().to_owned()
132}
133
134