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
/// g-code emitter with a few basic commands and argument-checking
pub mod emit;
/// g-code parser written with [peg]
pub mod parse;

#[cfg(test)]
mod test {
    use crate::{emit::FormatOptions, parse::into_diagnostic};
    use pretty_assertions::assert_eq;

    #[test]
    #[cfg(feature = "codespan_helpers")]
    fn parsing_gcode_then_emitting_then_parsing_again_returns_functionally_identical_gcode() {
        use codespan_reporting::diagnostic::{Diagnostic, Label};
        use codespan_reporting::term::{
            emit,
            termcolor::{ColorChoice, StandardStream},
        };

        let mut writer = StandardStream::stderr(ColorChoice::Auto);
        let config = codespan_reporting::term::Config::default();

        for str in [
            include_str!("../tests/square.gcode"),
            include_str!("../tests/edge_cases.gcode"),
            include_str!("../tests/vandy_commodores_logo.gcode"),
            include_str!("../tests/ncviewer_sample.gcode"),
        ] {
            let parsed_file = crate::parse::file_parser(str).unwrap();
            let emission_tokens = parsed_file.iter_emit_tokens().collect::<Vec<_>>();

            for format_options in [true, false]
                .iter()
                .copied()
                .map(|a| [[a, true], [a, false]])
                .flatten()
                .map(|[a, b]| [[a, b, true], [a, b, false]])
                .flatten()
                .map(|[a, b, c]| [[a, b, c, true], [a, b, c, false]])
                .flatten()
                .map(
                    |[checksums, line_numbers, delimit_with_percent, newline_before_comment]| {
                        FormatOptions {
                            checksums,
                            line_numbers,
                            delimit_with_percent,
                            newline_before_comment,
                        }
                    },
                )
            {
                let mut emitted_gcode = String::new();
                crate::emit::format_gcode_fmt(
                    emission_tokens.iter(),
                    format_options,
                    &mut emitted_gcode,
                )
                .unwrap();

                let reparsed_file = match super::parse::file_parser(&emitted_gcode) {
                    Ok(reparsed) => reparsed,
                    Err(err) => {
                        emit(
                            &mut writer,
                            &config,
                            &codespan_reporting::files::SimpleFile::new(
                                "test_input.gcode",
                                emitted_gcode,
                            ),
                            &into_diagnostic(&err),
                        )
                        .unwrap();
                        panic!("{}", err);
                    }
                };

                for line in reparsed_file.iter() {
                    let validated_checksum = line.validate_checksum();
                    assert!(
                        validated_checksum.clone().transpose().is_ok(),
                        "got {:?} for {:#?}",
                        validated_checksum,
                        line
                    );
                }

                parsed_file
                    .iter_fields()
                    .filter(|field| field.letters != "N")
                    .zip(
                        reparsed_file
                            .iter_fields()
                            .filter(|field| field.letters != "N"),
                    )
                    .for_each(|(expected, actual)| {
                        if expected.value != actual.value || expected.letters != actual.letters {
                            emit(
                                &mut writer,
                                &config,
                                &codespan_reporting::files::SimpleFile::new(
                                    "test_input.gcode",
                                    str,
                                ),
                                &Diagnostic::error()
                                    .with_message("fields do not match")
                                    .with_labels(vec![Label::primary((), expected.span)
                                        .with_message("this one here officer")]),
                            )
                            .unwrap();
                        }
                        assert_eq!(
                            expected.letters, actual.letters,
                            "{:?} vs {:?}",
                            expected, actual
                        );
                        assert_eq!(
                            expected.value, actual.value,
                            "{:?} vs {:?}",
                            expected, actual
                        );
                    })
            }
        }
    }
}