aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cargo/config1
-rw-r--r--appveyor.yml1
-rw-r--r--docs/TESTS.md16
-rw-r--r--docs/TOOLS.md10
-rw-r--r--src/parser/event_parser/grammar/items/mod.rs4
-rw-r--r--tests/data/parser/inline/0001_const_unsafe_fn.rs1
-rw-r--r--tests/data/parser/inline/0001_const_unsafe_fn.txt15
-rw-r--r--tests/data/parser/inline/0002_const_fn.rs1
-rw-r--r--tests/data/parser/inline/0002_const_fn.txt13
-rw-r--r--tests/data/parser/ok/0024_const_fn.rs5
-rw-r--r--tests/data/parser/ok/0024_const_fn.txt29
-rw-r--r--tests/data/parser/ok/0024_const_item.rs (renamed from tests/data/parser/ok/0025_const_item.rs)0
-rw-r--r--tests/data/parser/ok/0024_const_item.txt (renamed from tests/data/parser/ok/0025_const_item.txt)0
-rw-r--r--tests/parser.rs2
-rw-r--r--tools/Cargo.toml2
-rw-r--r--tools/src/bin/collect-tests.rs130
16 files changed, 192 insertions, 38 deletions
diff --git a/.cargo/config b/.cargo/config
index 1ebc0f748..7d89cf490 100644
--- a/.cargo/config
+++ b/.cargo/config
@@ -1,3 +1,4 @@
1[alias] 1[alias]
2parse = "run --package tools --bin parse" 2parse = "run --package tools --bin parse"
3gen = "run --package tools --bin gen" 3gen = "run --package tools --bin gen"
4collect-tests = "run --package tools --bin collect-tests --"
diff --git a/appveyor.yml b/appveyor.yml
index a6ba3b0e1..8c7d118c8 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -10,6 +10,7 @@ install:
10build: false 10build: false
11 11
12test_script: 12test_script:
13 - cargo collect-tests --verify
13 - cargo test 14 - cargo test
14 15
15branches: 16branches:
diff --git a/docs/TESTS.md b/docs/TESTS.md
index 8005ec9da..db06dbebc 100644
--- a/docs/TESTS.md
+++ b/docs/TESTS.md
@@ -19,12 +19,26 @@ files to have the same name except for the leading number. In general,
19test suite should be append-only: old tests should not be modified, 19test suite should be append-only: old tests should not be modified,
20new tests should be created instead. 20new tests should be created instead.
21 21
22
23Note that only `ok` tests are normative: `err` tests test error 22Note that only `ok` tests are normative: `err` tests test error
24recovery and it is totally ok for a parser to not implement any error 23recovery and it is totally ok for a parser to not implement any error
25recovery at all. However, for libsyntax2.0 we do care about error 24recovery at all. However, for libsyntax2.0 we do care about error
26recovery, and we do care about precise and useful error messages. 25recovery, and we do care about precise and useful error messages.
27 26
27There are also so-called "inline tests". They appear as the comments
28with a `test` header in the source code, like this:
29
30```rust
31// test fn_basic
32// fn foo() {}
33fn fn_item(p: &mut Parser) {
34 // ...
35}
36```
37
38You can run `cargo collect-tests` command to collect all inline tests
39into `tests/data/inline` directory. The main advantage of inline tests
40is that they help to illustrate what the relevant code is doing.
41
28 42
29Contribution opportunity: design and implement testing infrastructure 43Contribution opportunity: design and implement testing infrastructure
30for validators. 44for validators.
diff --git a/docs/TOOLS.md b/docs/TOOLS.md
index 1fcfa2dec..f8754c06f 100644
--- a/docs/TOOLS.md
+++ b/docs/TOOLS.md
@@ -17,14 +17,20 @@ cargo tool
17``` 17```
18 18
19 19
20# Tool: `gen` 20## Tool: `gen`
21 21
22This tool reads a "grammar" from [grammar.ron](../grammar.ron) and 22This tool reads a "grammar" from [grammar.ron](../grammar.ron) and
23generates the `syntax_kinds.rs` file. You should run this tool if you 23generates the `syntax_kinds.rs` file. You should run this tool if you
24add new keywords or syntax elements. 24add new keywords or syntax elements.
25 25
26 26
27# Tool: 'parse' 27## Tool: `parse`
28 28
29This tool reads rust source code from the standard input, parses it, 29This tool reads rust source code from the standard input, parses it,
30and prints the result to stdout. 30and prints the result to stdout.
31
32
33## Tool: `collect-tests`
34
35This tools collect inline tests from comments in libsyntax2 source code
36and places them into `tests/data/inline` directory.
diff --git a/src/parser/event_parser/grammar/items/mod.rs b/src/parser/event_parser/grammar/items/mod.rs
index 8ccf8f90f..5cf2fc39a 100644
--- a/src/parser/event_parser/grammar/items/mod.rs
+++ b/src/parser/event_parser/grammar/items/mod.rs
@@ -52,11 +52,15 @@ fn item(p: &mut Parser) {
52 STATIC_ITEM 52 STATIC_ITEM
53 } 53 }
54 CONST_KW => match p.nth(1) { 54 CONST_KW => match p.nth(1) {
55 // test const_fn
56 // const fn foo() {}
55 FN_KW => { 57 FN_KW => {
56 p.bump(); 58 p.bump();
57 fn_item(p); 59 fn_item(p);
58 FN_ITEM 60 FN_ITEM
59 } 61 }
62 // test const_unsafe_fn
63 // const unsafe fn foo() {}
60 UNSAFE_KW if p.nth(2) == FN_KW => { 64 UNSAFE_KW if p.nth(2) == FN_KW => {
61 p.bump(); 65 p.bump();
62 p.bump(); 66 p.bump();
diff --git a/tests/data/parser/inline/0001_const_unsafe_fn.rs b/tests/data/parser/inline/0001_const_unsafe_fn.rs
new file mode 100644
index 000000000..31a1e435f
--- /dev/null
+++ b/tests/data/parser/inline/0001_const_unsafe_fn.rs
@@ -0,0 +1 @@
const unsafe fn foo() {}
diff --git a/tests/data/parser/inline/0001_const_unsafe_fn.txt b/tests/data/parser/inline/0001_const_unsafe_fn.txt
new file mode 100644
index 000000000..1f0865cb0
--- /dev/null
+++ b/tests/data/parser/inline/0001_const_unsafe_fn.txt
@@ -0,0 +1,15 @@
1FILE@[0; 25)
2 FN_ITEM@[0; 25)
3 CONST_KW@[0; 5)
4 WHITESPACE@[5; 6)
5 UNSAFE_KW@[6; 12)
6 WHITESPACE@[12; 13)
7 FN_KW@[13; 15)
8 WHITESPACE@[15; 16)
9 IDENT@[16; 19) "foo"
10 L_PAREN@[19; 20)
11 R_PAREN@[20; 21)
12 WHITESPACE@[21; 22)
13 L_CURLY@[22; 23)
14 R_CURLY@[23; 24)
15 WHITESPACE@[24; 25)
diff --git a/tests/data/parser/inline/0002_const_fn.rs b/tests/data/parser/inline/0002_const_fn.rs
new file mode 100644
index 000000000..8c84d9cd7
--- /dev/null
+++ b/tests/data/parser/inline/0002_const_fn.rs
@@ -0,0 +1 @@
const fn foo() {}
diff --git a/tests/data/parser/inline/0002_const_fn.txt b/tests/data/parser/inline/0002_const_fn.txt
new file mode 100644
index 000000000..2d360d78b
--- /dev/null
+++ b/tests/data/parser/inline/0002_const_fn.txt
@@ -0,0 +1,13 @@
1FILE@[0; 18)
2 FN_ITEM@[0; 18)
3 CONST_KW@[0; 5)
4 WHITESPACE@[5; 6)
5 FN_KW@[6; 8)
6 WHITESPACE@[8; 9)
7 IDENT@[9; 12) "foo"
8 L_PAREN@[12; 13)
9 R_PAREN@[13; 14)
10 WHITESPACE@[14; 15)
11 L_CURLY@[15; 16)
12 R_CURLY@[16; 17)
13 WHITESPACE@[17; 18)
diff --git a/tests/data/parser/ok/0024_const_fn.rs b/tests/data/parser/ok/0024_const_fn.rs
deleted file mode 100644
index eba9322a1..000000000
--- a/tests/data/parser/ok/0024_const_fn.rs
+++ /dev/null
@@ -1,5 +0,0 @@
1const fn foo() {
2}
3
4const unsafe fn foo() {
5}
diff --git a/tests/data/parser/ok/0024_const_fn.txt b/tests/data/parser/ok/0024_const_fn.txt
deleted file mode 100644
index 0fd485997..000000000
--- a/tests/data/parser/ok/0024_const_fn.txt
+++ /dev/null
@@ -1,29 +0,0 @@
1FILE@[0; 46)
2 FN_ITEM@[0; 20)
3 CONST_KW@[0; 5)
4 WHITESPACE@[5; 6)
5 FN_KW@[6; 8)
6 WHITESPACE@[8; 9)
7 IDENT@[9; 12) "foo"
8 L_PAREN@[12; 13)
9 R_PAREN@[13; 14)
10 WHITESPACE@[14; 15)
11 L_CURLY@[15; 16)
12 WHITESPACE@[16; 17)
13 R_CURLY@[17; 18)
14 WHITESPACE@[18; 20)
15 FN_ITEM@[20; 46)
16 CONST_KW@[20; 25)
17 WHITESPACE@[25; 26)
18 UNSAFE_KW@[26; 32)
19 WHITESPACE@[32; 33)
20 FN_KW@[33; 35)
21 WHITESPACE@[35; 36)
22 IDENT@[36; 39) "foo"
23 L_PAREN@[39; 40)
24 R_PAREN@[40; 41)
25 WHITESPACE@[41; 42)
26 L_CURLY@[42; 43)
27 WHITESPACE@[43; 44)
28 R_CURLY@[44; 45)
29 WHITESPACE@[45; 46)
diff --git a/tests/data/parser/ok/0025_const_item.rs b/tests/data/parser/ok/0024_const_item.rs
index 7446859b5..7446859b5 100644
--- a/tests/data/parser/ok/0025_const_item.rs
+++ b/tests/data/parser/ok/0024_const_item.rs
diff --git a/tests/data/parser/ok/0025_const_item.txt b/tests/data/parser/ok/0024_const_item.txt
index 588e001f5..588e001f5 100644
--- a/tests/data/parser/ok/0025_const_item.txt
+++ b/tests/data/parser/ok/0024_const_item.txt
diff --git a/tests/parser.rs b/tests/parser.rs
index f681c066f..68a6434be 100644
--- a/tests/parser.rs
+++ b/tests/parser.rs
@@ -7,7 +7,7 @@ use testutils::dir_tests;
7 7
8#[test] 8#[test]
9fn parser_tests() { 9fn parser_tests() {
10 dir_tests(&["parser/ok", "parser/err"], |text| { 10 dir_tests(&["parser/inline", "parser/ok", "parser/err"], |text| {
11 let tokens = tokenize(text); 11 let tokens = tokenize(text);
12 let file = parse(text.to_string(), &tokens); 12 let file = parse(text.to_string(), &tokens);
13 dump_tree(&file) 13 dump_tree(&file)
diff --git a/tools/Cargo.toml b/tools/Cargo.toml
index e46874929..8cbc2fc93 100644
--- a/tools/Cargo.toml
+++ b/tools/Cargo.toml
@@ -9,4 +9,6 @@ serde = "1.0.26"
9serde_derive = "1.0.26" 9serde_derive = "1.0.26"
10file = "1.1.1" 10file = "1.1.1"
11ron = "0.1.5" 11ron = "0.1.5"
12walkdir = "2"
13itertools = "0.7"
12libsyntax2 = { path = "../" } 14libsyntax2 = { path = "../" }
diff --git a/tools/src/bin/collect-tests.rs b/tools/src/bin/collect-tests.rs
new file mode 100644
index 000000000..df9d2db81
--- /dev/null
+++ b/tools/src/bin/collect-tests.rs
@@ -0,0 +1,130 @@
1extern crate file;
2extern crate itertools;
3extern crate walkdir;
4
5use walkdir::WalkDir;
6use itertools::Itertools;
7
8use std::path::{Path, PathBuf};
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#[derive(Debug, Eq)]
37struct Test {
38 name: String,
39 text: String,
40}
41
42impl PartialEq for Test {
43 fn eq(&self, other: &Test) -> bool {
44 self.name.eq(&other.name)
45 }
46}
47
48impl ::std::hash::Hash for Test {
49 fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
50 self.name.hash(state)
51 }
52}
53
54fn tests_from_dir(dir: &Path) -> HashSet<Test> {
55 let mut res = HashSet::new();
56 for entry in WalkDir::new(dir) {
57 let entry = entry.unwrap();
58 if !entry.file_type().is_file() {
59 continue;
60 }
61 if entry.path().extension().unwrap_or_default() != "rs" {
62 continue;
63 }
64 let text = file::get_text(entry.path()).unwrap();
65
66 for test in collect_tests(&text) {
67 if let Some(old_test) = res.replace(test) {
68 panic!("Duplicate test: {}", old_test.name)
69 }
70 }
71 }
72 res
73}
74
75fn collect_tests(s: &str) -> Vec<Test> {
76 let mut res = vec![];
77 let prefix = "// ";
78 let comment_blocks = s.lines()
79 .map(str::trim_left)
80 .group_by(|line| line.starts_with(prefix));
81
82 for (is_comment, block) in comment_blocks.into_iter() {
83 if !is_comment {
84 continue;
85 }
86 let mut block = block.map(|line| &line[prefix.len()..]);
87 let first = block.next().unwrap();
88 if !first.starts_with("test ") {
89 continue;
90 }
91 let name = first["test ".len()..].to_string();
92 let text: String = itertools::join(block.chain(::std::iter::once("")), "\n");
93 assert!(!text.trim().is_empty() && text.ends_with("\n"));
94 res.push(Test { name, text })
95 }
96 res
97}
98
99fn existing_tests() -> HashSet<Test> {
100 let mut res = HashSet::new();
101 for file in fs::read_dir(&inline_tests_dir()).unwrap() {
102 let file = file.unwrap();
103 let path = file.path();
104 if path.extension().unwrap_or_default() != "rs" {
105 continue;
106 }
107 let name = path.file_name().unwrap().to_str().unwrap();
108 let name = name["0000_".len()..name.len() - 3].to_string();
109 let text = file::get_text(&path).unwrap();
110 res.insert(Test { name, text });
111 }
112 res
113}
114
115fn inline_tests_dir() -> PathBuf {
116 let res = base_dir().join("tests/data/parser/inline");
117 if !res.is_dir() {
118 fs::create_dir_all(&res).unwrap();
119 }
120 res
121}
122
123fn grammar_dir() -> PathBuf {
124 base_dir().join("src/parser/event_parser/grammar")
125}
126
127fn base_dir() -> PathBuf {
128 let dir = env!("CARGO_MANIFEST_DIR");
129 PathBuf::from(dir).parent().unwrap().to_owned()
130}