Add module declaration type checking
[hiphop-php.git] / hphp / hack / test / unit / naming / naming_table_tests.ml
bloba6570bf02a5d3302a8a30023a7422dfec3c3f755
1 (*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
9 *)
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. *)
16 open Hh_prelude
18 let deps_mode = Typing_deps_mode.InMemoryMode None
20 module Types_pos_asserter = Asserter.Make_asserter (struct
21 type t = FileInfo.pos * Naming_types.kind_of_type
23 let to_string (pos, kind_of_type) =
24 Printf.sprintf
25 "(%s, %s)"
26 (FileInfo.show_pos pos)
27 (Naming_types.show_kind_of_type kind_of_type)
29 let is_equal = Poly.( = )
30 end)
32 module Pos_asserter = Asserter.Make_asserter (struct
33 type t = FileInfo.pos
35 let to_string pos = Printf.sprintf "(%s)" (FileInfo.show_pos pos)
37 let is_equal = FileInfo.equal_pos
38 end)
40 let files =
42 ("foo.php", {|<?hh
43 class Foo {}
44 |});
45 ("bar.php", {|<?hh
46 function bar(): void {}
47 |});
48 ("baz.php", {|<?hh
49 type Baz = Foo;
50 |});
51 ("qux.php", {|<?hh
52 const int Qux = 5;
53 |});
54 ("qux.php", {|<?hh
55 const int Qux = 5;
56 |});
57 ( "corge.php",
58 {|<?hh
59 <<file: __EnableUnstableFeatures('modules')>>
60 module Corge {}
65 let write_and_parse_test_files ctx =
66 let files =
67 List.map files ~f:(fun (fn, contents) ->
68 (Relative_path.from_root ~suffix:fn, contents))
70 List.iter files ~f:(fun (fn, contents) ->
71 let fn = Path.make (Relative_path.to_absolute fn) in
72 let dir = Path.dirname fn in
73 Disk.mkdir_p (Path.to_string dir);
74 Disk.write_file ~file:(Path.to_string fn) ~contents);
75 let get_next = MultiWorker.next None (List.map files ~f:fst) in
76 let (file_infos, errors, failed_parsing) =
78 TypecheckerOptions.use_direct_decl_parser (Provider_context.get_tcopt ctx)
79 then
80 ( Direct_decl_service.go
81 ctx
82 None
83 ~ide_files:Relative_path.Set.empty
84 ~get_next
85 ~trace:true
86 ~cache_decls:false,
87 Errors.empty,
88 Relative_path.Set.empty )
89 else
90 let po =
91 ParserOptions.with_allow_unstable_features ParserOptions.default true
93 Parsing_service.go_DEPRECATED
94 ctx
95 None
96 Relative_path.Set.empty
97 ~get_next
99 ~trace:true
101 if not (Errors.is_empty errors) then (
102 Errors.iter_error_list
103 (fun e ->
104 List.iter (User_error.to_list_ e) ~f:(fun (pos, msg) ->
105 eprintf
106 "%s: %s\n"
107 (Pos.string
108 (Pos.to_absolute @@ Pos_or_decl.unsafe_to_raw_pos pos))
109 msg))
110 errors;
111 failwith "Expected no errors from parsing."
113 if not (Relative_path.Set.is_empty failed_parsing) then
114 failwith "Expected all files to pass parsing.";
115 Naming_table.create file_infos
117 let run_naming_table_test f =
118 Tempfile.with_real_tempdir (fun path ->
119 Relative_path.set_path_prefix
120 Relative_path.Root
121 (Path.concat path "root/");
122 let config =
123 SharedMem.
125 global_size = 1024;
126 heap_size = 1024 * 1024;
127 hash_table_pow = 10;
128 shm_dirs = [];
129 shm_use_sharded_hashtbl = false;
130 shm_cache_size = -1;
131 shm_min_avail = 0;
132 log_level = 0;
133 sample_rate = 0.0;
134 compression = 0;
137 let popt =
138 ParserOptions.with_allow_unstable_features ParserOptions.default true
140 let tcopt = TypecheckerOptions.default in
141 let ctx =
142 Provider_context.empty_for_tool
143 ~popt
144 ~tcopt
145 ~backend:(Provider_backend.get ())
146 ~deps_mode
148 let (_ : SharedMem.handle) = SharedMem.init config ~num_workers:0 in
149 let unbacked_naming_table = write_and_parse_test_files ctx in
150 let db_name = Path.to_string (Path.concat path "naming_table.sqlite") in
151 let save_results = Naming_table.save unbacked_naming_table db_name in
152 Asserter.Int_asserter.assert_equals
154 Naming_sqlite.(save_results.files_added + save_results.symbols_added)
155 "Expected to add eight rows (four files and four symbols)";
157 let ctx_for_sqlite_load =
158 Provider_context.empty_for_test ~popt ~tcopt ~deps_mode
160 let backed_naming_table =
161 Naming_table.load_from_sqlite ctx_for_sqlite_load db_name
164 Provider_backend.set_local_memory_backend_with_defaults_for_test ();
165 let ctx =
166 Provider_context.empty_for_tool
167 ~popt
168 ~tcopt
169 ~backend:(Provider_backend.get ())
170 ~deps_mode
172 (* load_from_sqlite will call set_naming_db_path for the ctx it's given, but
173 here is a fresh ctx with a fresh backend so we have to set it again. *)
174 Db_path_provider.set_naming_db_path
175 (Provider_context.get_backend ctx)
176 (Some (Naming_sqlite.Db_path db_name));
177 (try f ~ctx ~unbacked_naming_table ~backed_naming_table ~db_name with
178 | e ->
179 Printf.eprintf
180 "NOTE: backend was local-memory for this exception's test run\n";
181 raise e);
182 Provider_backend.set_shared_memory_backend ();
183 let ctx =
184 Provider_context.empty_for_tool
185 ~popt
186 ~tcopt
187 ~backend:(Provider_backend.get ())
188 ~deps_mode
190 (try f ~ctx ~unbacked_naming_table ~backed_naming_table ~db_name with
191 | e ->
192 Printf.eprintf
193 "NOTE: backend was shared-memory for this exception's test run\n";
194 raise e);
195 true)
197 let test_get_pos () =
198 run_naming_table_test
199 (fun ~ctx ~unbacked_naming_table:_ ~backed_naming_table:_ ~db_name:_ ->
200 Types_pos_asserter.assert_option_equals
201 (Some
202 ( FileInfo.File
203 (FileInfo.Class, Relative_path.from_root ~suffix:"foo.php"),
204 Naming_types.TClass ))
205 (Naming_provider.get_type_pos_and_kind ctx "\\Foo")
206 "Check for class type";
207 Pos_asserter.assert_option_equals
208 (Some
209 (FileInfo.File
210 (FileInfo.Fun, Relative_path.from_root ~suffix:"bar.php")))
211 (Naming_provider.get_fun_pos ctx "\\bar")
212 "Check for function";
213 Types_pos_asserter.assert_option_equals
214 (Some
215 ( FileInfo.File
216 (FileInfo.Typedef, Relative_path.from_root ~suffix:"baz.php"),
217 Naming_types.TTypedef ))
218 (Naming_provider.get_type_pos_and_kind ctx "\\Baz")
219 "Check for typedef type";
220 Pos_asserter.assert_option_equals
221 (Some
222 (FileInfo.File
223 (FileInfo.Const, Relative_path.from_root ~suffix:"qux.php")))
224 (Naming_provider.get_const_pos ctx "\\Qux")
225 "Check for const";
226 Pos_asserter.assert_option_equals
227 (Some
228 (FileInfo.File
229 (FileInfo.Module, Relative_path.from_root ~suffix:"corge.php")))
230 (Naming_provider.get_module_pos ctx "Corge")
231 "Check for module")
233 let test_get_canon_name () =
234 run_naming_table_test
235 (fun ~ctx ~unbacked_naming_table:_ ~backed_naming_table:_ ~db_name:_ ->
236 (* Since we're parsing but not naming, the canon heap must fall back to the
237 files on disk, which is the situation we'd be in when loading from a
238 saved state. *)
239 Asserter.String_asserter.assert_option_equals
240 (Some "\\Foo")
241 (Naming_provider.get_type_canon_name ctx "\\foo")
242 "Check for class canon name";
243 Asserter.String_asserter.assert_option_equals
244 (Some "\\bar")
245 (Naming_provider.get_fun_canon_name ctx "\\bar")
246 "Check for function canon name lowercase";
247 Asserter.String_asserter.assert_option_equals
248 (Some "\\bar")
249 (Naming_provider.get_fun_canon_name ctx "\\BAR")
250 "Check for function canon name uppercase";
251 Asserter.String_asserter.assert_option_equals
252 (Some "\\Baz")
253 (Naming_provider.get_type_canon_name ctx "\\baz")
254 "Check for typedef canon name")
256 let test_remove () =
257 run_naming_table_test
258 (fun ~ctx:_ ~unbacked_naming_table ~backed_naming_table ~db_name:_ ->
259 let foo_path = Relative_path.from_root ~suffix:"foo.php" in
260 assert (
261 Naming_table.get_file_info unbacked_naming_table foo_path
262 |> Option.is_some);
263 let unbacked_naming_table =
264 Naming_table.remove unbacked_naming_table foo_path
266 assert (
267 Naming_table.get_file_info unbacked_naming_table foo_path
268 |> Option.is_none);
270 assert (
271 Naming_table.get_file_info backed_naming_table foo_path
272 |> Option.is_some);
273 let backed_naming_table =
274 Naming_table.remove backed_naming_table foo_path
276 assert (
277 Naming_table.get_file_info backed_naming_table foo_path
278 |> Option.is_none))
280 let test_get_sqlite_paths () =
281 run_naming_table_test
282 (fun ~ctx ~unbacked_naming_table:_ ~backed_naming_table ~db_name ->
283 let provider_path =
284 match
285 Db_path_provider.get_naming_db_path (Provider_context.get_backend ctx)
286 with
287 | None -> None
288 | Some (Naming_sqlite.Db_path path) -> Some path
290 Asserter.String_asserter.assert_option_equals
291 (Some db_name)
292 provider_path
293 "get_naming_db_path should return the expected value";
295 Asserter.String_asserter.assert_option_equals
296 (Some db_name)
297 (Naming_table.get_forward_naming_fallback_path backed_naming_table)
298 "get_forward_naming_fallback_path should return the expected value")
300 let test_local_changes () =
301 run_naming_table_test
302 (fun ~ctx ~unbacked_naming_table:_ ~backed_naming_table ~db_name ->
303 let a_name = "CONST_IN_A" in
305 let a_file = Relative_path.from_root ~suffix:"a.php" in
306 let a_pos = FileInfo.File (FileInfo.Const, a_file) in
307 let a_file_info =
308 FileInfo.
310 FileInfo.empty_t with
311 consts = [(a_pos, a_name, None)];
312 hash = Some (Int64.of_int 1234567);
315 let backed_naming_table =
316 Naming_table.update backed_naming_table a_file a_file_info
318 let changes_since_baseline_path = "/tmp/base_plus_changes" in
319 Naming_table.save_changes_since_baseline
320 backed_naming_table
321 ~destination_path:changes_since_baseline_path;
322 let (changes_since_baseline : Naming_table.changes_since_baseline) =
323 Marshal.from_string (Disk.cat changes_since_baseline_path) 0
325 Asserter.Relative_path_asserter.assert_list_equals
326 [a_file]
327 (Naming_table.get_files_changed_since_baseline changes_since_baseline)
328 "Expected files changed since baseline to be correct";
329 let backed_naming_table' =
330 Naming_table.load_from_sqlite_with_changes_since_baseline
332 changes_since_baseline
333 db_name
335 let a_file_info' =
336 Option.value_exn
337 (Naming_table.get_file_info backed_naming_table' a_file)
339 Asserter.Bool_asserter.assert_equals
340 true
341 (FileInfo.equal_hash_type
342 a_file_info.FileInfo.hash
343 a_file_info'.FileInfo.hash)
344 "Expected file info to be found in the naming table";
345 let a_pos' =
346 Option.value_exn (Naming_provider.get_const_pos ctx a_name)
348 Asserter.Bool_asserter.assert_equals
349 true
350 (FileInfo.equal_pos a_pos a_pos')
351 "Expected position of constant to be found in the naming table")
353 let test_context_changes_consts () =
354 run_naming_table_test
355 (fun ~ctx ~unbacked_naming_table:_ ~backed_naming_table:_ ~db_name:_ ->
356 let (ctx, _entry) =
357 Provider_context.add_or_overwrite_entry_contents
358 ~ctx
359 ~path:(Relative_path.from_root ~suffix:"foo.php")
360 ~contents:{|<?hh
361 class New_qux {}
364 let (ctx, _entry) =
365 Provider_context.add_or_overwrite_entry_contents
366 ~ctx
367 ~path:(Relative_path.from_root ~suffix:"qux.php")
368 ~contents:{|<?hh
369 const int New_qux = 5;
372 Asserter.Relative_path_asserter.assert_option_equals
373 (Some (Relative_path.from_root ~suffix:"qux.php"))
374 (Naming_provider.get_const_path ctx "\\New_qux")
375 "New const in context should be visible";
376 Asserter.Relative_path_asserter.assert_option_equals
377 None
378 (Naming_provider.get_const_path ctx "\\Qux")
379 "Old, deleted const in context should NOT be visible")
381 let test_context_changes_funs () =
382 run_naming_table_test
383 (fun ~ctx ~unbacked_naming_table:_ ~backed_naming_table:_ ~db_name:_ ->
384 Asserter.String_asserter.assert_option_equals
385 (Some "\\bar")
386 (Naming_provider.get_fun_canon_name ctx "\\bar")
387 "Existing function should be accessible by non-canon name \\bar";
388 Asserter.String_asserter.assert_option_equals
389 (Some "\\bar")
390 (Naming_provider.get_fun_canon_name ctx "\\BAR")
391 "Existing function should be accessible by non-canon name \\BAR";
393 let (ctx, _entry) =
394 Provider_context.add_or_overwrite_entry_contents
395 ~ctx
396 ~path:(Relative_path.from_root ~suffix:"foo.php")
397 ~contents:{|<?hh
398 class bar {}
401 let (ctx, _entry) =
402 Provider_context.add_or_overwrite_entry_contents
403 ~ctx
404 ~path:(Relative_path.from_root ~suffix:"bar.php")
405 ~contents:{|<?hh
406 function new_bar(): void {}
409 Asserter.Relative_path_asserter.assert_option_equals
410 (Some (Relative_path.from_root ~suffix:"bar.php"))
411 (Naming_provider.get_fun_path ctx "\\new_bar")
412 "New function in context should be visible";
413 Asserter.Relative_path_asserter.assert_option_equals
414 None
415 (Naming_provider.get_fun_path ctx "\\bar")
416 "Old, deleted function in context should NOT be visible";
418 Asserter.String_asserter.assert_option_equals
419 (Some "\\new_bar")
420 (Naming_provider.get_fun_canon_name ctx "\\NeW_bAr")
421 "New function in context should be accessible by canon name";
423 (* NB: under shared-memory provider, the following two tests aren't
424 useful. Sharedmem doesn't suppress canonical lookup results that
425 have been overridden by the context. (That's because sharedmem only
426 gives us back the canonical name, not the path where that canonical
427 name was defined, and without paths we can't tell whether it's been
428 overridden by context). For the sharedmem case, the caller is expected
429 to manually remove any old reverse-naming-table entries before calling
430 into the naming provider -- something that this test doesn't do.
431 Hence why it gives incorrect answers. *)
432 let expected =
433 match Provider_context.get_backend ctx with
434 | Provider_backend.Shared_memory ->
435 Some "\\bar" (* because the caller (us) is expected to clean up *)
436 | _ -> None
438 Asserter.String_asserter.assert_option_equals
439 expected
440 (Naming_provider.get_fun_canon_name ctx "\\bar")
441 "Old function in context should NOT be accessible by non-canon name \\bar";
442 Asserter.String_asserter.assert_option_equals
443 expected
444 (Naming_provider.get_fun_canon_name ctx "\\BAR")
445 "Old function in context should NOT be accessible by non-canon name \\BAR";
446 Asserter.String_asserter.assert_option_equals
447 expected
448 (Naming_provider.get_fun_canon_name ctx "\\BaR")
449 "Old function in context should NOT be accessible by non-canon name \\BaR";
452 let test_context_changes_classes () =
453 run_naming_table_test
454 (fun ~ctx ~unbacked_naming_table:_ ~backed_naming_table:_ ~db_name:_ ->
455 Asserter.String_asserter.assert_option_equals
456 (Some "\\Foo")
457 (Naming_provider.get_type_canon_name ctx "\\Foo")
458 "Existing class should be accessible by non-canon name \\Foo";
459 Asserter.String_asserter.assert_option_equals
460 (Some "\\Foo")
461 (Naming_provider.get_type_canon_name ctx "\\FOO")
462 "Existing class should be accessible by non-canon name \\FOO";
464 let (ctx, _entry) =
465 Provider_context.add_or_overwrite_entry_contents
466 ~ctx
467 ~path:(Relative_path.from_root ~suffix:"foo.php")
468 ~contents:{|<?hh
469 class NewFoo {}
472 Asserter.Relative_path_asserter.assert_option_equals
473 (Some (Relative_path.from_root ~suffix:"foo.php"))
474 (Naming_provider.get_class_path ctx "\\NewFoo")
475 "New class in context should be visible";
476 Asserter.Relative_path_asserter.assert_option_equals
477 None
478 (Naming_provider.get_class_path ctx "\\Foo")
479 "Old class in context should NOT be visible";
481 Asserter.String_asserter.assert_option_equals
482 (Some "\\NewFoo")
483 (Naming_provider.get_type_canon_name ctx "\\NEWFOO")
484 "New class in context should be accessible by canon name";
486 (* NB: under shared-memory provider, the following two tests aren't
487 useful. Sharedmem doesn't suppress canonical lookup results that
488 have been overridden by the context. (That's because sharedmem only
489 gives us back the canonical name, not the path where that canonical
490 name was defined, and without paths we can't tell whether it's been
491 overridden by context). For the sharedmem case, the caller is expected
492 to manually remove any old reverse-naming-table entries before calling
493 into the naming provider -- something that this test doesn't do.
494 Hence why it gives incorrect answers. *)
495 let expected =
496 match Provider_context.get_backend ctx with
497 | Provider_backend.Shared_memory ->
498 Some "\\Foo" (* because the caller (us) is expected to clean up *)
499 | _ -> None
501 Asserter.String_asserter.assert_option_equals
502 expected
503 (Naming_provider.get_type_canon_name ctx "\\Foo")
504 "Old class in context should NOT be accessible by non-canon name \\Foo";
505 Asserter.String_asserter.assert_option_equals
506 expected
507 (Naming_provider.get_type_canon_name ctx "\\FOO")
508 "Old class in context should NOT be accessible by non-canon name \\FOO";
509 Asserter.String_asserter.assert_option_equals
510 expected
511 (Naming_provider.get_type_canon_name ctx "\\FoO")
512 "Old class in context should NOT be accessible by non-canon name \\FoO";
515 let test_context_changes_typedefs () =
516 run_naming_table_test
517 (fun ~ctx ~unbacked_naming_table:_ ~backed_naming_table:_ ~db_name:_ ->
518 Asserter.String_asserter.assert_option_equals
519 (Some "\\Baz")
520 (Naming_provider.get_type_canon_name ctx "\\Baz")
521 "Existing typedef should be accessible by non-canon name \\Baz";
522 Asserter.String_asserter.assert_option_equals
523 (Some "\\Baz")
524 (Naming_provider.get_type_canon_name ctx "\\BAZ")
525 "Existing typedef should be accessible by non-canon name \\BAZ";
527 let (ctx, _entry) =
528 Provider_context.add_or_overwrite_entry_contents
529 ~ctx
530 ~path:(Relative_path.from_root ~suffix:"baz.php")
531 ~contents:{|<?hh
532 type NewBaz = Foo;
535 Asserter.Relative_path_asserter.assert_option_equals
536 (Some (Relative_path.from_root ~suffix:"baz.php"))
537 (Naming_provider.get_typedef_path ctx "\\NewBaz")
538 "New typedef in context should be visible";
539 Asserter.Relative_path_asserter.assert_option_equals
540 None
541 (Naming_provider.get_typedef_path ctx "\\Baz")
542 "Old typedef in context should NOT be visible";
544 Asserter.String_asserter.assert_option_equals
545 (Some "\\NewBaz")
546 (Naming_provider.get_type_canon_name ctx "\\NEWBAZ")
547 "New typedef in context should be accessible by canon name";
549 (* NB: under shared-memory provider, the following two tests aren't
550 useful. Sharedmem doesn't suppress canonical lookup results that
551 have been overridden by the context. (That's because sharedmem only
552 gives us back the canonical name, not the path where that canonical
553 name was defined, and without paths we can't tell whether it's been
554 overridden by context). For the sharedmem case, the caller is expected
555 to manually remove any old reverse-naming-table entries before calling
556 into the naming provider -- something that this test doesn't do.
557 Hence why it gives incorrect answers. *)
558 let expected =
559 match Provider_context.get_backend ctx with
560 | Provider_backend.Shared_memory ->
561 Some "\\Baz" (* because the caller (us) is expected to clean up *)
562 | _ -> None
564 Asserter.String_asserter.assert_option_equals
565 expected
566 (Naming_provider.get_type_canon_name ctx "\\Baz")
567 "Old typedef in context should NOT be accessible by non-canon name \\Baz";
568 Asserter.String_asserter.assert_option_equals
569 expected
570 (Naming_provider.get_type_canon_name ctx "\\BAZ")
571 "Old typedef in context should NOT be accessible by non-canon name \\BAZ";
572 Asserter.String_asserter.assert_option_equals
573 expected
574 (Naming_provider.get_type_canon_name ctx "\\BaZ")
575 "Old typedef in context should NOT be accessible by non-canon name \\BaZ";
578 let test_naming_table_hash () =
579 List.iter [0; -1; 1; 200; -200; Int.max_value; Int.min_value] ~f:(fun i ->
580 let dep = Typing_deps.Dep.of_debug_string (string_of_int i) in
581 let hash = Typing_deps.Dep.to_int64 dep in
582 (* "%16x" on a negative integer will produce a hex version as if it were unsigned, e.g. -2 is printed as 7ffffffffffffffe rather than -0000000000000002. *)
583 let i_str = Printf.sprintf "0x%016x" i in
584 let hash_str = Caml.Int64.format "0x%016x" hash in
585 Asserter.String_asserter.assert_equals
586 i_str
587 hash_str
588 "Expected 64bit hash to be same as int hash");
590 let foo_dep = Typing_deps.Dep.Type "\\Foo" in
591 let foo_dep_hash =
592 Typing_deps.Dep.make foo_dep |> Typing_deps.Dep.to_hex_string
594 Asserter.String_asserter.assert_equals
595 "0x4cd17f7c3d7b6feb"
596 foo_dep_hash
597 "Expected foo dep hash to be correct (this test must be updated if the hashing logic changes)";
599 true
601 let test_naming_table_query_by_dep_hash () =
602 run_naming_table_test
603 (fun ~ctx ~unbacked_naming_table:_ ~backed_naming_table ~db_name:_ ->
604 let db_path =
605 Db_path_provider.get_naming_db_path (Provider_context.get_backend ctx)
607 let db_path = Option.value_exn db_path in
608 Asserter.Relative_path_asserter.assert_option_equals
609 (Some (Relative_path.from_root ~suffix:"qux.php"))
610 (Typing_deps.Dep.GConst "\\Qux"
611 |> Typing_deps.Dep.make
612 |> Naming_sqlite.get_path_by_64bit_dep db_path
613 |> Option.map ~f:fst)
614 "Look up const by dep hash should return file path";
615 Asserter.Relative_path_asserter.assert_option_equals
616 None
617 (Typing_deps.Dep.GConst "\\Nonexistent"
618 |> Typing_deps.Dep.make
619 |> Naming_sqlite.get_path_by_64bit_dep db_path
620 |> Option.map ~f:fst)
621 "Look up non-existent const by dep hash should return nothing";
623 Asserter.Relative_path_asserter.assert_option_equals
624 (Some (Relative_path.from_root ~suffix:"bar.php"))
625 (Typing_deps.Dep.Fun "\\bar"
626 |> Typing_deps.Dep.make
627 |> Naming_sqlite.get_path_by_64bit_dep db_path
628 |> Option.map ~f:fst)
629 "Look up fun by dep hash should return file path";
630 Asserter.Relative_path_asserter.assert_option_equals
631 None
632 (Typing_deps.Dep.Fun "\\nonexistent"
633 |> Typing_deps.Dep.make
634 |> Naming_sqlite.get_path_by_64bit_dep db_path
635 |> Option.map ~f:fst)
636 "Look up non-existent fun by dep hash should return nothing";
638 Asserter.Relative_path_asserter.assert_option_equals
639 (Some (Relative_path.from_root ~suffix:"foo.php"))
640 (Typing_deps.Dep.Type "\\Foo"
641 |> Typing_deps.Dep.make
642 |> Naming_sqlite.get_path_by_64bit_dep db_path
643 |> Option.map ~f:fst)
644 "Look up class by dep hash should return file path";
645 Asserter.Relative_path_asserter.assert_option_equals
646 None
647 (Typing_deps.Dep.Type "\\nonexistent"
648 |> Typing_deps.Dep.make
649 |> Naming_sqlite.get_path_by_64bit_dep db_path
650 |> Option.map ~f:fst)
651 "Look up non-existent class by dep hash should return nothing";
653 Asserter.Relative_path_asserter.assert_option_equals
654 (Some (Relative_path.from_root ~suffix:"baz.php"))
655 (Typing_deps.Dep.Type "\\Baz"
656 |> Typing_deps.Dep.make
657 |> Naming_sqlite.get_path_by_64bit_dep db_path
658 |> Option.map ~f:fst)
659 "Look up class by dep hash should return file path";
660 Asserter.Relative_path_asserter.assert_option_equals
661 None
662 (Typing_deps.Dep.Type "\\nonexistent"
663 |> Typing_deps.Dep.make
664 |> Naming_sqlite.get_path_by_64bit_dep db_path
665 |> Option.map ~f:fst)
666 "Look up non-existent typedef by dep hash should return nothing";
668 Asserter.Relative_path_asserter.assert_list_equals
669 [Relative_path.from_root ~suffix:"qux.php"]
670 (Typing_deps.Dep.GConst "\\Qux"
671 |> Typing_deps.Dep.make
672 |> Typing_deps.DepSet.singleton
673 |> Naming_table.get_64bit_dep_set_files backed_naming_table
674 |> Relative_path.Set.elements)
675 "Bulk lookup for const should be correct";
676 Asserter.Relative_path_asserter.assert_list_equals
677 [Relative_path.from_root ~suffix:"bar.php"]
678 (Typing_deps.Dep.Fun "\\bar"
679 |> Typing_deps.Dep.make
680 |> Typing_deps.DepSet.singleton
681 |> Naming_table.get_64bit_dep_set_files backed_naming_table
682 |> Relative_path.Set.elements)
683 "Bulk lookup for fun should be correct";
684 Asserter.Relative_path_asserter.assert_list_equals
685 [Relative_path.from_root ~suffix:"baz.php"]
686 (Typing_deps.Dep.Type "\\Baz"
687 |> Typing_deps.Dep.make
688 |> Typing_deps.DepSet.singleton
689 |> Naming_table.get_64bit_dep_set_files backed_naming_table
690 |> Relative_path.Set.elements)
691 "Bulk lookup for class should be correct";
693 Asserter.Relative_path_asserter.assert_list_equals
695 Relative_path.from_root ~suffix:"bar.php";
696 Relative_path.from_root ~suffix:"baz.php";
697 Relative_path.from_root ~suffix:"qux.php";
699 (Typing_deps.DepSet.make ()
700 |> Typing_deps.DepSet.union
701 (Typing_deps.Dep.GConst "\\Qux"
702 |> Typing_deps.Dep.make
703 |> Typing_deps.DepSet.singleton)
704 |> Typing_deps.DepSet.union
705 (Typing_deps.Dep.Fun "\\bar"
706 |> Typing_deps.Dep.make
707 |> Typing_deps.DepSet.singleton)
708 |> Typing_deps.DepSet.union
709 (Typing_deps.Dep.Type "\\Baz"
710 |> Typing_deps.Dep.make
711 |> Typing_deps.DepSet.singleton)
712 |> Naming_table.get_64bit_dep_set_files backed_naming_table
713 |> Relative_path.Set.elements)
714 "Bulk lookup for multiple elements should be correct";
716 (* Simulate moving \Baz from baz.php to bar.php. *)
717 let baz_file_info = FileInfo.empty_t in
718 let bar_file_info =
720 (* Might raise {!Naming_table.File_info_not_found} *)
721 (Naming_table.get_file_info_unsafe
722 backed_naming_table
723 (Relative_path.from_root ~suffix:"bar.php"))
724 with
725 FileInfo.classes =
727 ( FileInfo.File
728 (FileInfo.Class, Relative_path.from_root ~suffix:"bar.php"),
729 "\\Baz",
730 None );
734 let new_naming_table = backed_naming_table in
735 let new_naming_table =
736 Naming_table.update
737 new_naming_table
738 (Relative_path.from_root ~suffix:"baz.php")
739 baz_file_info
741 let new_naming_table =
742 Naming_table.update
743 new_naming_table
744 (Relative_path.from_root ~suffix:"bar.php")
745 bar_file_info
747 Asserter.Relative_path_asserter.assert_list_equals
748 [Relative_path.from_root ~suffix:"bar.php"]
749 (Typing_deps.Dep.Type "\\Baz"
750 |> Typing_deps.Dep.make
751 |> Typing_deps.DepSet.singleton
752 |> Naming_table.get_64bit_dep_set_files new_naming_table
753 |> Relative_path.Set.elements)
754 "\\Baz should now be located in bar.php";
758 let () =
759 let config =
760 SharedMem.
762 global_size = 1024;
763 heap_size = 1024 * 1024;
764 hash_table_pow = 10;
765 shm_dirs = [];
766 shm_use_sharded_hashtbl = false;
767 shm_cache_size = -1;
768 shm_min_avail = 0;
769 log_level = 0;
770 sample_rate = 0.0;
771 compression = 0;
774 let (_ : SharedMem.handle) = SharedMem.init config ~num_workers:0 in
775 Unit_test.run_all
777 ("test_get_pos", test_get_pos);
778 ("test_get_canon_name", test_get_canon_name);
779 ("test_remove", test_remove);
780 ("test_get_sqlite_paths", test_get_sqlite_paths);
781 ("test_local_changes", test_local_changes);
782 ("test_context_changes_consts", test_context_changes_consts);
783 ("test_context_changes_funs", test_context_changes_funs);
784 ("test_context_changes_classes", test_context_changes_classes);
785 ("test_context_changes_typedefs", test_context_changes_typedefs);
786 ("test_naming_table_hash", test_naming_table_hash);
787 ( "test_naming_table_query_by_dep_hash",
788 test_naming_table_query_by_dep_hash );