aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src/fuzz.rs
diff options
context:
space:
mode:
authorDmitry <[email protected]>2020-08-14 19:32:05 +0100
committerDmitry <[email protected]>2020-08-14 19:32:05 +0100
commit178c3e135a2a249692f7784712492e7884ae0c00 (patch)
treeac6b769dbf7162150caa0c1624786a4dd79ff3be /crates/syntax/src/fuzz.rs
parent06ff8e6c760ff05f10e868b5d1f9d79e42fbb49c (diff)
parentc2594daf2974dbd4ce3d9b7ec72481764abaceb5 (diff)
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'crates/syntax/src/fuzz.rs')
-rw-r--r--crates/syntax/src/fuzz.rs73
1 files changed, 73 insertions, 0 deletions
diff --git a/crates/syntax/src/fuzz.rs b/crates/syntax/src/fuzz.rs
new file mode 100644
index 000000000..fbb97aa27
--- /dev/null
+++ b/crates/syntax/src/fuzz.rs
@@ -0,0 +1,73 @@
1//! FIXME: write short doc here
2
3use std::{
4 convert::TryInto,
5 str::{self, FromStr},
6};
7
8use text_edit::Indel;
9
10use crate::{validation, AstNode, SourceFile, TextRange};
11
12fn check_file_invariants(file: &SourceFile) {
13 let root = file.syntax();
14 validation::validate_block_structure(root);
15}
16
17pub fn check_parser(text: &str) {
18 let file = SourceFile::parse(text);
19 check_file_invariants(&file.tree());
20}
21
22#[derive(Debug, Clone)]
23pub struct CheckReparse {
24 text: String,
25 edit: Indel,
26 edited_text: String,
27}
28
29impl CheckReparse {
30 pub fn from_data(data: &[u8]) -> Option<Self> {
31 const PREFIX: &str = "fn main(){\n\t";
32 const SUFFIX: &str = "\n}";
33
34 let data = str::from_utf8(data).ok()?;
35 let mut lines = data.lines();
36 let delete_start = usize::from_str(lines.next()?).ok()? + PREFIX.len();
37 let delete_len = usize::from_str(lines.next()?).ok()?;
38 let insert = lines.next()?.to_string();
39 let text = lines.collect::<Vec<_>>().join("\n");
40 let text = format!("{}{}{}", PREFIX, text, SUFFIX);
41 text.get(delete_start..delete_start.checked_add(delete_len)?)?; // make sure delete is a valid range
42 let delete =
43 TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap());
44 let edited_text =
45 format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]);
46 let edit = Indel { delete, insert };
47 Some(CheckReparse { text, edit, edited_text })
48 }
49
50 pub fn run(&self) {
51 let parse = SourceFile::parse(&self.text);
52 let new_parse = parse.reparse(&self.edit);
53 check_file_invariants(&new_parse.tree());
54 assert_eq!(&new_parse.tree().syntax().text().to_string(), &self.edited_text);
55 let full_reparse = SourceFile::parse(&self.edited_text);
56 for (a, b) in
57 new_parse.tree().syntax().descendants().zip(full_reparse.tree().syntax().descendants())
58 {
59 if (a.kind(), a.text_range()) != (b.kind(), b.text_range()) {
60 eprint!("original:\n{:#?}", parse.tree().syntax());
61 eprint!("reparsed:\n{:#?}", new_parse.tree().syntax());
62 eprint!("full reparse:\n{:#?}", full_reparse.tree().syntax());
63 assert_eq!(
64 format!("{:?}", a),
65 format!("{:?}", b),
66 "different syntax tree produced by the full reparse"
67 );
68 }
69 }
70 // FIXME
71 // assert_eq!(new_file.errors(), full_reparse.errors());
72 }
73}