2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
11 (* These are basically the same tests as in
12 * test/integration_ml/saved_state/test_naming_table_sqlite_fallback.ml, but
13 * as stripped down to just the basics as possible to make finding the root
14 * cause of test failures easier. *)
18 module Types_pos_asserter
= Asserter.Make_asserter
(struct
19 type t
= FileInfo.pos
* Naming_types.kind_of_type
21 let to_string (pos
, type_of_type
) =
24 (FileInfo.show_pos pos
)
25 (Naming_types.kind_of_type_to_enum type_of_type
)
30 module Pos_asserter
= Asserter.Make_asserter
(struct
33 let to_string pos
= Printf.sprintf
"(%s)" (FileInfo.show_pos pos
)
44 function bar
(): void
{}
54 let write_and_parse_test_files () =
56 List.map
files ~f
:(fun (fn
, contents
) ->
57 (Relative_path.from_root fn
, contents
))
59 List.iter
files ~f
:(fun (fn
, contents
) ->
60 let fn = Path.make
(Relative_path.to_absolute
fn) in
61 let dir = Path.dirname
fn in
62 Disk.mkdir_p
(Path.to_string dir);
63 Disk.write_file ~file
:(Path.to_string fn) ~contents
);
64 let (file_infos
, errors
, failed_parsing
) =
67 Relative_path.Set.empty
68 ~get_next
:(MultiWorker.next None
(List.map
files ~f
:fst
))
72 if not
(Errors.is_empty errors
) then (
73 Errors.iter_error_list
75 List.iter
(Errors.to_list e
) ~f
:(fun (pos
, msg
) ->
76 eprintf
"%s: %s\n" (Pos.string (Pos.to_absolute pos
)) msg
))
78 failwith
"Expected no errors from parsing."
80 if failed_parsing
<> Relative_path.Set.empty
then
81 failwith
"Expected all files to pass parsing.";
82 Naming_table.create file_infos
84 let run_naming_table_test f
=
85 Tempfile.with_real_tempdir
(fun path
->
86 Relative_path.set_path_prefix
88 (Path.concat path
"root/");
93 heap_size
= 1024 * 1024;
102 let (_
: SharedMem.handle
) = SharedMem.init
config ~num_workers
:0 in
103 let unbacked_naming_table = write_and_parse_test_files () in
104 let db_name = Path.to_string (Path.concat path
"naming_table.sqlite") in
105 let save_results = Naming_table.save
unbacked_naming_table db_name in
106 Asserter.Int_asserter.assert_equals
108 Naming_sqlite.(save_results.files_added
+ save_results.symbols_added
)
109 "Expected to add eight rows (four files and four symbols)";
111 let popt = ParserOptions.default
in
112 let tcopt = TypecheckerOptions.default
in
113 let ctx_for_sqlite_load = Provider_context.empty_for_test ~
popt ~
tcopt in
114 let backed_naming_table =
115 Naming_table.load_from_sqlite
ctx_for_sqlite_load db_name
118 Provider_backend.set_local_memory_backend_with_defaults
();
120 Provider_context.empty_for_tool
123 ~backend
:(Provider_backend.get
())
125 (try f ~
ctx ~
unbacked_naming_table ~
backed_naming_table ~
db_name
128 "NOTE: backend was local-memory for this exception's test run\n";
130 Provider_backend.set_shared_memory_backend
();
132 Provider_context.empty_for_tool
135 ~backend
:(Provider_backend.get
())
137 (try f ~
ctx ~
unbacked_naming_table ~
backed_naming_table ~
db_name
140 "NOTE: backend was shared-memory for this exception's test run\n";
144 let test_get_pos () =
145 run_naming_table_test
146 (fun ~
ctx ~
unbacked_naming_table:_ ~
backed_naming_table:_ ~
db_name:_
->
147 Types_pos_asserter.assert_option_equals
149 ( FileInfo.File
(FileInfo.Class
, Relative_path.from_root
"foo.php"),
150 Naming_types.TClass
))
151 (Naming_provider.get_type_pos_and_kind
ctx "\\Foo")
152 "Check for class type";
153 Pos_asserter.assert_option_equals
154 (Some
(FileInfo.File
(FileInfo.Fun
, Relative_path.from_root
"bar.php")))
155 (Naming_provider.get_fun_pos
ctx "\\bar")
156 "Check for function";
157 Types_pos_asserter.assert_option_equals
159 ( FileInfo.File
(FileInfo.Typedef
, Relative_path.from_root
"baz.php"),
160 Naming_types.TTypedef
))
161 (Naming_provider.get_type_pos_and_kind
ctx "\\Baz")
162 "Check for typedef type";
163 Pos_asserter.assert_option_equals
165 (FileInfo.File
(FileInfo.Const
, Relative_path.from_root
"qux.php")))
166 (Naming_provider.get_const_pos
ctx "\\Qux")
169 let test_get_canon_name () =
170 run_naming_table_test
171 (fun ~
ctx ~
unbacked_naming_table:_ ~
backed_naming_table:_ ~
db_name:_
->
172 (* Since we're parsing but not naming, the canon heap must fall back to the
173 files on disk, which is the situation we'd be in when loading from a
175 Asserter.String_asserter.assert_option_equals
177 (Naming_provider.get_type_canon_name
ctx "\\foo")
178 "Check for class canon name";
179 Asserter.String_asserter.assert_option_equals
181 (Naming_provider.get_fun_canon_name
ctx "\\bar")
182 "Check for function canon name lowercase";
183 Asserter.String_asserter.assert_option_equals
185 (Naming_provider.get_fun_canon_name
ctx "\\BAR")
186 "Check for function canon name uppercase";
187 Asserter.String_asserter.assert_option_equals
189 (Naming_provider.get_type_canon_name
ctx "\\baz")
190 "Check for typedef canon name")
193 run_naming_table_test
194 (fun ~
ctx:_ ~
unbacked_naming_table ~
backed_naming_table ~
db_name:_
->
195 let foo_path = Relative_path.from_root
"foo.php" in
197 Naming_table.get_file_info
unbacked_naming_table foo_path
199 let unbacked_naming_table =
200 Naming_table.remove
unbacked_naming_table foo_path
203 Naming_table.get_file_info
unbacked_naming_table foo_path
207 Naming_table.get_file_info
backed_naming_table foo_path
209 let backed_naming_table =
210 Naming_table.remove
backed_naming_table foo_path
213 Naming_table.get_file_info
backed_naming_table foo_path
216 let test_get_sqlite_paths () =
217 run_naming_table_test
218 (fun ~
ctx:_ ~
unbacked_naming_table:_ ~
backed_naming_table ~
db_name ->
219 Asserter.String_asserter.assert_option_equals
221 (Naming_table.get_reverse_naming_fallback_path
())
222 "get_reverse_naming_fallback_path should return the expected value";
224 Asserter.String_asserter.assert_option_equals
226 (Naming_table.get_forward_naming_fallback_path
backed_naming_table)
227 "get_forward_naming_fallback_path should return the expected value")
229 let test_local_changes () =
230 run_naming_table_test
231 (fun ~
ctx ~
unbacked_naming_table:_ ~
backed_naming_table ~
db_name ->
232 let a_name = "CONST_IN_A" in
234 let a_file = Relative_path.from_root
"a.php" in
235 let a_pos = FileInfo.File
(FileInfo.Const
, a_file) in
237 FileInfo.{ FileInfo.empty_t
with consts
= [(a_pos, a_name)] }
239 let backed_naming_table =
240 Naming_table.update
backed_naming_table a_file a_file_info
242 let changes_since_baseline_path = "/tmp/base_plus_changes" in
243 Naming_table.save_changes_since_baseline
245 changes_since_baseline_path;
246 let (changes_since_baseline
: Naming_table.changes_since_baseline
) =
247 Marshal.from_string
(Disk.cat
changes_since_baseline_path) 0
249 Asserter.Relative_path_asserter.assert_list_equals
251 (Naming_table.get_files_changed_since_baseline changes_since_baseline
)
252 "Expected files changed since baseline to be correct";
253 let backed_naming_table'
=
254 Naming_table.load_from_sqlite_with_changes_since_baseline
256 changes_since_baseline
261 (Naming_table.get_file_info
backed_naming_table'
a_file)
263 Asserter.Bool_asserter.assert_equals
265 (a_file_info = a_file_info'
)
266 "Expected file info to be found in the naming table";
269 Option.value_exn
(Naming_provider.get_const_pos
ctx a_name)
271 Asserter.Bool_asserter.assert_equals
274 "Expected position of constant to be found in the naming table")
276 let test_context_changes_consts () =
277 run_naming_table_test
278 (fun ~
ctx ~
unbacked_naming_table:_ ~
backed_naming_table:_ ~
db_name:_
->
280 Provider_context.add_or_overwrite_entry_contents
282 ~path
:(Relative_path.from_root
"foo.php")
288 Provider_context.add_or_overwrite_entry_contents
290 ~path
:(Relative_path.from_root
"qux.php")
292 const
int New_qux
= 5;
295 Asserter.Relative_path_asserter.assert_option_equals
296 (Some
(Relative_path.from_root
"qux.php"))
297 (Naming_provider.get_const_path
ctx "\\New_qux")
298 "New const in context should be visible";
299 Asserter.Relative_path_asserter.assert_option_equals
301 (Naming_provider.get_const_path
ctx "\\Qux")
302 "Old, deleted const in context should NOT be visible")
304 let test_context_changes_funs () =
305 run_naming_table_test
306 (fun ~
ctx ~
unbacked_naming_table:_ ~
backed_naming_table:_ ~
db_name:_
->
308 Provider_context.add_or_overwrite_entry_contents
310 ~path
:(Relative_path.from_root
"foo.php")
316 Provider_context.add_or_overwrite_entry_contents
318 ~path
:(Relative_path.from_root
"bar.php")
320 function new_bar
(): void
{}
323 Asserter.Relative_path_asserter.assert_option_equals
324 (Some
(Relative_path.from_root
"bar.php"))
325 (Naming_provider.get_fun_path
ctx "\\new_bar")
326 "New function in context should be visible";
327 Asserter.Relative_path_asserter.assert_option_equals
329 (Naming_provider.get_fun_path
ctx "\\bar")
330 "Old, deleted function in context should NOT be visible";
332 Asserter.String_asserter.assert_option_equals
334 (Naming_provider.get_fun_canon_name
ctx "\\NeW_bAr")
335 "New function in context should be accessible by canon name";
337 (* NB: under shared-memory provider, this doesn't hold true if we made
338 a call to `get_fun_canon_name` before we added the context entry, as
339 the result will be cached. The caller is expected to have manually
340 removed any old reverse naming table entries manually in that case. *)
341 Asserter.String_asserter.assert_option_equals
343 (Naming_provider.get_fun_canon_name
ctx "\\BAR")
344 "Old function in context should NOT be accessible by canon name")
346 let test_context_changes_classes () =
347 run_naming_table_test
348 (fun ~
ctx ~
unbacked_naming_table:_ ~
backed_naming_table:_ ~
db_name:_
->
350 Provider_context.add_or_overwrite_entry_contents
352 ~path
:(Relative_path.from_root
"foo.php")
357 Asserter.Relative_path_asserter.assert_option_equals
358 (Some
(Relative_path.from_root
"foo.php"))
359 (Naming_provider.get_class_path
ctx "\\NewFoo")
360 "New class in context should be visible";
361 Asserter.Relative_path_asserter.assert_option_equals
363 (Naming_provider.get_class_path
ctx "\\Foo")
364 "Old class in context should NOT be visible";
366 Asserter.String_asserter.assert_option_equals
368 (Naming_provider.get_type_canon_name
ctx "\\NEWFOO")
369 "New class in context should be accessible by canon name";
371 (* NB: under shared-memory provider, this doesn't hold true if we made
372 a call to `get_type_canon_name` before we added the context entry, as
373 the result will be cached. The caller is expected to have manually
374 removed any old reverse naming table entries manually in that case. *)
375 Asserter.String_asserter.assert_option_equals
377 (Naming_provider.get_type_canon_name
ctx "\\FOO")
378 "Old class in context should NOT be accessible by canon name")
380 let test_context_changes_typedefs () =
381 run_naming_table_test
382 (fun ~
ctx ~
unbacked_naming_table:_ ~
backed_naming_table:_ ~
db_name:_
->
384 Provider_context.add_or_overwrite_entry_contents
386 ~path
:(Relative_path.from_root
"baz.php")
391 Asserter.Relative_path_asserter.assert_option_equals
392 (Some
(Relative_path.from_root
"baz.php"))
393 (Naming_provider.get_typedef_path
ctx "\\NewBaz")
394 "New typedef in context should be visible";
395 Asserter.Relative_path_asserter.assert_option_equals
397 (Naming_provider.get_typedef_path
ctx "\\Baz")
398 "Old typedef in context should NOT be visible";
400 Asserter.String_asserter.assert_option_equals
402 (Naming_provider.get_type_canon_name
ctx "\\NEWBAZ")
403 "New typedef in context should be accessible by canon name";
405 (* NB: under shared-memory provider, this doesn't hold true if we made
406 a call to `get_type_canon_name` before we added the context entry, as
407 the result will be cached. The caller is expected to have manually
408 removed any old reverse naming table entries manually in that case. *)
409 Asserter.String_asserter.assert_option_equals
411 (Naming_provider.get_type_canon_name
ctx "\\BAZ")
412 "Old typedef in context should NOT be accessible by canon name")
419 heap_size
= 1024 * 1024;
428 let (_
: SharedMem.handle
) = SharedMem.init
config ~num_workers
:0 in
431 ("test_get_pos", test_get_pos);
432 ("test_get_canon_name", test_get_canon_name);
433 ("test_remove", test_remove);
434 ("test_get_sqlite_paths", test_get_sqlite_paths);
435 ("test_local_changes", test_local_changes);
436 ("test_context_changes_consts", test_context_changes_consts);
437 ("test_context_changes_funs", test_context_changes_funs);
438 ("test_context_changes_classes", test_context_changes_classes);
439 ("test_context_changes_typedefs", test_context_changes_typedefs);