1#[cfg(test)]
6mod tests {
7 use super::*;
8 use crate::ast_impl::Decl;
9 use crate::module::*;
10 use crate::tokens::Span;
11 use crate::{Located, SurfaceExpr};
12 use std::collections::HashMap;
13 fn mk_span() -> Span {
14 Span::new(0, 1, 1, 1)
15 }
16 fn mk_def(name: &str) -> Decl {
17 Decl::Definition {
18 name: name.to_string(),
19 univ_params: vec![],
20 ty: None,
21 val: Located::new(SurfaceExpr::Hole, mk_span()),
22 where_clauses: vec![],
23 attrs: vec![],
24 }
25 }
26 #[test]
27 fn test_module_create() {
28 let module = Module::new("test".to_string());
29 assert_eq!(module.name, "test");
30 assert_eq!(module.decls.len(), 0);
31 }
32 #[test]
33 fn test_module_full_path() {
34 let mut module = Module::new("test".to_string());
35 assert_eq!(module.full_path(), "test");
36 module.path = vec!["std".to_string()];
37 assert_eq!(module.full_path(), "std.test");
38 }
39 #[test]
40 fn test_registry_create() {
41 let registry = ModuleRegistry::new();
42 assert_eq!(registry.all_modules().len(), 0);
43 }
44 #[test]
45 fn test_register_module() {
46 let mut registry = ModuleRegistry::new();
47 let module = Module::new("test".to_string());
48 assert!(registry.register(module).is_ok());
49 assert!(registry.contains("test"));
50 }
51 #[test]
52 fn test_register_duplicate() {
53 let mut registry = ModuleRegistry::new();
54 let module1 = Module::new("test".to_string());
55 let module2 = Module::new("test".to_string());
56 assert!(registry.register(module1).is_ok());
57 assert!(registry.register(module2).is_err());
58 }
59 #[test]
60 fn test_resolve_name_local() {
61 let mut module = Module::new("test".to_string());
62 module.add_decl(mk_def("foo"));
63 assert_eq!(
64 module.resolve_name("foo"),
65 ResolvedName::Local("foo".to_string())
66 );
67 }
68 #[test]
69 fn test_resolve_name_not_found() {
70 let module = Module::new("test".to_string());
71 assert_eq!(module.resolve_name("foo"), ResolvedName::NotFound);
72 }
73 #[test]
74 fn test_resolve_name_imported_all() {
75 let mut module = Module::new("test".to_string());
76 module.import_specs.push(ImportSpec::All("Std".to_string()));
77 match module.resolve_name("bar") {
78 ResolvedName::Imported { module: m, name } => {
79 assert_eq!(m, "Std");
80 assert_eq!(name, "bar");
81 }
82 _ => panic!("Expected Imported"),
83 }
84 }
85 #[test]
86 fn test_resolve_name_imported_selective() {
87 let mut module = Module::new("test".to_string());
88 module.import_specs.push(ImportSpec::Selective(
89 "Std".to_string(),
90 vec!["bar".to_string()],
91 ));
92 match module.resolve_name("bar") {
93 ResolvedName::Imported { module: m, name } => {
94 assert_eq!(m, "Std");
95 assert_eq!(name, "bar");
96 }
97 _ => panic!("Expected Imported"),
98 }
99 }
100 #[test]
101 fn test_resolve_name_imported_hiding() {
102 let mut module = Module::new("test".to_string());
103 module.import_specs.push(ImportSpec::Hiding(
104 "Std".to_string(),
105 vec!["secret".to_string()],
106 ));
107 match module.resolve_name("bar") {
108 ResolvedName::Imported { module: m, name } => {
109 assert_eq!(m, "Std");
110 assert_eq!(name, "bar");
111 }
112 _ => panic!("Expected Imported"),
113 }
114 }
115 #[test]
116 fn test_resolve_name_renaming() {
117 let mut module = Module::new("test".to_string());
118 module.import_specs.push(ImportSpec::Renaming(
119 "Std".to_string(),
120 vec![("originalName".to_string(), "renamedName".to_string())],
121 ));
122 match module.resolve_name("renamedName") {
123 ResolvedName::Imported { module: m, name } => {
124 assert_eq!(m, "Std");
125 assert_eq!(name, "originalName");
126 }
127 _ => panic!("Expected Imported with original name"),
128 }
129 }
130 #[test]
131 fn test_visible_names() {
132 let mut module = Module::new("test".to_string());
133 module.add_decl(mk_def("foo"));
134 module.add_decl(mk_def("bar"));
135 let visible = module.visible_names();
136 assert!(visible.contains(&"foo".to_string()));
137 assert!(visible.contains(&"bar".to_string()));
138 }
139 #[test]
140 fn test_visible_names_with_aliases() {
141 let mut module = Module::new("test".to_string());
142 module.add_decl(mk_def("foo"));
143 let mut aliases = HashMap::new();
144 aliases.insert("f".to_string(), "foo".to_string());
145 module.add_namespace(NamespaceScope {
146 name: "ns".to_string(),
147 opened: vec![],
148 aliases,
149 visibility: std::collections::HashMap::new(),
150 parent: None,
151 });
152 let visible = module.visible_names();
153 assert!(visible.contains(&"foo".to_string()));
154 assert!(visible.contains(&"f".to_string()));
155 }
156 #[test]
157 fn test_exported_names_all() {
158 let mut module = Module::new("test".to_string());
159 module.add_decl(mk_def("foo"));
160 module.add_decl(mk_def("bar"));
161 module.export_spec = Some(ExportSpec::All);
162 let exported = module.exported_names();
163 assert_eq!(exported.len(), 2);
164 }
165 #[test]
166 fn test_exported_names_selective() {
167 let mut module = Module::new("test".to_string());
168 module.add_decl(mk_def("foo"));
169 module.add_decl(mk_def("bar"));
170 module.export_spec = Some(ExportSpec::Selective(vec!["foo".to_string()]));
171 let exported = module.exported_names();
172 assert_eq!(exported.len(), 1);
173 assert_eq!(exported[0], "foo");
174 }
175 #[test]
176 fn test_exported_names_default() {
177 let mut module = Module::new("test".to_string());
178 module.add_decl(mk_def("foo"));
179 let exported = module.exported_names();
180 assert_eq!(exported, vec!["foo"]);
181 }
182 #[test]
183 fn test_with_import_spec() {
184 let mut module = Module::new("test".to_string());
185 module.with_import_spec(ImportSpec::All("Std".to_string()));
186 assert!(module.imports.contains(&"Std".to_string()));
187 assert_eq!(module.import_specs.len(), 1);
188 }
189 #[test]
190 fn test_add_namespace() {
191 let mut module = Module::new("test".to_string());
192 module.add_namespace(NamespaceScope {
193 name: "Ns".to_string(),
194 opened: vec![],
195 aliases: HashMap::new(),
196 visibility: std::collections::HashMap::new(),
197 parent: None,
198 });
199 assert_eq!(module.namespaces.len(), 1);
200 assert_eq!(module.namespaces[0].name, "Ns");
201 }
202 #[test]
203 fn test_registry_get_mut() {
204 let mut registry = ModuleRegistry::new();
205 let module = Module::new("test".to_string());
206 registry
207 .register(module)
208 .expect("test operation should succeed");
209 let m = registry
210 .get_mut("test")
211 .expect("test operation should succeed");
212 m.add_decl(mk_def("new_decl"));
213 assert_eq!(
214 registry.get("test").expect("key should exist").decls.len(),
215 1
216 );
217 }
218 #[test]
219 fn test_registry_unregister() {
220 let mut registry = ModuleRegistry::new();
221 let module = Module::new("test".to_string());
222 registry
223 .register(module)
224 .expect("test operation should succeed");
225 let removed = registry.unregister("test");
226 assert!(removed.is_some());
227 assert!(!registry.contains("test"));
228 }
229 #[test]
230 fn test_registry_unregister_nonexistent() {
231 let mut registry = ModuleRegistry::new();
232 assert!(registry.unregister("nope").is_none());
233 }
234 #[test]
235 fn test_registry_resolve_local() {
236 let mut registry = ModuleRegistry::new();
237 let mut module = Module::new("A".to_string());
238 module.add_decl(mk_def("foo"));
239 registry
240 .register(module)
241 .expect("test operation should succeed");
242 match registry.resolve("A", "foo") {
243 ResolvedName::Local(name) => assert_eq!(name, "foo"),
244 _ => panic!("Expected Local"),
245 }
246 }
247 #[test]
248 fn test_registry_resolve_imported() {
249 let mut registry = ModuleRegistry::new();
250 let mut mod_a = Module::new("A".to_string());
251 mod_a.add_decl(mk_def("helper"));
252 registry
253 .register(mod_a)
254 .expect("test operation should succeed");
255 let mut mod_b = Module::new("B".to_string());
256 mod_b.with_import_spec(ImportSpec::All("A".to_string()));
257 registry
258 .register(mod_b)
259 .expect("test operation should succeed");
260 match registry.resolve("B", "helper") {
261 ResolvedName::Imported { module, name } => {
262 assert_eq!(module, "A");
263 assert_eq!(name, "helper");
264 }
265 _ => panic!("Expected Imported"),
266 }
267 }
268 #[test]
269 fn test_registry_resolve_not_found() {
270 let mut registry = ModuleRegistry::new();
271 let module = Module::new("A".to_string());
272 registry
273 .register(module)
274 .expect("test operation should succeed");
275 assert_eq!(registry.resolve("A", "nonexistent"), ResolvedName::NotFound);
276 }
277 #[test]
278 fn test_dependency_order_simple() {
279 let mut registry = ModuleRegistry::new();
280 let mod_a = Module::new("A".to_string());
281 registry
282 .register(mod_a)
283 .expect("test operation should succeed");
284 let mut mod_b = Module::new("B".to_string());
285 mod_b.add_import("A".to_string());
286 registry
287 .register(mod_b)
288 .expect("test operation should succeed");
289 let order = registry
290 .dependency_order()
291 .expect("test operation should succeed");
292 let pos_a = order
293 .iter()
294 .position(|n| n == "A")
295 .expect("test operation should succeed");
296 let pos_b = order
297 .iter()
298 .position(|n| n == "B")
299 .expect("test operation should succeed");
300 assert!(pos_a < pos_b);
301 }
302 #[test]
303 fn test_dependency_order_chain() {
304 let mut registry = ModuleRegistry::new();
305 let mod_a = Module::new("A".to_string());
306 registry
307 .register(mod_a)
308 .expect("test operation should succeed");
309 let mut mod_b = Module::new("B".to_string());
310 mod_b.add_import("A".to_string());
311 registry
312 .register(mod_b)
313 .expect("test operation should succeed");
314 let mut mod_c = Module::new("C".to_string());
315 mod_c.add_import("B".to_string());
316 registry
317 .register(mod_c)
318 .expect("test operation should succeed");
319 let order = registry
320 .dependency_order()
321 .expect("test operation should succeed");
322 let pos_a = order
323 .iter()
324 .position(|n| n == "A")
325 .expect("test operation should succeed");
326 let pos_b = order
327 .iter()
328 .position(|n| n == "B")
329 .expect("test operation should succeed");
330 let pos_c = order
331 .iter()
332 .position(|n| n == "C")
333 .expect("test operation should succeed");
334 assert!(pos_a < pos_b);
335 assert!(pos_b < pos_c);
336 }
337 #[test]
338 fn test_detect_cycles_none() {
339 let mut registry = ModuleRegistry::new();
340 let mod_a = Module::new("A".to_string());
341 registry
342 .register(mod_a)
343 .expect("test operation should succeed");
344 let mut mod_b = Module::new("B".to_string());
345 mod_b.add_import("A".to_string());
346 registry
347 .register(mod_b)
348 .expect("test operation should succeed");
349 let cycles = registry.detect_cycles();
350 assert!(cycles.is_empty());
351 }
352 #[test]
353 fn test_detect_cycles_present() {
354 let mut registry = ModuleRegistry::new();
355 let mut mod_a = Module::new("A".to_string());
356 mod_a.add_import("B".to_string());
357 registry
358 .register(mod_a)
359 .expect("test operation should succeed");
360 let mut mod_b = Module::new("B".to_string());
361 mod_b.add_import("A".to_string());
362 registry
363 .register(mod_b)
364 .expect("test operation should succeed");
365 let cycles = registry.detect_cycles();
366 assert!(!cycles.is_empty());
367 }
368 #[test]
369 fn test_transitive_deps_simple() {
370 let mut registry = ModuleRegistry::new();
371 let mod_a = Module::new("A".to_string());
372 registry
373 .register(mod_a)
374 .expect("test operation should succeed");
375 let mut mod_b = Module::new("B".to_string());
376 mod_b.add_import("A".to_string());
377 registry
378 .register(mod_b)
379 .expect("test operation should succeed");
380 let mut mod_c = Module::new("C".to_string());
381 mod_c.add_import("B".to_string());
382 registry
383 .register(mod_c)
384 .expect("test operation should succeed");
385 let deps = registry.transitive_deps("C");
386 assert!(deps.contains(&"A".to_string()));
387 assert!(deps.contains(&"B".to_string()));
388 }
389 #[test]
390 fn test_transitive_deps_empty() {
391 let mut registry = ModuleRegistry::new();
392 let mod_a = Module::new("A".to_string());
393 registry
394 .register(mod_a)
395 .expect("test operation should succeed");
396 let deps = registry.transitive_deps("A");
397 assert!(deps.is_empty());
398 }
399 #[test]
400 fn test_transitive_deps_nonexistent() {
401 let registry = ModuleRegistry::new();
402 let deps = registry.transitive_deps("X");
403 assert!(deps.is_empty());
404 }
405 #[test]
406 fn test_namespace_alias_resolution() {
407 let mut module = Module::new("test".to_string());
408 module.add_decl(mk_def("Nat.add"));
409 let mut aliases = HashMap::new();
410 aliases.insert("add".to_string(), "Nat.add".to_string());
411 module.add_namespace(NamespaceScope {
412 name: "Nat".to_string(),
413 opened: vec![],
414 aliases,
415 visibility: std::collections::HashMap::new(),
416 parent: None,
417 });
418 match module.resolve_name("add") {
419 ResolvedName::Local(name) => assert_eq!(name, "Nat.add"),
420 _ => panic!("Expected Local from alias"),
421 }
422 }
423 #[test]
424 fn test_import_spec_hiding_blocks_name() {
425 let mut module = Module::new("test".to_string());
426 module.import_specs.push(ImportSpec::Hiding(
427 "Std".to_string(),
428 vec!["secret".to_string()],
429 ));
430 let result = module.resolve_name("secret");
431 assert_eq!(result, ResolvedName::NotFound);
432 }
433 #[test]
434 fn test_module_with_config() {
435 let config = ModuleConfig {
436 allow_circular: true,
437 private_by_default: true,
438 allow_shadowing: false,
439 };
440 let module = Module::with_config("test".to_string(), config);
441 assert!(module.config.allow_circular);
442 assert!(module.config.private_by_default);
443 }
444 #[test]
445 fn test_set_and_get_visibility() {
446 let mut module = Module::new("test".to_string());
447 module.set_visibility("foo".to_string(), Visibility::Private);
448 assert_eq!(module.get_visibility("foo"), Visibility::Private);
449 }
450 #[test]
451 fn test_get_visibility_default_public() {
452 let module = Module::new("test".to_string());
453 assert_eq!(module.get_visibility("undefined"), Visibility::Public);
454 }
455 #[test]
456 fn test_get_visibility_default_private() {
457 let config = ModuleConfig {
458 allow_circular: false,
459 private_by_default: true,
460 allow_shadowing: false,
461 };
462 let module = Module::with_config("test".to_string(), config);
463 assert_eq!(module.get_visibility("undefined"), Visibility::Private);
464 }
465 #[test]
466 fn test_add_and_get_opens() {
467 let mut module = Module::new("test".to_string());
468 module.add_open("Std".to_string(), false);
469 module.add_open("Math".to_string(), true);
470 let opens = module.get_opens();
471 assert_eq!(opens.len(), 2);
472 assert!(opens.contains(&"Std".to_string()));
473 assert!(opens.contains(&"Math".to_string()));
474 }
475 #[test]
476 fn test_is_accessible_public() {
477 let mut module = Module::new("test".to_string());
478 module.set_visibility("foo".to_string(), Visibility::Public);
479 assert!(module.is_accessible("foo", false));
480 assert!(module.is_accessible("foo", true));
481 }
482 #[test]
483 fn test_is_accessible_private_same_module() {
484 let mut module = Module::new("test".to_string());
485 module.set_visibility("foo".to_string(), Visibility::Private);
486 assert!(module.is_accessible("foo", true));
487 assert!(!module.is_accessible("foo", false));
488 }
489 #[test]
490 fn test_get_dependencies_imports() {
491 let mut module = Module::new("test".to_string());
492 module.add_import("A".to_string());
493 module.add_import("B".to_string());
494 let deps = module.get_dependencies();
495 assert_eq!(deps.len(), 2);
496 assert!(deps.contains("A"));
497 assert!(deps.contains("B"));
498 }
499 #[test]
500 fn test_get_dependencies_opens() {
501 let mut module = Module::new("test".to_string());
502 module.add_open("Std".to_string(), false);
503 let deps = module.get_dependencies();
504 assert!(deps.contains("Std"));
505 }
506 #[test]
507 fn test_imports_module() {
508 let mut module = Module::new("test".to_string());
509 module.add_import("Std".to_string());
510 assert!(module.imports_module("Std"));
511 assert!(!module.imports_module("Math"));
512 }
513 #[test]
514 fn test_get_hidden_names() {
515 let mut module = Module::new("test".to_string());
516 module.import_specs.push(ImportSpec::Hiding(
517 "Std".to_string(),
518 vec!["secret".to_string(), "hidden".to_string()],
519 ));
520 let hidden = module.get_hidden_names("Std");
521 assert_eq!(hidden.len(), 2);
522 }
523 #[test]
524 fn test_resolve_selective_import() {
525 let module = Module::new("test".to_string());
526 let selected = vec!["foo".to_string(), "bar".to_string()];
527 let resolved = module.resolve_selective_import("Std", &selected);
528 assert_eq!(resolved, selected);
529 }
530 #[test]
531 fn test_namespace_lookup() {
532 let mut module = Module::new("test".to_string());
533 let mut aliases = HashMap::new();
534 aliases.insert("f".to_string(), "Nat.add".to_string());
535 module.add_namespace(NamespaceScope {
536 name: "Nat".to_string(),
537 opened: vec![],
538 aliases,
539 visibility: std::collections::HashMap::new(),
540 parent: None,
541 });
542 let resolved = module.lookup_in_namespaces("f");
543 assert_eq!(resolved, Some("Nat.add".to_string()));
544 }
545 #[test]
546 fn test_namespace_names() {
547 let mut module = Module::new("test".to_string());
548 let mut aliases = HashMap::new();
549 aliases.insert("a".to_string(), "A".to_string());
550 aliases.insert("b".to_string(), "B".to_string());
551 module.add_namespace(NamespaceScope {
552 name: "ns".to_string(),
553 opened: vec![],
554 aliases,
555 visibility: std::collections::HashMap::new(),
556 parent: None,
557 });
558 let names = module.namespace_names("ns");
559 assert_eq!(names.len(), 2);
560 assert!(names.contains(&"a".to_string()));
561 assert!(names.contains(&"b".to_string()));
562 }
563 #[test]
564 fn test_all_visible_names() {
565 let mut module = Module::new("test".to_string());
566 module.add_decl(mk_def("foo"));
567 module.add_decl(mk_def("bar"));
568 module.set_visibility("foo".to_string(), Visibility::Public);
569 module.set_visibility("bar".to_string(), Visibility::Private);
570 let visible = module.all_visible_names();
571 assert!(visible.iter().any(|nv| nv.name == "foo"));
572 assert!(visible.iter().any(|nv| nv.name == "bar"));
573 }
574 #[test]
575 fn test_registry_detect_mutual_imports_none() {
576 let mut registry = ModuleRegistry::new();
577 let mod_a = Module::new("A".to_string());
578 registry
579 .register(mod_a)
580 .expect("test operation should succeed");
581 let mut mod_b = Module::new("B".to_string());
582 mod_b.add_import("A".to_string());
583 registry
584 .register(mod_b)
585 .expect("test operation should succeed");
586 let mutual = registry.detect_mutual_imports();
587 assert!(mutual.is_empty());
588 }
589 #[test]
590 fn test_registry_detect_mutual_imports_present() {
591 let mut registry = ModuleRegistry::new();
592 let mut mod_a = Module::new("A".to_string());
593 mod_a.add_import("B".to_string());
594 registry
595 .register(mod_a)
596 .expect("test operation should succeed");
597 let mut mod_b = Module::new("B".to_string());
598 mod_b.add_import("A".to_string());
599 registry
600 .register(mod_b)
601 .expect("test operation should succeed");
602 let mutual = registry.detect_mutual_imports();
603 assert!(!mutual.is_empty());
604 }
605 #[test]
606 fn test_are_mutually_dependent_yes() {
607 let mut registry = ModuleRegistry::new();
608 let mut mod_a = Module::new("A".to_string());
609 mod_a.add_import("B".to_string());
610 registry
611 .register(mod_a)
612 .expect("test operation should succeed");
613 let mut mod_b = Module::new("B".to_string());
614 mod_b.add_import("A".to_string());
615 registry
616 .register(mod_b)
617 .expect("test operation should succeed");
618 assert!(registry.are_mutually_dependent("A", "B"));
619 }
620 #[test]
621 fn test_are_mutually_dependent_no() {
622 let mut registry = ModuleRegistry::new();
623 let mod_a = Module::new("A".to_string());
624 registry
625 .register(mod_a)
626 .expect("test operation should succeed");
627 let mut mod_b = Module::new("B".to_string());
628 mod_b.add_import("A".to_string());
629 registry
630 .register(mod_b)
631 .expect("test operation should succeed");
632 assert!(!registry.are_mutually_dependent("A", "B"));
633 }
634 #[test]
635 fn test_get_dependents_empty() {
636 let mut registry = ModuleRegistry::new();
637 let mod_a = Module::new("A".to_string());
638 registry
639 .register(mod_a)
640 .expect("test operation should succeed");
641 let dependents = registry.get_dependents("A");
642 assert!(dependents.is_empty());
643 }
644 #[test]
645 fn test_get_dependents_one() {
646 let mut registry = ModuleRegistry::new();
647 let mod_a = Module::new("A".to_string());
648 registry
649 .register(mod_a)
650 .expect("test operation should succeed");
651 let mut mod_b = Module::new("B".to_string());
652 mod_b.add_import("A".to_string());
653 registry
654 .register(mod_b)
655 .expect("test operation should succeed");
656 let dependents = registry.get_dependents("A");
657 assert_eq!(dependents.len(), 1);
658 assert_eq!(dependents[0], "B");
659 }
660 #[test]
661 fn test_get_all_dependencies_chain() {
662 let mut registry = ModuleRegistry::new();
663 let mod_a = Module::new("A".to_string());
664 registry
665 .register(mod_a)
666 .expect("test operation should succeed");
667 let mut mod_b = Module::new("B".to_string());
668 mod_b.add_import("A".to_string());
669 registry
670 .register(mod_b)
671 .expect("test operation should succeed");
672 let mut mod_c = Module::new("C".to_string());
673 mod_c.add_import("B".to_string());
674 registry
675 .register(mod_c)
676 .expect("test operation should succeed");
677 let all_deps = registry.get_all_dependencies("C");
678 assert!(all_deps.contains(&"B".to_string()));
679 assert!(all_deps.contains(&"A".to_string()));
680 }
681 #[test]
682 fn test_verify_consistency_ok() {
683 let mut registry = ModuleRegistry::new();
684 let mod_a = Module::new("A".to_string());
685 registry
686 .register(mod_a)
687 .expect("test operation should succeed");
688 assert!(registry.verify_consistency().is_ok());
689 }
690 #[test]
691 fn test_verify_consistency_broken() {
692 let mut registry = ModuleRegistry::new();
693 let mut mod_a = Module::new("A".to_string());
694 mod_a.add_import("NonExistent".to_string());
695 registry
696 .register(mod_a)
697 .expect("test operation should succeed");
698 assert!(registry.verify_consistency().is_err());
699 }
700 #[test]
701 fn test_get_reverse_dependencies() {
702 let mut registry = ModuleRegistry::new();
703 let mod_a = Module::new("A".to_string());
704 registry
705 .register(mod_a)
706 .expect("test operation should succeed");
707 let mut mod_b = Module::new("B".to_string());
708 mod_b.add_import("A".to_string());
709 registry
710 .register(mod_b)
711 .expect("test operation should succeed");
712 let mut mod_c = Module::new("C".to_string());
713 mod_c.add_import("B".to_string());
714 registry
715 .register(mod_c)
716 .expect("test operation should succeed");
717 let rev_deps = registry.get_reverse_dependencies("A");
718 assert!(rev_deps.contains(&"B".to_string()));
719 assert!(rev_deps.contains(&"C".to_string()));
720 }
721 #[test]
722 fn test_reachable_from() {
723 let mut registry = ModuleRegistry::new();
724 let mod_a = Module::new("A".to_string());
725 registry
726 .register(mod_a)
727 .expect("test operation should succeed");
728 let mut mod_b = Module::new("B".to_string());
729 mod_b.add_import("A".to_string());
730 registry
731 .register(mod_b)
732 .expect("test operation should succeed");
733 let reachable = registry.reachable_from("B");
734 assert!(reachable.contains(&"A".to_string()));
735 }
736 #[test]
737 fn test_get_statistics() {
738 let mut registry = ModuleRegistry::new();
739 let mut mod_a = Module::new("A".to_string());
740 mod_a.add_import("B".to_string());
741 mod_a.add_open("C".to_string(), false);
742 registry
743 .register(mod_a)
744 .expect("test operation should succeed");
745 let stats = registry.get_statistics();
746 assert_eq!(stats.get("modules"), Some(&1));
747 assert_eq!(stats.get("total_imports"), Some(&1));
748 assert_eq!(stats.get("total_opens"), Some(&1));
749 }
750 #[test]
751 fn test_get_public_interface() {
752 let mut registry = ModuleRegistry::new();
753 let mut mod_a = Module::new("A".to_string());
754 mod_a.add_decl(mk_def("public_func"));
755 mod_a.set_visibility("public_func".to_string(), Visibility::Public);
756 mod_a.export_spec = Some(ExportSpec::All);
757 registry
758 .register(mod_a)
759 .expect("test operation should succeed");
760 let iface = registry.get_public_interface("A");
761 assert!(iface.contains(&"public_func".to_string()));
762 }
763 #[test]
764 fn test_is_name_accessible() {
765 let mut registry = ModuleRegistry::new();
766 let mut mod_a = Module::new("A".to_string());
767 mod_a.add_decl(mk_def("public_func"));
768 mod_a.set_visibility("public_func".to_string(), Visibility::Public);
769 registry
770 .register(mod_a)
771 .expect("test operation should succeed");
772 assert!(registry.is_name_accessible("public_func", "B", "A"));
773 }
774 #[test]
775 fn test_resolve_with_opens() {
776 let mut module = Module::new("test".to_string());
777 module.add_open("Std".to_string(), false);
778 match module.resolve_with_opens("foo") {
779 ResolvedName::Imported { module: m, name } => {
780 assert_eq!(m, "Std");
781 assert_eq!(name, "foo");
782 }
783 _ => panic!("Expected Imported"),
784 }
785 }
786 #[test]
787 fn test_get_sccs() {
788 let mut registry = ModuleRegistry::new();
789 let mod_a = Module::new("A".to_string());
790 registry
791 .register(mod_a)
792 .expect("test operation should succeed");
793 let sccs = registry.get_sccs();
794 let module_count = registry.all_modules().len();
795 assert!(sccs.is_empty() || module_count > 0);
796 }
797 #[test]
798 fn test_module_full_path_nested() {
799 let mut module = Module::new("inner".to_string());
800 module.path = vec!["root".to_string(), "middle".to_string()];
801 assert_eq!(module.full_path(), "root.middle.inner");
802 }
803 #[test]
804 fn test_set_default_visibility() {
805 let mut module = Module::new("test".to_string());
806 module.set_default_visibility(Visibility::Private);
807 assert!(module.config.private_by_default);
808 }
809 #[test]
810 fn test_registry_multiple_dependents() {
811 let mut registry = ModuleRegistry::new();
812 let mod_a = Module::new("A".to_string());
813 registry
814 .register(mod_a)
815 .expect("test operation should succeed");
816 let mut mod_b = Module::new("B".to_string());
817 mod_b.add_import("A".to_string());
818 registry
819 .register(mod_b)
820 .expect("test operation should succeed");
821 let mut mod_c = Module::new("C".to_string());
822 mod_c.add_import("A".to_string());
823 registry
824 .register(mod_c)
825 .expect("test operation should succeed");
826 let dependents = registry.get_dependents("A");
827 assert_eq!(dependents.len(), 2);
828 }
829 #[test]
830 fn test_open_directive_scoped() {
831 let open = OpenDirective {
832 module: "Std".to_string(),
833 scoped: true,
834 };
835 assert_eq!(open.module, "Std");
836 assert!(open.scoped);
837 }
838 #[test]
839 fn test_visibility_enum() {
840 assert_eq!(Visibility::Public, Visibility::Public);
841 assert_ne!(Visibility::Public, Visibility::Private);
842 }
843}
844#[cfg(test)]
845mod module_ext_tests {
846 use super::*;
847 use crate::ast_impl::Decl;
848 use crate::module::*;
849 use std::collections::HashMap;
850 #[test]
851 fn test_module_dep() {
852 let dep = ModuleDepExt::direct("A", "B");
853 assert_eq!(dep.from, "A");
854 assert_eq!(dep.to, "B");
855 assert!(dep.direct);
856 }
857 #[test]
858 fn test_dep_graph() {
859 let mut g = DepGraphExt::new();
860 g.add(ModuleDepExt::direct("A", "B"));
861 g.add(ModuleDepExt::direct("A", "C"));
862 g.add(ModuleDepExt::direct("B", "C"));
863 let deps = g.direct_deps("A");
864 assert_eq!(deps.len(), 2);
865 assert!(deps.contains(&"B"));
866 let dependents = g.dependents("C");
867 assert_eq!(dependents.len(), 2);
868 }
869 #[test]
870 fn test_self_import_detection() {
871 let mut g = DepGraphExt::new();
872 g.add(ModuleDepExt::direct("A", "A"));
873 assert!(g.has_self_import());
874 let mut g2 = DepGraphExt::new();
875 g2.add(ModuleDepExt::direct("A", "B"));
876 assert!(!g2.has_self_import());
877 }
878}
879#[cfg(test)]
880mod module_ext2_tests {
881 use super::*;
882 use crate::ast_impl::Decl;
883 use crate::module::*;
884 use std::collections::HashMap;
885 #[test]
886 fn test_module_attribute() {
887 let attr = ModuleAttribute::new("simp");
888 assert_eq!(attr.format(), "@[simp]");
889 let attr2 = ModuleAttribute::new("reducible").with_arg("500");
890 assert_eq!(attr2.format(), "@[reducible 500]");
891 }
892 #[test]
893 fn test_export_entry() {
894 let e = ExportEntry::all("Foo");
895 assert!(e.all);
896 let e2 = ExportEntry::names("Bar", vec!["x", "y"]);
897 assert!(!e2.all);
898 assert_eq!(e2.names.len(), 2);
899 }
900}
901#[cfg(test)]
902mod module_meta_tests {
903 use super::*;
904 use crate::ast_impl::Decl;
905 use crate::module::*;
906 use std::collections::HashMap;
907 #[test]
908 fn test_module_version() {
909 let v = ModuleVersion::new(1, 2, 3);
910 assert_eq!(v.format(), "1.2.3");
911 }
912 #[test]
913 fn test_module_metadata() {
914 let m = ModuleMetadata::new("Foo")
915 .with_version(ModuleVersion::new(0, 1, 0))
916 .with_author("Alice");
917 assert_eq!(m.name, "Foo");
918 assert!(m.version.is_some());
919 assert_eq!(m.author.as_deref(), Some("Alice"));
920 }
921}
922#[allow(dead_code)]
924#[allow(missing_docs)]
925pub fn module_fingerprint(name: &str, content: &str) -> u64 {
926 let mut hash = 14695981039346656037u64;
927 for b in name
928 .bytes()
929 .chain(b":".iter().copied())
930 .chain(content.bytes())
931 {
932 hash ^= b as u64;
933 hash = hash.wrapping_mul(1099511628211u64);
934 }
935 hash
936}
937#[allow(dead_code)]
939#[allow(missing_docs)]
940pub fn is_valid_module_name(name: &str) -> bool {
941 if name.is_empty() {
942 return false;
943 }
944 name.split('.')
945 .all(|part| !part.is_empty() && part.starts_with(|c: char| c.is_uppercase()))
946}
947#[cfg(test)]
948mod module_fingerprint_tests {
949 use super::*;
950 use crate::ast_impl::Decl;
951 use crate::module::*;
952 use std::collections::HashMap;
953 #[test]
954 fn test_module_fingerprint_stable() {
955 let h1 = module_fingerprint("Foo", "content");
956 let h2 = module_fingerprint("Foo", "content");
957 assert_eq!(h1, h2);
958 let h3 = module_fingerprint("Bar", "content");
959 assert_ne!(h1, h3);
960 }
961 #[test]
962 fn test_is_valid_module_name() {
963 assert!(is_valid_module_name("Foo.Bar.Baz"));
964 assert!(!is_valid_module_name("foo.bar"));
965 assert!(!is_valid_module_name(""));
966 assert!(!is_valid_module_name("Foo..Bar"));
967 }
968}
969#[allow(dead_code)]
971#[allow(missing_docs)]
972pub fn module_in_namespace(module: &str, namespace: &str) -> bool {
973 module.starts_with(namespace)
974}
975#[allow(dead_code)]
977#[allow(missing_docs)]
978pub fn top_namespace(module: &str) -> &str {
979 module.split('.').next().unwrap_or(module)
980}
981#[cfg(test)]
982mod module_pad {
983 use super::*;
984 use crate::ast_impl::Decl;
985 use crate::module::*;
986 use std::collections::HashMap;
987 #[test]
988 fn test_module_in_namespace() {
989 assert!(module_in_namespace("Mathlib.Algebra.Ring", "Mathlib"));
990 assert!(!module_in_namespace("Std.Tactic", "Mathlib"));
991 }
992 #[test]
993 fn test_top_namespace() {
994 assert_eq!(top_namespace("Mathlib.Algebra.Ring"), "Mathlib");
995 assert_eq!(top_namespace("Std"), "Std");
996 }
997}
998#[allow(dead_code)]
1000#[allow(missing_docs)]
1001pub fn module_depth(name: &str) -> usize {
1002 name.split('.').count()
1003}
1004#[allow(dead_code)]
1006#[allow(missing_docs)]
1007pub fn parent_module(name: &str) -> Option<&str> {
1008 name.rfind('.').map(|i| &name[..i])
1009}
1010#[allow(dead_code)]
1012#[allow(missing_docs)]
1013pub fn leaf_module_name(name: &str) -> &str {
1014 name.rfind('.').map(|i| &name[i + 1..]).unwrap_or(name)
1015}
1016#[cfg(test)]
1017mod module_pad2 {
1018 use super::*;
1019 use crate::ast_impl::Decl;
1020 use crate::module::*;
1021 use std::collections::HashMap;
1022 #[test]
1023 fn test_module_depth() {
1024 assert_eq!(module_depth("Mathlib.Algebra.Ring"), 3);
1025 assert_eq!(module_depth("Std"), 1);
1026 }
1027 #[test]
1028 fn test_parent_module() {
1029 assert_eq!(
1030 parent_module("Mathlib.Algebra.Ring"),
1031 Some("Mathlib.Algebra")
1032 );
1033 assert_eq!(parent_module("Std"), None);
1034 }
1035 #[test]
1036 fn test_leaf_module_name() {
1037 assert_eq!(leaf_module_name("Mathlib.Algebra.Ring"), "Ring");
1038 assert_eq!(leaf_module_name("Std"), "Std");
1039 }
1040}
1041#[allow(dead_code)]
1043#[allow(missing_docs)]
1044pub fn are_sibling_modules(a: &str, b: &str) -> bool {
1045 parent_module(a) == parent_module(b)
1046}