Skip to main content

oxilean_parse/module/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5#[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/// A module fingerprint for change detection.
923#[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/// Returns whether a module name is a valid Lean-style dotted name.
938#[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/// Returns whether a module is in a given namespace.
970#[allow(dead_code)]
971#[allow(missing_docs)]
972pub fn module_in_namespace(module: &str, namespace: &str) -> bool {
973    module.starts_with(namespace)
974}
975/// Returns the top-level namespace of a module name.
976#[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/// Returns the depth of a module name (number of dots + 1).
999#[allow(dead_code)]
1000#[allow(missing_docs)]
1001pub fn module_depth(name: &str) -> usize {
1002    name.split('.').count()
1003}
1004/// Returns the parent module of a dotted module name.
1005#[allow(dead_code)]
1006#[allow(missing_docs)]
1007pub fn parent_module(name: &str) -> Option<&str> {
1008    name.rfind('.').map(|i| &name[..i])
1009}
1010/// Returns the leaf name (last component) of a module name.
1011#[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/// Checks if two modules are siblings (share the same parent).
1042#[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}