1#![allow(dead_code)]
5#![allow(missing_docs)]
6
7#[allow(dead_code)]
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum BuildPhase {
15 Primitives,
17 Collections,
19 TypeClasses,
21 Theorems,
23 Automation,
25}
26
27impl BuildPhase {
28 #[allow(dead_code)]
30 pub fn all_in_order() -> &'static [BuildPhase] {
31 &[
32 BuildPhase::Primitives,
33 BuildPhase::Collections,
34 BuildPhase::TypeClasses,
35 BuildPhase::Theorems,
36 BuildPhase::Automation,
37 ]
38 }
39
40 #[allow(dead_code)]
42 pub fn name(&self) -> &'static str {
43 match self {
44 BuildPhase::Primitives => "primitives",
45 BuildPhase::Collections => "collections",
46 BuildPhase::TypeClasses => "type_classes",
47 BuildPhase::Theorems => "theorems",
48 BuildPhase::Automation => "automation",
49 }
50 }
51}
52
53#[allow(dead_code)]
55#[derive(Debug, Clone)]
56pub struct StdModuleEntry {
57 pub qualified_name: &'static str,
59 pub phase: BuildPhase,
61 pub default_load: bool,
63 pub description: &'static str,
65}
66
67#[allow(dead_code)]
69pub static STD_MODULE_REGISTRY: &[StdModuleEntry] = &[
70 StdModuleEntry {
71 qualified_name: "Std.Nat",
72 phase: BuildPhase::Primitives,
73 default_load: true,
74 description: "Natural number type",
75 },
76 StdModuleEntry {
77 qualified_name: "Std.Bool",
78 phase: BuildPhase::Primitives,
79 default_load: true,
80 description: "Boolean type",
81 },
82 StdModuleEntry {
83 qualified_name: "Std.Char",
84 phase: BuildPhase::Primitives,
85 default_load: true,
86 description: "Unicode character type",
87 },
88 StdModuleEntry {
89 qualified_name: "Std.Int",
90 phase: BuildPhase::Primitives,
91 default_load: true,
92 description: "Signed integer type",
93 },
94 StdModuleEntry {
95 qualified_name: "Std.String",
96 phase: BuildPhase::Primitives,
97 default_load: true,
98 description: "Immutable string type",
99 },
100 StdModuleEntry {
101 qualified_name: "Std.List",
102 phase: BuildPhase::Collections,
103 default_load: true,
104 description: "Linked list type",
105 },
106 StdModuleEntry {
107 qualified_name: "Std.Array",
108 phase: BuildPhase::Collections,
109 default_load: true,
110 description: "Fixed-size arrays",
111 },
112 StdModuleEntry {
113 qualified_name: "Std.Set",
114 phase: BuildPhase::Collections,
115 default_load: false,
116 description: "Mathematical sets",
117 },
118 StdModuleEntry {
119 qualified_name: "Std.Fin",
120 phase: BuildPhase::Collections,
121 default_load: true,
122 description: "Finite sets",
123 },
124 StdModuleEntry {
125 qualified_name: "Std.Vec",
126 phase: BuildPhase::Collections,
127 default_load: false,
128 description: "Length-indexed vectors",
129 },
130 StdModuleEntry {
131 qualified_name: "Std.Option",
132 phase: BuildPhase::Collections,
133 default_load: true,
134 description: "Optional value type",
135 },
136 StdModuleEntry {
137 qualified_name: "Std.Result",
138 phase: BuildPhase::Collections,
139 default_load: true,
140 description: "Result type",
141 },
142 StdModuleEntry {
143 qualified_name: "Std.Prod",
144 phase: BuildPhase::Collections,
145 default_load: true,
146 description: "Product type",
147 },
148 StdModuleEntry {
149 qualified_name: "Std.Sum",
150 phase: BuildPhase::Collections,
151 default_load: true,
152 description: "Sum type",
153 },
154 StdModuleEntry {
155 qualified_name: "Std.Sigma",
156 phase: BuildPhase::Collections,
157 default_load: false,
158 description: "Dependent pair type",
159 },
160 StdModuleEntry {
161 qualified_name: "Std.Eq",
162 phase: BuildPhase::TypeClasses,
163 default_load: true,
164 description: "Equality type class",
165 },
166 StdModuleEntry {
167 qualified_name: "Std.Ord",
168 phase: BuildPhase::TypeClasses,
169 default_load: true,
170 description: "Total ordering type class",
171 },
172 StdModuleEntry {
173 qualified_name: "Std.Show",
174 phase: BuildPhase::TypeClasses,
175 default_load: false,
176 description: "String representation",
177 },
178 StdModuleEntry {
179 qualified_name: "Std.Functor",
180 phase: BuildPhase::TypeClasses,
181 default_load: true,
182 description: "Functor type class",
183 },
184 StdModuleEntry {
185 qualified_name: "Std.Monad",
186 phase: BuildPhase::TypeClasses,
187 default_load: false,
188 description: "Monad type class",
189 },
190 StdModuleEntry {
191 qualified_name: "Std.Decidable",
192 phase: BuildPhase::TypeClasses,
193 default_load: true,
194 description: "Decidable propositions",
195 },
196 StdModuleEntry {
197 qualified_name: "Std.Algebra",
198 phase: BuildPhase::TypeClasses,
199 default_load: false,
200 description: "Algebraic structures",
201 },
202 StdModuleEntry {
203 qualified_name: "Std.Logic",
204 phase: BuildPhase::Theorems,
205 default_load: true,
206 description: "Classical logic",
207 },
208 StdModuleEntry {
209 qualified_name: "Std.Prop",
210 phase: BuildPhase::Theorems,
211 default_load: true,
212 description: "Propositional theorems",
213 },
214 StdModuleEntry {
215 qualified_name: "Std.Order",
216 phase: BuildPhase::Theorems,
217 default_load: false,
218 description: "Order theorems",
219 },
220 StdModuleEntry {
221 qualified_name: "Std.TacticLemmas",
222 phase: BuildPhase::Automation,
223 default_load: true,
224 description: "Tactic lemmas",
225 },
226 StdModuleEntry {
227 qualified_name: "Std.WellFounded",
228 phase: BuildPhase::Automation,
229 default_load: false,
230 description: "Well-founded relations",
231 },
232];
233
234#[allow(dead_code)]
236pub fn modules_for_phase(phase: BuildPhase) -> Vec<&'static StdModuleEntry> {
237 STD_MODULE_REGISTRY
238 .iter()
239 .filter(|e| e.phase == phase)
240 .collect()
241}
242
243#[allow(dead_code)]
245pub fn default_modules() -> Vec<&'static StdModuleEntry> {
246 STD_MODULE_REGISTRY
247 .iter()
248 .filter(|e| e.default_load)
249 .collect()
250}
251
252#[allow(dead_code)]
254pub fn all_modules() -> &'static [StdModuleEntry] {
255 STD_MODULE_REGISTRY
256}
257
258#[allow(dead_code)]
260pub fn count_default_modules() -> usize {
261 STD_MODULE_REGISTRY
262 .iter()
263 .filter(|e| e.default_load)
264 .count()
265}
266
267#[allow(dead_code)]
269pub fn count_total_modules() -> usize {
270 STD_MODULE_REGISTRY.len()
271}
272
273#[allow(dead_code)]
275pub fn find_module(qualified_name: &str) -> Option<&'static StdModuleEntry> {
276 STD_MODULE_REGISTRY
277 .iter()
278 .find(|e| e.qualified_name == qualified_name)
279}
280
281#[allow(dead_code)]
283#[derive(Debug, Clone, Copy)]
284pub struct ModuleDep {
285 pub dependent: &'static str,
287 pub dependency: &'static str,
289}
290
291#[allow(dead_code)]
293pub static CORE_DEPS: &[ModuleDep] = &[
294 ModuleDep {
295 dependent: "Std.List",
296 dependency: "Std.Nat",
297 },
298 ModuleDep {
299 dependent: "Std.Array",
300 dependency: "Std.Nat",
301 },
302 ModuleDep {
303 dependent: "Std.Fin",
304 dependency: "Std.Nat",
305 },
306 ModuleDep {
307 dependent: "Std.Vec",
308 dependency: "Std.List",
309 },
310 ModuleDep {
311 dependent: "Std.Set",
312 dependency: "Std.List",
313 },
314 ModuleDep {
315 dependent: "Std.Ord",
316 dependency: "Std.Eq",
317 },
318 ModuleDep {
319 dependent: "Std.Functor",
320 dependency: "Std.Eq",
321 },
322 ModuleDep {
323 dependent: "Std.Monad",
324 dependency: "Std.Functor",
325 },
326 ModuleDep {
327 dependent: "Std.Algebra",
328 dependency: "Std.Eq",
329 },
330 ModuleDep {
331 dependent: "Std.Logic",
332 dependency: "Std.Bool",
333 },
334 ModuleDep {
335 dependent: "Std.Prop",
336 dependency: "Std.Logic",
337 },
338 ModuleDep {
339 dependent: "Std.Order",
340 dependency: "Std.Ord",
341 },
342 ModuleDep {
343 dependent: "Std.TacticLemmas",
344 dependency: "Std.Nat",
345 },
346 ModuleDep {
347 dependent: "Std.WellFounded",
348 dependency: "Std.Nat",
349 },
350];
351
352#[allow(dead_code)]
354pub fn direct_deps(module: &str) -> Vec<&'static str> {
355 CORE_DEPS
356 .iter()
357 .filter(|d| d.dependent == module)
358 .map(|d| d.dependency)
359 .collect()
360}
361
362#[allow(dead_code)]
364pub fn dependents_of(module: &str) -> Vec<&'static str> {
365 CORE_DEPS
366 .iter()
367 .filter(|d| d.dependency == module)
368 .map(|d| d.dependent)
369 .collect()
370}
371
372#[allow(dead_code)]
376pub fn topological_sort_modules() -> Option<Vec<&'static str>> {
377 let mut in_degree: std::collections::HashMap<&'static str, usize> =
378 std::collections::HashMap::new();
379 let mut adjacency: std::collections::HashMap<&'static str, Vec<&'static str>> =
380 std::collections::HashMap::new();
381
382 for entry in STD_MODULE_REGISTRY {
384 in_degree.entry(entry.qualified_name).or_insert(0);
385 adjacency.entry(entry.qualified_name).or_default();
386 }
387
388 for dep in CORE_DEPS {
390 *in_degree.entry(dep.dependent).or_insert(0) += 1;
391 adjacency
392 .entry(dep.dependency)
393 .or_default()
394 .push(dep.dependent);
395 }
396
397 let mut queue: std::collections::VecDeque<&'static str> = in_degree
399 .iter()
400 .filter(|(_, &d)| d == 0)
401 .map(|(&n, _)| n)
402 .collect();
403
404 let mut sorted = Vec::new();
405 while let Some(node) = queue.pop_front() {
406 sorted.push(node);
407 if let Some(neighbors) = adjacency.get(node) {
408 for &neighbor in neighbors {
409 let deg = in_degree.entry(neighbor).or_insert(0);
410 *deg -= 1;
411 if *deg == 0 {
412 queue.push_back(neighbor);
413 }
414 }
415 }
416 }
417
418 if sorted.len() == in_degree.len() {
419 Some(sorted)
420 } else {
421 None }
423}
424
425#[allow(dead_code)]
427pub const STD_VERSION: &str = "0.1.1";
428
429#[allow(dead_code)]
431#[derive(Debug, Clone, Default)]
432pub struct StdFeatures {
433 pub classical: bool,
435 pub propext: bool,
437 pub funext: bool,
439 pub quotient: bool,
441 pub category_theory: bool,
443 pub topology: bool,
445 pub reals: bool,
447}
448
449impl StdFeatures {
450 #[allow(dead_code)]
452 pub fn default_features() -> Self {
453 Self {
454 classical: true,
455 propext: true,
456 funext: true,
457 quotient: false,
458 category_theory: false,
459 topology: false,
460 reals: false,
461 }
462 }
463
464 #[allow(dead_code)]
466 pub fn full() -> Self {
467 Self {
468 classical: true,
469 propext: true,
470 funext: true,
471 quotient: true,
472 category_theory: true,
473 topology: true,
474 reals: true,
475 }
476 }
477
478 #[allow(dead_code)]
480 pub fn count_enabled(&self) -> usize {
481 [
482 self.classical,
483 self.propext,
484 self.funext,
485 self.quotient,
486 self.category_theory,
487 self.topology,
488 self.reals,
489 ]
490 .iter()
491 .filter(|&&v| v)
492 .count()
493 }
494}
495
496#[allow(dead_code)]
498#[derive(Debug, Clone, Default)]
499pub struct StdLibStats {
500 pub total_modules: usize,
502 pub default_modules: usize,
504 pub per_phase: [usize; 5],
506}
507
508impl StdLibStats {
509 #[allow(dead_code)]
511 pub fn compute() -> Self {
512 let total = count_total_modules();
513 let defaults = count_default_modules();
514 let phases = [
515 modules_for_phase(BuildPhase::Primitives).len(),
516 modules_for_phase(BuildPhase::Collections).len(),
517 modules_for_phase(BuildPhase::TypeClasses).len(),
518 modules_for_phase(BuildPhase::Theorems).len(),
519 modules_for_phase(BuildPhase::Automation).len(),
520 ];
521 Self {
522 total_modules: total,
523 default_modules: defaults,
524 per_phase: phases,
525 }
526 }
527
528 #[allow(dead_code)]
530 pub fn all_phases_populated(&self) -> bool {
531 self.per_phase.iter().all(|&n| n > 0)
532 }
533
534 #[allow(dead_code)]
536 pub fn phase_total(&self) -> usize {
537 self.per_phase.iter().sum()
538 }
539}
540
541#[allow(dead_code)]
544#[derive(Debug, Clone)]
545pub struct StdEntry {
546 pub name: &'static str,
548 pub module: &'static str,
550 pub description: &'static str,
552 pub is_theorem: bool,
554}
555
556#[allow(dead_code)]
558pub const STD_KNOWN_ENTRIES: &[StdEntry] = &[
559 StdEntry {
560 name: "Nat.zero_add",
561 module: "Std.Nat",
562 description: "0 + n = n",
563 is_theorem: true,
564 },
565 StdEntry {
566 name: "Nat.add_zero",
567 module: "Std.Nat",
568 description: "n + 0 = n",
569 is_theorem: true,
570 },
571 StdEntry {
572 name: "Nat.add_comm",
573 module: "Std.Nat",
574 description: "Commutativity of natural number addition",
575 is_theorem: true,
576 },
577 StdEntry {
578 name: "Nat.add_assoc",
579 module: "Std.Nat",
580 description: "Associativity of natural number addition",
581 is_theorem: true,
582 },
583 StdEntry {
584 name: "Nat.mul_comm",
585 module: "Std.Nat",
586 description: "Commutativity of natural number multiplication",
587 is_theorem: true,
588 },
589 StdEntry {
590 name: "List.length_nil",
591 module: "Std.List",
592 description: "Length of the empty list is 0",
593 is_theorem: true,
594 },
595 StdEntry {
596 name: "List.length_cons",
597 module: "Std.List",
598 description: "Length of cons is 1 + length of tail",
599 is_theorem: true,
600 },
601 StdEntry {
602 name: "Bool.not_not",
603 module: "Std.Bool",
604 description: "Double negation elimination for Bool",
605 is_theorem: true,
606 },
607 StdEntry {
608 name: "Bool.and_comm",
609 module: "Std.Bool",
610 description: "Commutativity of boolean and",
611 is_theorem: true,
612 },
613 StdEntry {
614 name: "Option.some_ne_none",
615 module: "Std.Option",
616 description: "Some x is never None",
617 is_theorem: true,
618 },
619];
620
621#[allow(dead_code)]
623pub fn lookup_std_entry(name: &str) -> Option<&'static StdEntry> {
624 STD_KNOWN_ENTRIES.iter().find(|e| e.name == name)
625}
626
627#[allow(dead_code)]
629pub fn entries_in_module(module: &str) -> Vec<&'static StdEntry> {
630 STD_KNOWN_ENTRIES
631 .iter()
632 .filter(|e| e.module == module)
633 .collect()
634}
635
636#[allow(dead_code)]
638pub fn all_theorems() -> Vec<&'static StdEntry> {
639 STD_KNOWN_ENTRIES.iter().filter(|e| e.is_theorem).collect()
640}
641
642#[allow(dead_code)]
644#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
645pub enum StdCategory {
646 Arithmetic,
648 Logic,
650 Data,
652 TypeClass,
654 IO,
656 String,
658 Tactic,
660 Universe,
662}
663
664impl StdCategory {
665 #[allow(dead_code)]
667 pub fn label(self) -> &'static str {
668 match self {
669 Self::Arithmetic => "Arithmetic",
670 Self::Logic => "Logic",
671 Self::Data => "Data",
672 Self::TypeClass => "TypeClass",
673 Self::IO => "IO",
674 Self::String => "String",
675 Self::Tactic => "Tactic",
676 Self::Universe => "Universe",
677 }
678 }
679}
680
681#[allow(dead_code)]
683pub fn module_category(module: &str) -> StdCategory {
684 if module.contains("Nat") || module.contains("Int") {
685 StdCategory::Arithmetic
686 } else if module.contains("Logic") || module.contains("Prop") {
687 StdCategory::Logic
688 } else if module.contains("List") || module.contains("Option") || module.contains("Array") {
689 StdCategory::Data
690 } else if module.contains("Functor") || module.contains("Monad") || module.contains("Eq") {
691 StdCategory::TypeClass
692 } else if module.contains("IO") {
693 StdCategory::IO
694 } else if module.contains("String") || module.contains("Char") {
695 StdCategory::String
696 } else if module.contains("Tactic") {
697 StdCategory::Tactic
698 } else {
699 StdCategory::Universe
700 }
701}
702
703#[allow(dead_code)]
705pub struct StdVersion {
706 pub major: u32,
708 pub minor: u32,
710 pub patch: u32,
712 pub pre: &'static str,
714}
715
716impl StdVersion {
717 #[allow(dead_code)]
719 pub const CURRENT: StdVersion = StdVersion {
720 major: 0,
721 minor: 1,
722 patch: 0,
723 pre: "alpha",
724 };
725
726 #[allow(dead_code)]
728 pub fn format_version(&self) -> String {
729 self.to_string()
730 }
731
732 #[allow(dead_code)]
734 pub fn is_stable(&self) -> bool {
735 self.pre.is_empty()
736 }
737}
738
739impl std::fmt::Display for StdVersion {
740 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
741 if self.pre.is_empty() {
742 write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
743 } else {
744 write!(
745 f,
746 "{}.{}.{}-{}",
747 self.major, self.minor, self.patch, self.pre
748 )
749 }
750 }
751}
752
753#[cfg(test)]
758mod tests {
759 use super::*;
760
761 #[test]
762 fn test_module_registry_not_empty() {
763 assert!(!STD_MODULE_REGISTRY.is_empty());
764 assert!(count_total_modules() > 10);
765 }
766
767 #[test]
768 fn test_default_modules_subset() {
769 let defaults = default_modules();
770 assert!(!defaults.is_empty());
771 assert!(defaults.len() <= count_total_modules());
772 }
773
774 #[test]
775 fn test_modules_for_phase() {
776 let primitives = modules_for_phase(BuildPhase::Primitives);
777 assert!(!primitives.is_empty());
778 for m in &primitives {
779 assert_eq!(m.phase, BuildPhase::Primitives);
780 }
781 }
782
783 #[test]
784 fn test_find_module_existing() {
785 let m = find_module("Std.Nat");
786 assert!(m.is_some());
787 assert_eq!(m.expect("m should be valid").phase, BuildPhase::Primitives);
788 }
789
790 #[test]
791 fn test_find_module_nonexistent() {
792 assert!(find_module("Std.DoesNotExist").is_none());
793 }
794
795 #[test]
796 fn test_direct_deps() {
797 let deps = direct_deps("Std.List");
798 assert!(deps.contains(&"Std.Nat"));
799 }
800
801 #[test]
802 fn test_dependents_of() {
803 let deps = dependents_of("Std.Nat");
804 assert!(deps.contains(&"Std.List"));
805 }
806
807 #[test]
808 fn test_build_phase_order() {
809 let phases = BuildPhase::all_in_order();
810 assert_eq!(phases.len(), 5);
811 assert_eq!(phases[0], BuildPhase::Primitives);
812 assert_eq!(phases[4], BuildPhase::Automation);
813 }
814
815 #[test]
816 fn test_std_features_default() {
817 let f = StdFeatures::default_features();
818 assert!(f.classical);
819 assert!(f.propext);
820 assert!(!f.topology);
821 }
822
823 #[test]
824 fn test_std_features_full() {
825 let f = StdFeatures::full();
826 assert!(f.classical && f.topology && f.reals && f.quotient);
827 assert_eq!(f.count_enabled(), 7);
828 }
829
830 #[test]
831 fn test_build_phase_names() {
832 assert_eq!(BuildPhase::Primitives.name(), "primitives");
833 assert_eq!(BuildPhase::Automation.name(), "automation");
834 }
835
836 #[test]
837 fn test_count_default_modules() {
838 let count = count_default_modules();
839 assert!(count > 0);
840 assert!(count <= count_total_modules());
841 }
842
843 #[test]
844 fn test_std_lib_stats() {
845 let stats = StdLibStats::compute();
846 assert!(stats.total_modules > 0);
847 assert!(stats.all_phases_populated());
848 }
849
850 #[test]
851 fn test_all_modules_count() {
852 assert_eq!(all_modules().len(), STD_MODULE_REGISTRY.len());
853 }
854
855 #[test]
856 fn test_std_version_nonempty() {
857 assert!(!STD_VERSION.is_empty());
858 }
859
860 #[test]
861 fn test_std_lib_stats_compute() {
862 let s = StdLibStats::compute();
863 assert_eq!(s.total_modules, count_total_modules());
864 assert!(s.all_phases_populated());
865 assert!(s.phase_total() > 0);
866 }
867
868 #[test]
869 fn test_std_lib_stats_phase_total() {
870 let s = StdLibStats::compute();
871 assert_eq!(s.phase_total(), s.total_modules);
872 }
873
874 #[test]
875 fn test_module_descriptions_not_empty() {
876 for m in STD_MODULE_REGISTRY {
877 assert!(
878 !m.description.is_empty(),
879 "Module {} has empty description",
880 m.qualified_name
881 );
882 }
883 }
884
885 #[test]
886 fn test_topological_sort_acyclic() {
887 let result = topological_sort_modules();
888 assert!(result.is_some(), "Dependency graph should have no cycles");
889 let sorted = result.expect("result should be valid");
890 assert!(!sorted.is_empty());
891 }
892
893 #[test]
894 fn test_nat_before_list() {
895 let sorted = topological_sort_modules().expect("operation should succeed");
896 let nat_pos = sorted.iter().position(|&s| s == "Std.Nat");
897 let list_pos = sorted.iter().position(|&s| s == "Std.List");
898 if let (Some(np), Some(lp)) = (nat_pos, list_pos) {
899 assert!(np < lp, "Nat must appear before List");
900 }
901 }
902
903 #[test]
904 fn test_nat_before_array() {
905 let sorted = topological_sort_modules().expect("operation should succeed");
906 let nat_pos = sorted.iter().position(|&s| s == "Std.Nat");
907 let arr_pos = sorted.iter().position(|&s| s == "Std.Array");
908 if let (Some(np), Some(ap)) = (nat_pos, arr_pos) {
909 assert!(np < ap);
910 }
911 }
912
913 #[test]
914 fn test_all_modules_in_sorted() {
915 let sorted = topological_sort_modules().expect("operation should succeed");
916 for entry in STD_MODULE_REGISTRY {
917 assert!(
918 sorted.contains(&entry.qualified_name),
919 "Module {} missing from topological sort",
920 entry.qualified_name
921 );
922 }
923 }
924
925 #[test]
926 fn test_std_features_default_count() {
927 let f = StdFeatures::default_features();
928 assert_eq!(f.count_enabled(), 3);
930 }
931
932 #[test]
933 fn test_module_dep_dependent_in_registry() {
934 let names: Vec<_> = STD_MODULE_REGISTRY
935 .iter()
936 .map(|e| e.qualified_name)
937 .collect();
938 for dep in CORE_DEPS {
939 assert!(
940 names.contains(&dep.dependent),
941 "Dependent {} not in registry",
942 dep.dependent
943 );
944 }
945 }
946
947 #[test]
948 fn test_module_dep_dependency_in_registry() {
949 let names: Vec<_> = STD_MODULE_REGISTRY
950 .iter()
951 .map(|e| e.qualified_name)
952 .collect();
953 for dep in CORE_DEPS {
954 assert!(
955 names.contains(&dep.dependency),
956 "Dependency {} not in registry",
957 dep.dependency
958 );
959 }
960 }
961
962 #[test]
963 fn test_std_lib_stats_phase_count() {
964 let s = StdLibStats::compute();
965 assert_eq!(s.per_phase.len(), 5);
966 }
967
968 #[test]
969 fn test_direct_deps_non_empty() {
970 let deps = direct_deps("Std.Monad");
971 assert!(!deps.is_empty());
972 }
973
974 #[test]
975 fn test_lookup_std_entry_found() {
976 let e = lookup_std_entry("Nat.add_comm");
977 assert!(e.is_some());
978 assert!(e.expect("e should be valid").is_theorem);
979 }
980
981 #[test]
982 fn test_lookup_std_entry_not_found() {
983 assert!(lookup_std_entry("Nonexistent.theorem").is_none());
984 }
985
986 #[test]
987 fn test_entries_in_module() {
988 let nat_entries = entries_in_module("Std.Nat");
989 assert!(!nat_entries.is_empty());
990 assert!(nat_entries.iter().all(|e| e.module == "Std.Nat"));
991 }
992
993 #[test]
994 fn test_all_theorems_nonempty() {
995 let thms = all_theorems();
996 assert!(!thms.is_empty());
997 assert!(thms.iter().all(|e| e.is_theorem));
998 }
999
1000 #[test]
1001 fn test_module_category_nat() {
1002 assert_eq!(module_category("Std.Nat"), StdCategory::Arithmetic);
1003 }
1004
1005 #[test]
1006 fn test_module_category_list() {
1007 assert_eq!(module_category("Std.List"), StdCategory::Data);
1008 }
1009
1010 #[test]
1011 fn test_module_category_io() {
1012 assert_eq!(module_category("Std.IO"), StdCategory::IO);
1013 }
1014
1015 #[test]
1016 fn test_std_version_to_string() {
1017 let v = StdVersion {
1018 major: 1,
1019 minor: 2,
1020 patch: 3,
1021 pre: "",
1022 };
1023 assert_eq!(v.to_string(), "1.2.3");
1024 }
1025
1026 #[test]
1027 fn test_std_version_prerelease_to_string() {
1028 let v = StdVersion {
1029 major: 0,
1030 minor: 1,
1031 patch: 0,
1032 pre: "alpha",
1033 };
1034 assert_eq!(v.to_string(), "0.1.0-alpha");
1035 }
1036
1037 #[test]
1038 fn test_std_version_is_stable_false() {
1039 assert!(!StdVersion::CURRENT.is_stable());
1040 }
1041
1042 #[test]
1043 fn test_std_category_label() {
1044 assert_eq!(StdCategory::Arithmetic.label(), "Arithmetic");
1045 assert_eq!(StdCategory::Logic.label(), "Logic");
1046 assert_eq!(StdCategory::Data.label(), "Data");
1047 }
1048
1049 #[test]
1050 fn test_std_known_entries_nonempty() {
1051 assert!(!STD_KNOWN_ENTRIES.is_empty());
1052 }
1053
1054 #[test]
1055 fn test_all_entries_have_module() {
1056 for e in STD_KNOWN_ENTRIES {
1057 assert!(!e.module.is_empty(), "Entry {} has empty module", e.name);
1058 }
1059 }
1060}