]> git.lizzy.rs Git - rust.git/blob - crates/ide_diagnostics/src/tests.rs
Merge #11840
[rust.git] / crates / ide_diagnostics / src / tests.rs
1 mod sourcegen;
2
3 use expect_test::Expect;
4 use ide_db::{
5     assists::AssistResolveStrategy,
6     base_db::{fixture::WithFixture, SourceDatabaseExt},
7     RootDatabase,
8 };
9 use stdx::trim_indent;
10 use test_utils::{assert_eq_text, extract_annotations};
11
12 use crate::{DiagnosticsConfig, ExprFillDefaultMode, Severity};
13
14 /// Takes a multi-file input fixture with annotated cursor positions,
15 /// and checks that:
16 ///  * a diagnostic is produced
17 ///  * the first diagnostic fix trigger range touches the input cursor position
18 ///  * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
19 #[track_caller]
20 pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
21     check_nth_fix(0, ra_fixture_before, ra_fixture_after);
22 }
23 /// Takes a multi-file input fixture with annotated cursor positions,
24 /// and checks that:
25 ///  * a diagnostic is produced
26 ///  * every diagnostic fixes trigger range touches the input cursor position
27 ///  * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied
28 pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) {
29     for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() {
30         check_nth_fix(i, ra_fixture_before, ra_fixture_after)
31     }
32 }
33
34 #[track_caller]
35 fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
36     let after = trim_indent(ra_fixture_after);
37
38     let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
39     let mut conf = DiagnosticsConfig::default();
40     conf.expr_fill_default = ExprFillDefaultMode::Default;
41     let diagnostic =
42         super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id)
43             .pop()
44             .expect("no diagnostics");
45     let fix = &diagnostic.fixes.expect("diagnostic misses fixes")[nth];
46     let actual = {
47         let source_change = fix.source_change.as_ref().unwrap();
48         let file_id = *source_change.source_file_edits.keys().next().unwrap();
49         let mut actual = db.file_text(file_id).to_string();
50
51         for edit in source_change.source_file_edits.values() {
52             edit.apply(&mut actual);
53         }
54         actual
55     };
56
57     assert_eq_text!(&after, &actual);
58     assert!(
59         fix.target.contains_inclusive(file_position.offset),
60         "diagnostic fix range {:?} does not touch cursor position {:?}",
61         fix.target,
62         file_position.offset
63     );
64 }
65
66 /// Checks that there's a diagnostic *without* fix at `$0`.
67 pub(crate) fn check_no_fix(ra_fixture: &str) {
68     let (db, file_position) = RootDatabase::with_position(ra_fixture);
69     let diagnostic = super::diagnostics(
70         &db,
71         &DiagnosticsConfig::default(),
72         &AssistResolveStrategy::All,
73         file_position.file_id,
74     )
75     .pop()
76     .unwrap();
77     assert!(diagnostic.fixes.is_none(), "got a fix when none was expected: {:?}", diagnostic);
78 }
79
80 pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) {
81     let (db, file_id) = RootDatabase::with_single_file(ra_fixture);
82     let diagnostics = super::diagnostics(
83         &db,
84         &DiagnosticsConfig::default(),
85         &AssistResolveStrategy::All,
86         file_id,
87     );
88     expect.assert_debug_eq(&diagnostics)
89 }
90
91 #[track_caller]
92 pub(crate) fn check_diagnostics(ra_fixture: &str) {
93     let mut config = DiagnosticsConfig::default();
94     config.disabled.insert("inactive-code".to_string());
95     check_diagnostics_with_config(config, ra_fixture)
96 }
97
98 #[track_caller]
99 pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) {
100     let (db, files) = RootDatabase::with_many_files(ra_fixture);
101     for file_id in files {
102         let diagnostics = super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id);
103
104         let expected = extract_annotations(&*db.file_text(file_id));
105         let mut actual = diagnostics
106             .into_iter()
107             .map(|d| {
108                 let mut annotation = String::new();
109                 if let Some(fixes) = &d.fixes {
110                     assert!(!fixes.is_empty());
111                     annotation.push_str("💡 ")
112                 }
113                 annotation.push_str(match d.severity {
114                     Severity::Error => "error",
115                     Severity::WeakWarning => "weak",
116                 });
117                 annotation.push_str(": ");
118                 annotation.push_str(&d.message);
119                 (d.range, annotation)
120             })
121             .collect::<Vec<_>>();
122         actual.sort_by_key(|(range, _)| range.start());
123         assert_eq!(expected, actual);
124     }
125 }
126
127 #[test]
128 fn test_disabled_diagnostics() {
129     let mut config = DiagnosticsConfig::default();
130     config.disabled.insert("unresolved-module".into());
131
132     let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#);
133
134     let diagnostics = super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id);
135     assert!(diagnostics.is_empty());
136
137     let diagnostics = super::diagnostics(
138         &db,
139         &DiagnosticsConfig::default(),
140         &AssistResolveStrategy::All,
141         file_id,
142     );
143     assert!(!diagnostics.is_empty());
144 }