lrpar_tests/
lib.rs

1#[cfg(test)]
2use cfgrammar::Span;
3
4mod cgen_helper;
5#[allow(unused)]
6use cgen_helper::run_test_path;
7
8mod calc_wasm;
9
10#[cfg(test)]
11use cttests_macro::generate_codegen_fail_tests;
12use lrlex::lrlex_mod;
13use lrpar::lrpar_mod;
14#[cfg(test)]
15use lrpar::{Lexeme, Lexer, NonStreamingLexer};
16
17lrlex_mod!("calc_multitypes.l");
18lrpar_mod!("calc_multitypes.y");
19
20lrlex_mod!("calc_actiontype.l");
21lrpar_mod!("calc_actiontype.y");
22
23lrlex_mod!("calc_noactions.l");
24lrpar_mod!("calc_noactions.y");
25
26lrlex_mod!("calc_nodefault_yacckind.l");
27lrpar_mod!("calc_nodefault_yacckind.y");
28
29lrlex_mod!("calc_unsafeaction.l");
30lrpar_mod!("calc_unsafeaction.y");
31
32lrlex_mod!("expect.l");
33lrpar_mod!("expect.y");
34
35lrlex_mod!("lexer_lifetime.l");
36lrpar_mod!("lexer_lifetime.y");
37
38lrlex_mod!("lex_flags.l");
39lrpar_mod!("lex_flags.y");
40
41lrlex_mod!("multitypes.l");
42lrpar_mod!("multitypes.y");
43
44lrlex_mod!("parseparam.l");
45lrpar_mod!("parseparam.y");
46
47lrlex_mod!("parseparam_copy.l");
48lrpar_mod!("parseparam_copy.y");
49
50lrlex_mod!("passthrough.l");
51lrpar_mod!("passthrough.y");
52
53lrlex_mod!("regex_opt.l");
54lrlex_mod!("regex_opt.y");
55
56lrlex_mod!("span.l");
57lrpar_mod!("span.y");
58
59lrlex_mod!("storaget.l");
60lrpar_mod!("storaget.y");
61
62lrlex_mod!("grmtools_section.l");
63lrpar_mod!("grmtools_section.y");
64
65#[test]
66fn multitypes() {
67    let lexerdef = multitypes_l::lexerdef();
68    let lexer = lexerdef.lexer("aa");
69    let (r, errs) = multitypes_y::parse(&lexer);
70    assert_eq!(r.unwrap().len(), 2);
71    assert_eq!(errs.len(), 0);
72}
73
74#[test]
75fn test_no_actions() {
76    let lexerdef = calc_noactions_l::lexerdef();
77    let lexer = lexerdef.lexer("2+3");
78    if !calc_noactions_y::parse(&lexer).is_empty() {
79        panic!();
80    }
81    let lexer = lexerdef.lexer("2++3");
82    if calc_noactions_y::parse(&lexer).len() != 1 {
83        panic!();
84    }
85}
86
87#[test]
88fn test_basic_actions() {
89    let lexerdef = calc_actiontype_l::lexerdef();
90    let lexer = lexerdef.lexer("2+3");
91    match calc_actiontype_y::parse(&lexer) {
92        (Some(Ok(5)), ref errs) if errs.is_empty() => (),
93        _ => unreachable!(),
94    }
95}
96
97#[test]
98fn test_nodefault_yacckind() {
99    let lexerdef = calc_nodefault_yacckind_l::lexerdef();
100    let lexer = lexerdef.lexer("2+3");
101    match calc_nodefault_yacckind_y::parse(&lexer) {
102        (Some(Ok(5)), ref errs) if errs.is_empty() => (),
103        _ => unreachable!(),
104    }
105}
106#[test]
107fn test_unsafe_actions() {
108    let lexerdef = calc_unsafeaction_l::lexerdef();
109    let lexer = lexerdef.lexer("2+3");
110    match calc_unsafeaction_y::parse(&lexer) {
111        (Some(Ok(5)), ref errs) if errs.is_empty() => (),
112        _ => unreachable!(),
113    }
114}
115
116#[test]
117fn test_error_recovery_and_actions() {
118    use lrpar::LexParseError;
119
120    let lexerdef = calc_actiontype_l::lexerdef();
121
122    let lexer = lexerdef.lexer("2++3");
123    let (r, errs) = calc_actiontype_y::parse(&lexer);
124    match r {
125        Some(Ok(5)) => (),
126        _ => unreachable!(),
127    }
128    match errs[0] {
129        LexParseError::ParseError(..) => (),
130        _ => unreachable!(),
131    }
132
133    let lexer = lexerdef.lexer("2+3)");
134    let (r, errs) = calc_actiontype_y::parse(&lexer);
135    assert_eq!(r, Some(Ok(5)));
136    assert_eq!(errs.len(), 1);
137    match errs[0] {
138        LexParseError::ParseError(..) => (),
139        _ => unreachable!(),
140    }
141
142    let lexer = lexerdef.lexer("2+3+18446744073709551616");
143    let (r, errs) = calc_actiontype_y::parse(&lexer);
144    assert_eq!(r, Some(Err(())));
145    assert!(errs.is_empty());
146}
147
148#[test]
149fn test_calc_multitypes() {
150    let lexerdef = calc_multitypes_l::lexerdef();
151    let lexer = lexerdef.lexer("1+2*3");
152    let (res, _errs) = calc_multitypes_y::parse(&lexer);
153    assert_eq!(res, Some(Ok(7)));
154
155    let lexer = lexerdef.lexer("1++2");
156    let (res, _errs) = calc_multitypes_y::parse(&lexer);
157    assert_eq!(res, Some(Ok(3)));
158}
159
160#[test]
161fn test_input_lifetime() {
162    // This test only exists to make sure that this code compiles: there's no need for us to
163    // actually run anything.
164    let lexerdef = lexer_lifetime_l::lexerdef();
165    let input = "a";
166    let _ = {
167        let lexer = lexerdef.lexer(input);
168        let lx = lexer.iter().next().unwrap().unwrap();
169        lexer.span_str(lx.span())
170    };
171}
172
173#[test]
174fn test_lexer_lifetime() {
175    // This test only exists to make sure that this code compiles: there's no need for us to
176    // actually run anything.
177
178    #[allow(clippy::needless_lifetimes)]
179    pub(crate) fn parse_data<'a>(input: &'a str) -> Option<&'a str> {
180        let lexer_def = crate::lexer_lifetime_l::lexerdef();
181        let l = lexer_def.lexer(input);
182        match crate::lexer_lifetime_y::parse(&l) {
183            (Option::Some(x), _) => Some(x),
184            _ => None,
185        }
186    }
187    parse_data("abc");
188}
189
190#[test]
191fn test_span() {
192    let lexerdef = span_l::lexerdef();
193    let lexer = lexerdef.lexer("2+3");
194    match span_y::parse(&lexer) {
195        (Some(ref spans), _)
196            if spans
197                == &vec![
198                    Span::new(0, 1),
199                    Span::new(0, 1),
200                    Span::new(0, 1),
201                    Span::new(2, 3),
202                    Span::new(2, 3),
203                    Span::new(0, 3),
204                ] => {}
205        _ => unreachable!(),
206    }
207
208    let lexer = lexerdef.lexer("2 + 3");
209    match span_y::parse(&lexer) {
210        (Some(ref spans), _)
211            if spans
212                == &vec![
213                    Span::new(0, 1),
214                    Span::new(0, 1),
215                    Span::new(0, 1),
216                    Span::new(4, 5),
217                    Span::new(4, 5),
218                    Span::new(0, 5),
219                ] => {}
220        _ => unreachable!(),
221    }
222
223    let lexer = lexerdef.lexer("2+3*4");
224    match span_y::parse(&lexer) {
225        (Some(ref spans), _)
226            if spans
227                == &vec![
228                    Span::new(0, 1),
229                    Span::new(0, 1),
230                    Span::new(0, 1),
231                    Span::new(2, 3),
232                    Span::new(2, 3),
233                    Span::new(4, 5),
234                    Span::new(2, 5),
235                    Span::new(0, 5),
236                ] => {}
237        _ => unreachable!(),
238    }
239
240    let lexer = lexerdef.lexer("2++3");
241    match span_y::parse(&lexer) {
242        (Some(ref spans), _)
243            if spans
244                == &vec![
245                    Span::new(0, 1),
246                    Span::new(0, 1),
247                    Span::new(0, 1),
248                    Span::new(3, 4),
249                    Span::new(3, 4),
250                    Span::new(0, 4),
251                ] => {}
252        _ => unreachable!(),
253    }
254
255    let lexer = lexerdef.lexer("(2)))");
256    match dbg!(span_y::parse(&lexer)) {
257        (Some(ref spans), _)
258            if spans
259                == &vec![
260                    Span::new(1, 2),
261                    Span::new(1, 2),
262                    Span::new(1, 2),
263                    Span::new(0, 3),
264                    Span::new(0, 3),
265                    Span::new(0, 3),
266                ] => {}
267        _ => unreachable!(),
268    }
269}
270
271#[test]
272fn test_parseparam() {
273    let lexerdef = parseparam_l::lexerdef();
274    let lexer = lexerdef.lexer("101");
275    match parseparam_y::parse(&lexer, &3) {
276        (Some(104), _) => (),
277        _ => unreachable!(),
278    }
279}
280
281#[test]
282fn test_parseparam_copy() {
283    let lexerdef = parseparam_copy_l::lexerdef();
284    let lexer = lexerdef.lexer("101");
285    match parseparam_copy_y::parse(&lexer, 3) {
286        (Some(104), _) => (),
287        _ => unreachable!(),
288    }
289}
290
291#[test]
292fn test_passthrough() {
293    let lexerdef = passthrough_l::lexerdef();
294    let lexer = lexerdef.lexer("101");
295    match passthrough_y::parse(&lexer) {
296        (Some(Ok(ref s)), _) if s == "$101" => (),
297        _ => unreachable!(),
298    }
299}
300
301#[test]
302fn test_storaget() {
303    let lexerdef = storaget_l::lexerdef();
304    let lexer = lexerdef.lexer("glasses, keys, umbrella");
305    let expect = ["glasses", "keys", "umbrella"]
306        .iter()
307        .map(|x| x.to_string())
308        .collect::<Vec<_>>();
309    let (val, e) = storaget_y::parse(&lexer);
310    assert_eq!(val, Some(expect));
311    assert!(e.is_empty());
312}
313
314#[test]
315fn test_expect() {
316    // This test merely needs to compile in order to be successful.
317}
318
319// This test isn't run on wasm32-wasi because it accesses
320// various files from across the project workspace.
321//
322// Wasi's filesystem access is sandboxed by default.
323#[test]
324fn test_grmtools_section_files() {
325    use glob::glob;
326    use std::env;
327    use std::fs::File;
328    use std::io::BufReader;
329    use std::io::{BufRead as _, Read as _};
330
331    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
332    let examples_glob = format!("{manifest_dir}/../examples/**");
333    let examples_l_glob = format!("{examples_glob}/*.l");
334    let examples_y_glob = format!("{examples_glob}/*.y");
335    let out_dir = env::var("OUT_DIR").unwrap();
336    let cttests_l_glob = format!("{out_dir}/*.l");
337    let cttests_y_glob = format!("{out_dir}/*.y");
338    let files = glob(&examples_l_glob)
339        .unwrap()
340        .chain(glob(&examples_y_glob).unwrap())
341        .chain(glob(&cttests_l_glob).unwrap())
342        .chain(glob(&cttests_y_glob).unwrap())
343        .collect::<Vec<_>>();
344    assert!(!files.is_empty());
345    for file_path in files {
346        let file_path = file_path.unwrap();
347        let mut s = String::new();
348        let mut f = File::open(&file_path).unwrap();
349        let _ = f.read_to_string(&mut s).unwrap();
350        if s.starts_with("%grmtools") {
351            let mut buf = Vec::new();
352            let mut reader = BufReader::new(s.as_bytes());
353            let _ = reader.read_until(b'}', &mut buf);
354            let lexerdef = grmtools_section_l::lexerdef();
355            let s = String::from_utf8(buf).unwrap();
356            let l = lexerdef.lexer(&s);
357            let (yacc_parsed, errs) = grmtools_section_y::parse(&l);
358            let parser = cfgrammar::header::GrmtoolsSectionParser::new(&s, true);
359            let (header_parsed, _) = parser.parse().unwrap();
360            assert_eq!(yacc_parsed.unwrap().unwrap(), header_parsed);
361            assert!(errs.is_empty());
362        }
363    }
364}
365
366#[test]
367fn test_grmtools_section_strings() {
368    let srcs = [
369        "%grmtools{}",
370        "%grmtools{x}",
371        "%grmtools{x,}",
372        "%grmtools{!x}",
373        "%grmtools{!x,}",
374        "%grmtools{x: y}",
375        "%grmtools{x: y,}",
376        "%grmtools{x, y}",
377        "%grmtools{x, y,}",
378        "%grmtools{x, !y}",
379        "%grmtools{x, !y,}",
380        "%grmtools{x: y(z)}",
381        "%grmtools{x: y(z),}",
382        "%grmtools{a, x: y(z),}",
383        "%grmtools{a, x: y(z)}",
384        "%grmtools{a, !b, x: y(z), e: f}",
385        "%grmtools{a, !b, x: y(z), e: f,}",
386        "%grmtools{a, !b, x: w::y(z), e: f}",
387        "%grmtools{a, !b, x: w::y(z), e: f,}",
388        "%grmtools{a, !b, x: w::y(z), e: g::f}",
389        "%grmtools{a, !b, x: w::y(z), e: g::f,}",
390    ];
391
392    let lexerdef = grmtools_section_l::lexerdef();
393    for src in srcs {
394        let l = lexerdef.lexer(src);
395        let (yacc_parsed, errs) = grmtools_section_y::parse(&l);
396        let yacc_parsed = yacc_parsed.unwrap().unwrap();
397        let parser = cfgrammar::header::GrmtoolsSectionParser::new(src, true);
398        let (header_parsed, _) = parser.parse().unwrap();
399        assert_eq!(yacc_parsed, header_parsed);
400        assert!(errs.is_empty());
401    }
402}
403
404// regex options set through the builder methods.
405#[test]
406fn test_regex_opt() {
407    let lexerdef = regex_opt_l::lexerdef();
408    let lexer = lexerdef.lexer("a");
409    match regex_opt_y::parse(&lexer) {
410        ref errs if errs.is_empty() => (),
411        e => panic!("{:?}", e),
412    }
413}
414
415// Lex flags set through the grmtools section.
416#[test]
417fn test_lex_flags() {
418    let lexerdef = lex_flags_l::lexerdef();
419    let lexer = lexerdef.lexer("a");
420    match lex_flags_y::parse(&lexer) {
421        ref errs if errs.is_empty() => (),
422        e => panic!("{:?}", e),
423    }
424}
425
426// Codegen failure tests
427#[cfg(test)]
428generate_codegen_fail_tests!("src/ctfails/*.test");