1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#![feature(crate_visibility_modifier)]
#![feature(specialization)]
use lark_collections::seq;
use lark_intern::Intern;
use lark_parser::{ParserDatabase, ParserDatabaseExt};
use lark_query_system::ls_ops::{Cancelled, LsDatabase, RangedDiagnostic};
use lark_query_system::LarkDatabase;
use lark_span::FileName;
use lark_string::Text;
use salsa::Database;
use std::fmt::Debug;
mod harness;
pub use harness::run_test_harness;
pub use harness::search_files;
pub use harness::TestPath;
pub use lark_debug_with::DebugWith;
pub use lark_span::IntoFileName;
pub trait ErrorSpec {
fn check_errors(&self, errors: &[RangedDiagnostic]);
}
pub struct NoErrors;
impl ErrorSpec for NoErrors {
fn check_errors(&self, errors: &[RangedDiagnostic]) {
if errors.is_empty() {
return;
}
for error in errors {
eprintln!("{:?}", error);
}
assert_eq!(0, errors.len());
}
}
impl ErrorSpec for &str {
fn check_errors(&self, errors: &[RangedDiagnostic]) {
assert_eq!(
errors.len(),
1,
"expected exactly one error, got {:#?}",
errors
);
for error in errors {
let range = error.range;
let expected = format!("0:{}..0:{}", self.find('~').unwrap(), self.len());
let actual = format!(
"{}:{}..{}:{}",
range.start.line, range.start.character, range.end.line, range.end.character
);
if expected != actual {
eprintln!("expected error on {}", expected);
eprintln!("found error on {}", actual);
eprintln!("error = {:#?}", error);
}
assert_eq!(expected, actual);
}
}
}
pub fn db_with_test(file_name: impl IntoFileName, text: &str) -> LarkDatabase {
let mut db = LarkDatabase::default();
db.add_file(file_name, text);
db
}
pub fn run_test(text: &str, error_spec: impl ErrorSpec) {
let file_name_str = "input.lark";
let db = db_with_test(file_name_str, text);
let parsed = db.parsed_file(file_name_str.into_file_name(&db));
assert!(parsed.value.entities().len() >= 1, "input with no items");
match db.errors_for_project() {
Ok(errors) => {
let flat_errors: Vec<_> = errors
.into_iter()
.flat_map(|(file_name, errors)| {
assert_eq!(file_name, file_name_str);
errors
})
.collect();
error_spec.check_errors(&flat_errors);
}
Err(Cancelled) => {
panic!("cancelled?!");
}
}
}
pub fn lark_parser_db(text: impl AsRef<str>) -> (FileName, LarkDatabase) {
let text: &str = text.as_ref();
let mut db = LarkDatabase::default();
let path1 = FileName {
id: "path1".intern(&db),
};
let text = Text::from(text);
db.query_mut(lark_parser::FileNamesQuery)
.set((), seq![path1]);
db.query_mut(lark_parser::FileTextQuery).set(path1, text);
(path1, db)
}
pub fn assert_equal<Cx, A>(cx: &Cx, expected_value: &A, actual_value: &A)
where
A: ?Sized + Debug + DebugWith + Eq,
{
let expected_text = format!("{:#?}", expected_value.debug_with(cx));
assert_expected_debug(cx, &expected_text, actual_value);
assert_eq!(expected_value, actual_value);
}
pub fn assert_expected_debug<Cx, A>(cx: &Cx, expected_text: &str, actual_value: &A)
where
A: ?Sized + DebugWith,
{
let actual_text = format!("{:#?}", actual_value.debug_with(cx));
if expected_text == actual_text {
return;
}
println!("# expected_text");
println!("{}", expected_text);
println!("# actual_text");
println!("{}", actual_text);
println!("# diff");
for diff in diff::lines(&expected_text, &actual_text) {
match diff {
diff::Result::Left(l) => println!("-{}", l),
diff::Result::Both(l, _) => println!(" {}", l),
diff::Result::Right(r) => println!("+{}", r),
}
}
panic!("debug comparison failed");
}