aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/mock.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/mock.rs')
-rw-r--r--crates/ra_hir/src/mock.rs117
1 files changed, 90 insertions, 27 deletions
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 950f89948..5ca870867 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -6,6 +6,7 @@ use ra_db::{
6}; 6};
7use relative_path::RelativePathBuf; 7use relative_path::RelativePathBuf;
8use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; 8use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
9use rustc_hash::FxHashMap;
9 10
10use crate::{db, HirInterner}; 11use crate::{db, HirInterner};
11 12
@@ -21,82 +22,125 @@ pub struct MockDatabase {
21 events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>, 22 events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>,
22 runtime: salsa::Runtime<MockDatabase>, 23 runtime: salsa::Runtime<MockDatabase>,
23 interner: Arc<HirInterner>, 24 interner: Arc<HirInterner>,
24 file_counter: u32, 25 files: FxHashMap<String, FileId>,
25} 26}
26 27
27impl panic::RefUnwindSafe for MockDatabase {} 28impl panic::RefUnwindSafe for MockDatabase {}
28 29
29impl MockDatabase { 30impl MockDatabase {
30 pub fn with_files(fixture: &str) -> (MockDatabase, SourceRoot) { 31 pub fn with_files(fixture: &str) -> MockDatabase {
31 let (db, source_root, position) = MockDatabase::from_fixture(fixture); 32 let (db, position) = MockDatabase::from_fixture(fixture);
32 assert!(position.is_none()); 33 assert!(position.is_none());
33 (db, source_root) 34 db
34 } 35 }
35 36
36 pub fn with_single_file(text: &str) -> (MockDatabase, SourceRoot, FileId) { 37 pub fn with_single_file(text: &str) -> (MockDatabase, SourceRoot, FileId) {
37 let mut db = MockDatabase::default(); 38 let mut db = MockDatabase::default();
38 let mut source_root = SourceRoot::default(); 39 let mut source_root = SourceRoot::default();
39 let file_id = db.add_file(WORKSPACE, &mut source_root, "/main.rs", text); 40 let file_id = db.add_file(WORKSPACE, "/", &mut source_root, "/main.rs", text);
40 db.set_source_root(WORKSPACE, Arc::new(source_root.clone())); 41 db.set_source_root(WORKSPACE, Arc::new(source_root.clone()));
41 (db, source_root, file_id) 42 (db, source_root, file_id)
42 } 43 }
43 44
44 pub fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { 45 pub fn with_position(fixture: &str) -> (MockDatabase, FilePosition) {
45 let (db, _, position) = MockDatabase::from_fixture(fixture); 46 let (db, position) = MockDatabase::from_fixture(fixture);
46 let position = position.expect("expected a marker ( <|> )"); 47 let position = position.expect("expected a marker ( <|> )");
47 (db, position) 48 (db, position)
48 } 49 }
49 50
50 fn from_fixture(fixture: &str) -> (MockDatabase, SourceRoot, Option<FilePosition>) { 51 pub fn file_id_of(&self, path: &str) -> FileId {
52 match self.files.get(path) {
53 Some(it) => *it,
54 None => panic!("unknown file: {:?}\nexisting files:\n{:#?}", path, self.files),
55 }
56 }
57
58 pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) {
59 let mut ids = FxHashMap::default();
60 let mut crate_graph = CrateGraph::default();
61 for (crate_name, (crate_root, _)) in graph.0.iter() {
62 let crate_root = self.file_id_of(&crate_root);
63 let crate_id = crate_graph.add_crate_root(crate_root);
64 ids.insert(crate_name, crate_id);
65 }
66 for (crate_name, (_, deps)) in graph.0.iter() {
67 let from = ids[crate_name];
68 for dep in deps {
69 let to = ids[dep];
70 crate_graph.add_dep(from, dep.as_str().into(), to).unwrap();
71 }
72 }
73 self.set_crate_graph(Arc::new(crate_graph))
74 }
75
76 fn from_fixture(fixture: &str) -> (MockDatabase, Option<FilePosition>) {
51 let mut db = MockDatabase::default(); 77 let mut db = MockDatabase::default();
52 78
53 let (source_root, pos) = db.add_fixture(WORKSPACE, fixture); 79 let pos = db.add_fixture(fixture);
54 80
55 (db, source_root, pos) 81 (db, pos)
56 } 82 }
57 83
58 pub fn add_fixture( 84 fn add_fixture(&mut self, fixture: &str) -> Option<FilePosition> {
59 &mut self,
60 source_root_id: SourceRootId,
61 fixture: &str,
62 ) -> (SourceRoot, Option<FilePosition>) {
63 let mut position = None; 85 let mut position = None;
64 let mut source_root = SourceRoot::default(); 86 let mut source_root = SourceRoot::default();
87 let mut source_root_id = WORKSPACE;
88 let mut source_root_prefix = "/".to_string();
65 for entry in parse_fixture(fixture) { 89 for entry in parse_fixture(fixture) {
90 if entry.meta.starts_with("root") {
91 self.set_source_root(source_root_id, Arc::new(source_root));
92 source_root = SourceRoot::default();
93
94 source_root_id = SourceRootId(source_root_id.0 + 1);
95 source_root_prefix = entry.meta["root".len()..].trim().to_string();
96 continue;
97 }
66 if entry.text.contains(CURSOR_MARKER) { 98 if entry.text.contains(CURSOR_MARKER) {
67 assert!(position.is_none(), "only one marker (<|>) per fixture is allowed"); 99 assert!(position.is_none(), "only one marker (<|>) per fixture is allowed");
68 position = Some(self.add_file_with_position( 100 position = Some(self.add_file_with_position(
69 source_root_id, 101 source_root_id,
102 &source_root_prefix,
70 &mut source_root, 103 &mut source_root,
71 &entry.meta, 104 &entry.meta,
72 &entry.text, 105 &entry.text,
73 )); 106 ));
74 } else { 107 } else {
75 self.add_file(source_root_id, &mut source_root, &entry.meta, &entry.text); 108 self.add_file(
109 source_root_id,
110 &source_root_prefix,
111 &mut source_root,
112 &entry.meta,
113 &entry.text,
114 );
76 } 115 }
77 } 116 }
78 self.set_source_root(source_root_id, Arc::new(source_root.clone())); 117 self.set_source_root(source_root_id, Arc::new(source_root));
79 (source_root, position) 118 position
80 } 119 }
81 120
82 fn add_file( 121 fn add_file(
83 &mut self, 122 &mut self,
84 source_root_id: SourceRootId, 123 source_root_id: SourceRootId,
124 source_root_prefix: &str,
85 source_root: &mut SourceRoot, 125 source_root: &mut SourceRoot,
86 path: &str, 126 path: &str,
87 text: &str, 127 text: &str,
88 ) -> FileId { 128 ) -> FileId {
89 assert!(path.starts_with('/')); 129 assert!(source_root_prefix.starts_with('/'));
90 let is_crate_root = path == "/lib.rs" || path == "/main.rs"; 130 assert!(source_root_prefix.ends_with('/'));
131 assert!(path.starts_with(source_root_prefix));
132 let rel_path = RelativePathBuf::from_path(&path[source_root_prefix.len()..]).unwrap();
133
134 let is_crate_root = rel_path == "lib.rs" || rel_path == "/main.rs";
91 135
92 let path = RelativePathBuf::from_path(&path[1..]).unwrap(); 136 let file_id = FileId(self.files.len() as u32);
93 let file_id = FileId(self.file_counter); 137 let prev = self.files.insert(path.to_string(), file_id);
94 self.file_counter += 1; 138 assert!(prev.is_none(), "duplicate files in the text fixture");
95 let text = Arc::new(text.to_string()); 139 let text = Arc::new(text.to_string());
96 self.set_file_text(file_id, text); 140 self.set_file_text(file_id, text);
97 self.set_file_relative_path(file_id, path.clone()); 141 self.set_file_relative_path(file_id, rel_path.clone());
98 self.set_file_source_root(file_id, source_root_id); 142 self.set_file_source_root(file_id, source_root_id);
99 source_root.files.insert(path, file_id); 143 source_root.files.insert(rel_path, file_id);
100 144
101 if is_crate_root { 145 if is_crate_root {
102 let mut crate_graph = CrateGraph::default(); 146 let mut crate_graph = CrateGraph::default();
@@ -109,12 +153,13 @@ impl MockDatabase {
109 fn add_file_with_position( 153 fn add_file_with_position(
110 &mut self, 154 &mut self,
111 source_root_id: SourceRootId, 155 source_root_id: SourceRootId,
156 source_root_prefix: &str,
112 source_root: &mut SourceRoot, 157 source_root: &mut SourceRoot,
113 path: &str, 158 path: &str,
114 text: &str, 159 text: &str,
115 ) -> FilePosition { 160 ) -> FilePosition {
116 let (offset, text) = extract_offset(text); 161 let (offset, text) = extract_offset(text);
117 let file_id = self.add_file(source_root_id, source_root, path, &text); 162 let file_id = self.add_file(source_root_id, source_root_prefix, source_root, path, &text);
118 FilePosition { file_id, offset } 163 FilePosition { file_id, offset }
119 } 164 }
120} 165}
@@ -138,7 +183,7 @@ impl Default for MockDatabase {
138 events: Default::default(), 183 events: Default::default(),
139 runtime: salsa::Runtime::default(), 184 runtime: salsa::Runtime::default(),
140 interner: Default::default(), 185 interner: Default::default(),
141 file_counter: 0, 186 files: FxHashMap::default(),
142 }; 187 };
143 db.set_crate_graph(Default::default()); 188 db.set_crate_graph(Default::default());
144 db 189 db
@@ -151,7 +196,8 @@ impl salsa::ParallelDatabase for MockDatabase {
151 events: Default::default(), 196 events: Default::default(),
152 runtime: self.runtime.snapshot(self), 197 runtime: self.runtime.snapshot(self),
153 interner: Arc::clone(&self.interner), 198 interner: Arc::clone(&self.interner),
154 file_counter: self.file_counter, 199 // only the root database can be used to get file_id by path.
200 files: FxHashMap::default(),
155 }) 201 })
156 } 202 }
157} 203}
@@ -184,3 +230,20 @@ impl MockDatabase {
184 .collect() 230 .collect()
185 } 231 }
186} 232}
233
234#[derive(Default)]
235pub struct CrateGraphFixture(pub FxHashMap<String, (String, Vec<String>)>);
236
237#[macro_export]
238macro_rules! crate_graph {
239 ($($crate_name:literal: ($crate_path:literal, [$($dep:literal),*]),)*) => {{
240 let mut res = $crate::mock::CrateGraphFixture::default();
241 $(
242 res.0.insert(
243 $crate_name.to_string(),
244 ($crate_path.to_string(), vec![$($dep.to_string()),*])
245 );
246 )*
247 res
248 }}
249}