Skip to content

Commit e784138

Browse files
committed
Restructure test suite's allocation recording so that tests can run in parallel
1 parent fe29bc8 commit e784138

File tree

4 files changed

+203
-143
lines changed

4 files changed

+203
-143
lines changed

cli/src/tests/corpus_test.rs

Lines changed: 147 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,6 @@ use tree_sitter::{allocations, LogType, Node, Parser, Tree};
1212

1313
const EDIT_COUNT: usize = 3;
1414
const TRIAL_COUNT: usize = 10;
15-
const LANGUAGES: &'static [&'static str] = &[
16-
"bash",
17-
"c",
18-
"cpp",
19-
"embedded-template",
20-
"go",
21-
"html",
22-
"javascript",
23-
"json",
24-
"php",
25-
"python",
26-
"ruby",
27-
"rust",
28-
];
2915

3016
lazy_static! {
3117
static ref LOG_ENABLED: bool = env::var("TREE_SITTER_TEST_ENABLE_LOG").is_ok();
@@ -36,7 +22,11 @@ lazy_static! {
3622
.map(|s| usize::from_str_radix(&s, 10).unwrap())
3723
.ok();
3824
pub static ref SEED: usize = env::var("TREE_SITTER_TEST_SEED")
39-
.map(|s| usize::from_str_radix(&s, 10).unwrap())
25+
.map(|s| {
26+
let seed = usize::from_str_radix(&s, 10).unwrap();
27+
eprintln!("\n\nRandom seed: {}\n", *SEED);
28+
seed
29+
})
4030
.unwrap_or(
4131
time::SystemTime::now()
4232
.duration_since(time::UNIX_EPOCH)
@@ -46,40 +36,95 @@ lazy_static! {
4636
}
4737

4838
#[test]
49-
fn test_real_language_corpus_files() {
50-
eprintln!("\n\nRandom seed: {}\n", *SEED);
39+
fn test_bash_corpus() {
40+
test_language_corpus("bash");
41+
}
42+
43+
#[test]
44+
fn test_c_corpus() {
45+
test_language_corpus("c");
46+
}
47+
48+
#[test]
49+
fn test_cpp_corpus() {
50+
test_language_corpus("cpp");
51+
}
52+
53+
#[test]
54+
fn test_embedded_template_corpus() {
55+
test_language_corpus("embedded-template");
56+
}
57+
58+
#[test]
59+
fn test_go_corpus() {
60+
test_language_corpus("go");
61+
}
62+
63+
#[test]
64+
fn test_html_corpus() {
65+
test_language_corpus("html");
66+
}
67+
68+
#[test]
69+
fn test_javascript_corpus() {
70+
test_language_corpus("javascript");
71+
}
72+
73+
#[test]
74+
fn test_json_corpus() {
75+
test_language_corpus("json");
76+
}
77+
78+
#[test]
79+
fn test_php_corpus() {
80+
test_language_corpus("php");
81+
}
82+
83+
#[test]
84+
fn test_python_corpus() {
85+
test_language_corpus("python");
86+
}
87+
88+
#[test]
89+
fn test_ruby_corpus() {
90+
test_language_corpus("ruby");
91+
}
92+
93+
#[test]
94+
fn test_rust_corpus() {
95+
test_language_corpus("rust");
96+
}
97+
98+
fn test_language_corpus(language_name: &str) {
99+
if let Some(language_filter) = LANGUAGE_FILTER.as_ref() {
100+
if language_filter != language_name {
101+
return;
102+
}
103+
}
104+
51105
let grammars_dir = fixtures_dir().join("grammars");
52106
let error_corpus_dir = fixtures_dir().join("error_corpus");
53107

54108
let mut failure_count = 0;
55-
for language_name in LANGUAGES.iter().cloned() {
56-
if let Some(filter) = LANGUAGE_FILTER.as_ref() {
57-
if language_name != filter.as_str() {
58-
continue;
59-
}
60-
}
61-
62-
let language = get_language(language_name);
63-
let mut corpus_dir = grammars_dir.join(language_name).join("corpus");
64-
if !corpus_dir.is_dir() {
65-
corpus_dir = grammars_dir.join(language_name).join("test").join("corpus");
66-
}
67109

68-
let error_corpus_file = error_corpus_dir.join(&format!("{}_errors.txt", language_name));
69-
let main_tests = parse_tests(&corpus_dir).unwrap();
70-
let error_tests = parse_tests(&error_corpus_file).unwrap_or(TestEntry::default());
71-
let mut tests = flatten_tests(main_tests);
72-
tests.extend(flatten_tests(error_tests));
110+
let language = get_language(language_name);
111+
let mut corpus_dir = grammars_dir.join(language_name).join("corpus");
112+
if !corpus_dir.is_dir() {
113+
corpus_dir = grammars_dir.join(language_name).join("test").join("corpus");
114+
}
73115

74-
if !tests.is_empty() {
75-
eprintln!("language: {:?}", language_name);
76-
}
116+
let error_corpus_file = error_corpus_dir.join(&format!("{}_errors.txt", language_name));
117+
let main_tests = parse_tests(&corpus_dir).unwrap();
118+
let error_tests = parse_tests(&error_corpus_file).unwrap_or(TestEntry::default());
119+
let mut tests = flatten_tests(main_tests);
120+
tests.extend(flatten_tests(error_tests));
77121

78-
for (example_name, input, expected_output, has_fields) in tests {
79-
eprintln!(" example: {:?}", example_name);
122+
for (example_name, input, expected_output, has_fields) in tests {
123+
println!(" {} example - {}", language_name, example_name);
80124

81-
if TRIAL_FILTER.map_or(true, |t| t == 0) {
82-
allocations::start_recording();
125+
let trial = 0;
126+
if TRIAL_FILTER.map_or(true, |t| t == trial) {
127+
let passed = allocations::record(|| {
83128
let mut log_session = None;
84129
let mut parser = get_parser(&mut log_session, "log.html");
85130
parser.set_language(language).unwrap();
@@ -88,28 +133,36 @@ fn test_real_language_corpus_files() {
88133
if !has_fields {
89134
actual_output = strip_sexp_fields(actual_output);
90135
}
91-
drop(tree);
92-
drop(parser);
93-
if actual_output != expected_output {
136+
if actual_output == expected_output {
137+
true
138+
} else {
139+
println!(
140+
"Incorrect initial parse for {} - {}",
141+
language_name, example_name,
142+
);
94143
print_diff_key();
95144
print_diff(&actual_output, &expected_output);
96145
println!("");
97-
failure_count += 1;
98-
continue;
146+
false
99147
}
100-
allocations::stop_recording();
148+
});
149+
150+
if !passed {
151+
failure_count += 1;
152+
continue;
101153
}
154+
}
102155

103-
let mut parser = Parser::new();
104-
parser.set_language(language).unwrap();
105-
let tree = parser.parse(&input, None).unwrap();
106-
drop(parser);
156+
let mut parser = Parser::new();
157+
parser.set_language(language).unwrap();
158+
let tree = parser.parse(&input, None).unwrap();
159+
drop(parser);
107160

108-
for trial in 1..=TRIAL_COUNT {
109-
if TRIAL_FILTER.map_or(true, |filter| filter == trial) {
110-
let mut rand = Rand::new(*SEED + trial);
161+
for trial in 1..=TRIAL_COUNT {
162+
if TRIAL_FILTER.map_or(true, |filter| filter == trial) {
163+
let mut rand = Rand::new(*SEED + trial);
111164

112-
allocations::start_recording();
165+
let passed = allocations::record(|| {
113166
let mut log_session = None;
114167
let mut parser = get_parser(&mut log_session, "log.html");
115168
parser.set_language(language).unwrap();
@@ -140,8 +193,7 @@ fn test_real_language_corpus_files() {
140193
"\nUnexpected scope change in trial {}\n{}\n\n",
141194
trial, message
142195
);
143-
failure_count += 1;
144-
break;
196+
return false;
145197
}
146198

147199
// Undo all of the edits and re-parse again.
@@ -168,8 +220,7 @@ fn test_real_language_corpus_files() {
168220
print_diff_key();
169221
print_diff(&actual_output, &expected_output);
170222
println!("");
171-
failure_count += 1;
172-
break;
223+
return false;
173224
}
174225

175226
// Check that the edited tree is consistent.
@@ -179,21 +230,22 @@ fn test_real_language_corpus_files() {
179230
"Unexpected scope change in trial {}\n{}\n\n",
180231
trial, message
181232
);
182-
failure_count += 1;
183-
break;
233+
return false;
184234
}
185235

186-
drop(tree);
187-
drop(tree2);
188-
drop(tree3);
189-
drop(parser);
190-
allocations::stop_recording();
236+
true
237+
});
238+
239+
if !passed {
240+
failure_count += 1;
241+
break;
191242
}
192243
}
193244
}
194245
}
246+
195247
if failure_count > 0 {
196-
panic!("{} corpus tests failed", failure_count);
248+
panic!("{} {} corpus tests failed", failure_count, language_name);
197249
}
198250
}
199251

@@ -271,26 +323,29 @@ fn test_feature_corpus_files() {
271323
for (name, input, expected_output, has_fields) in tests {
272324
eprintln!(" example: {:?}", name);
273325

274-
allocations::start_recording();
275-
let mut log_session = None;
276-
let mut parser = get_parser(&mut log_session, "log.html");
277-
parser.set_language(language).unwrap();
278-
let tree = parser.parse(&input, None).unwrap();
279-
let mut actual_output = tree.root_node().to_sexp();
280-
if !has_fields {
281-
actual_output = strip_sexp_fields(actual_output);
282-
}
326+
let passed = allocations::record(|| {
327+
let mut log_session = None;
328+
let mut parser = get_parser(&mut log_session, "log.html");
329+
parser.set_language(language).unwrap();
330+
let tree = parser.parse(&input, None).unwrap();
331+
let mut actual_output = tree.root_node().to_sexp();
332+
if !has_fields {
333+
actual_output = strip_sexp_fields(actual_output);
334+
}
335+
if actual_output == expected_output {
336+
true
337+
} else {
338+
print_diff_key();
339+
print_diff(&actual_output, &expected_output);
340+
println!("");
341+
false
342+
}
343+
});
283344

284-
drop(tree);
285-
drop(parser);
286-
if actual_output != expected_output {
287-
print_diff_key();
288-
print_diff(&actual_output, &expected_output);
289-
println!("");
345+
if !passed {
290346
failure_count += 1;
291347
continue;
292348
}
293-
allocations::stop_recording();
294349
}
295350
}
296351
}
@@ -381,7 +436,12 @@ fn get_parser(session: &mut Option<util::LogSession>, log_filename: &str) -> Par
381436
}
382437

383438
fn flatten_tests(test: TestEntry) -> Vec<(String, Vec<u8>, String, bool)> {
384-
fn helper(test: TestEntry, prefix: &str, result: &mut Vec<(String, Vec<u8>, String, bool)>) {
439+
fn helper(
440+
test: TestEntry,
441+
is_root: bool,
442+
prefix: &str,
443+
result: &mut Vec<(String, Vec<u8>, String, bool)>,
444+
) {
385445
match test {
386446
TestEntry::Example {
387447
mut name,
@@ -403,17 +463,17 @@ fn flatten_tests(test: TestEntry) -> Vec<(String, Vec<u8>, String, bool)> {
403463
TestEntry::Group {
404464
mut name, children, ..
405465
} => {
406-
if !prefix.is_empty() {
466+
if !is_root && !prefix.is_empty() {
407467
name.insert_str(0, " - ");
408468
name.insert_str(0, prefix);
409469
}
410470
for child in children {
411-
helper(child, &name, result);
471+
helper(child, false, &name, result);
412472
}
413473
}
414474
}
415475
}
416476
let mut result = Vec::new();
417-
helper(test, "", &mut result);
477+
helper(test, true, "", &mut result);
418478
result
419479
}

cli/src/tests/parser_test.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -596,8 +596,8 @@ fn test_parsing_with_a_timeout() {
596596
let mut parser = Parser::new();
597597
parser.set_language(get_language("json")).unwrap();
598598

599-
// Parse an infinitely-long array, but pause after 100 microseconds of processing.
600-
parser.set_timeout_micros(100);
599+
// Parse an infinitely-long array, but pause after 1ms of processing.
600+
parser.set_timeout_micros(1000);
601601
let start_time = time::Instant::now();
602602
let tree = parser.parse_with(
603603
&mut |offset, _| {
@@ -610,10 +610,10 @@ fn test_parsing_with_a_timeout() {
610610
None,
611611
);
612612
assert!(tree.is_none());
613-
assert!(start_time.elapsed().as_micros() < 500);
613+
assert!(start_time.elapsed().as_micros() < 2000);
614614

615-
// Continue parsing, but pause after 300 microseconds of processing.
616-
parser.set_timeout_micros(1000);
615+
// Continue parsing, but pause after 1 ms of processing.
616+
parser.set_timeout_micros(5000);
617617
let start_time = time::Instant::now();
618618
let tree = parser.parse_with(
619619
&mut |offset, _| {
@@ -626,8 +626,8 @@ fn test_parsing_with_a_timeout() {
626626
None,
627627
);
628628
assert!(tree.is_none());
629-
assert!(start_time.elapsed().as_micros() > 500);
630-
assert!(start_time.elapsed().as_micros() < 2000);
629+
assert!(start_time.elapsed().as_micros() > 100);
630+
assert!(start_time.elapsed().as_micros() < 10000);
631631

632632
// Finish parsing
633633
parser.set_timeout_micros(0);

0 commit comments

Comments
 (0)