slicec/
test_helpers.rs

1// Copyright (c) ZeroC, Inc.
2
3//! This module contains helper functions that are useful for testing both slicec and the compilers that use it.
4//! For the test helpers that are specific to slicec (and hence not exported, see: 'tests/test_helpers.rs').
5
6use crate::compilation_state::CompilationState;
7use crate::diagnostics::{Diagnostic, DiagnosticLevel};
8use crate::slice_options::SliceOptions;
9
10/// This function is used to get the Diagnostics from a `CompilationState`.
11#[must_use]
12pub fn diagnostics_from_compilation_state(state: CompilationState, options: &SliceOptions) -> Vec<Diagnostic> {
13    let mut diagnostics = state.into_diagnostics(options);
14    diagnostics.retain(|diagnostic| diagnostic.level() != DiagnosticLevel::Allowed);
15    diagnostics
16}
17
18/// Compares diagnostics emitted by the compiler to an array of expected diagnostics.
19/// It ensures that the expected number of diagnostics were emitted (ie: that both lists are the same length).
20///
21/// If the correct number were emitted, it checks each diagnostic against the expected array in order.
22/// For each diagnostic we ensure:
23/// - It has the correct diagnostic code.
24/// - It has the correct message.
25/// - If a span was expected, that it has the correct span.
26/// - If notes are expected, we check that all the notes have correct messages and spans.
27///
28/// If the expected diagnostics don't include spans or notes, this function doesn't check them.
29/// This is useful for the majority of tests that aren't explicitly testing spans or notes.
30pub fn check_diagnostics<const L: usize>(diagnostics: Vec<Diagnostic>, expected: [impl Into<Diagnostic>; L]) {
31    // Check that the correct number of diagnostics were emitted.
32    if expected.len() != diagnostics.len() {
33        eprintln!(
34            "Expected {} diagnostics, but got {}.",
35            expected.len(),
36            diagnostics.len()
37        );
38        eprintln!("The emitted diagnostics were:");
39        for diagnostic in diagnostics {
40            eprintln!("\t{diagnostic:?}");
41        }
42        eprintln!();
43        panic!("test failure");
44    }
45
46    // Check that the emitted diagnostics match what was expected.
47    for (expect, diagnostic) in expected.into_iter().zip(diagnostics) {
48        let expect: Diagnostic = expect.into();
49        let mut failed = false;
50
51        // Check that the diagnostic codes match.
52        if expect.code() != diagnostic.code() {
53            eprintln!("diagnostic codes didn't match:");
54            eprintln!("\texpected '{:?}', but got '{:?}'", expect.code(), diagnostic.code());
55            failed = true;
56        }
57
58        // Check that the messages match.
59        if expect.message() != diagnostic.message() {
60            eprintln!("diagnostic messages didn't match:");
61            eprintln!("\texpected: \"{}\"", expect.message());
62            eprintln!("\t but got: \"{}\"", diagnostic.message());
63            failed = true;
64        }
65
66        // If a span was provided, check that it matches.
67        if expect.span().is_some() && expect.span() != diagnostic.span() {
68            eprintln!("diagnostic spans didn't match:");
69            eprintln!("\texpected: \"{:?}\"", expect.span());
70            eprintln!("\t but got: \"{:?}\"", diagnostic.span());
71            failed = true;
72        }
73
74        // If notes were provided, check that they match.
75        if !expect.notes().is_empty() {
76            let expected_notes = expect.notes();
77            let emitted_notes = diagnostic.notes();
78            if expected_notes.len() != emitted_notes.len() {
79                eprintln!(
80                    "Expected {} notes, but got {}.",
81                    expected_notes.len(),
82                    emitted_notes.len()
83                );
84                eprintln!("The emitted notes were:");
85                for note in emitted_notes {
86                    eprintln!("\t{note:?}");
87                }
88                failed = true;
89            } else {
90                for (expected_note, emitted_note) in expected_notes.iter().zip(emitted_notes) {
91                    // Check that the messages match.
92                    if expected_note.message != emitted_note.message {
93                        eprintln!("note messages didn't match:");
94                        eprintln!("\texpected: \"{}\"", expected_note.message);
95                        eprintln!("\t but got: \"{}\"", emitted_note.message);
96                        failed = true;
97                    }
98
99                    // If a span was provided, check that it matches.
100                    if expected_note.span.is_some() && expected_note.span != emitted_note.span {
101                        eprintln!("note spans didn't match:");
102                        eprintln!("\texpected: \"{:?}\"", expected_note.span);
103                        eprintln!("\t but got: \"{:?}\"", emitted_note.span);
104                        failed = true;
105                    }
106                }
107            }
108        }
109
110        // If the checks failed, panic to signal a test failure.
111        if failed {
112            eprintln!();
113            panic!("test failure");
114        }
115    }
116}