1use crate::{Expr, Level, Name};
6use std::collections::HashSet;
7
8use super::types::{
9 ConfigNode, DecisionNode, Either2, Fixture, FlatSubstitution, FocusStack, LabelSet, MinHeap,
10 NonEmptyVec, PathBuf, PrefixCounter, ProofAnalysis, ProofAnalyzer, ProofCertificate,
11 ProofComplexity, ProofNormalizer, ProofObligation, ProofSkeleton, ProofState, ProofTerm,
12 RewriteRule, RewriteRuleSet, SimpleDag, SlidingSum, SmallMap, SparseVec, StackCalc,
13 StatSummary, Stopwatch, StringPool, TokenBucket, TransformStat, TransitiveClosure,
14 VersionedRecord, WindowIterator, WriteOnce,
15};
16
17pub(crate) const CLASSICAL_AXIOMS: &[&str] = &[
19 "Classical.choice",
20 "Classical.em",
21 "Classical.byContradiction",
22 "Quotient.sound",
23 "propext",
24];
25pub fn collect_axiom_deps(expr: &Expr) -> HashSet<Name> {
27 let mut result = HashSet::new();
28 collect_constants_impl(expr, &mut result);
29 result
30}
31pub(super) fn collect_constants_impl(expr: &Expr, result: &mut HashSet<Name>) {
33 match expr {
34 Expr::Const(name, _) => {
35 result.insert(name.clone());
36 }
37 Expr::App(f, a) => {
38 collect_constants_impl(f, result);
39 collect_constants_impl(a, result);
40 }
41 Expr::Lam(_, _, ty, body) => {
42 collect_constants_impl(ty, result);
43 collect_constants_impl(body, result);
44 }
45 Expr::Pi(_, _, ty, body) => {
46 collect_constants_impl(ty, result);
47 collect_constants_impl(body, result);
48 }
49 Expr::Let(_, ty, val, body) => {
50 collect_constants_impl(ty, result);
51 collect_constants_impl(val, result);
52 collect_constants_impl(body, result);
53 }
54 Expr::Proj(_, _, e) => {
55 collect_constants_impl(e, result);
56 }
57 _ => {}
58 }
59}
60pub fn is_proof_irrelevant(ty: &Expr, _t1: &Expr, _t2: &Expr) -> bool {
65 ProofTerm::could_be_prop(ty)
66}
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use crate::{Literal, Name};
71 #[test]
72 fn test_is_proof() {
73 let term = Expr::Lit(Literal::Nat(42));
74 let prop = Expr::Sort(Level::zero());
75 assert!(ProofTerm::is_proof(&term, &prop));
76 }
77 #[test]
78 fn test_is_proof_non_prop() {
79 let term = Expr::Lit(Literal::Nat(42));
80 let non_prop = Expr::Sort(Level::succ(Level::zero()));
81 assert!(!ProofTerm::is_proof(&term, &non_prop));
82 }
83 #[test]
84 fn test_size_simple() {
85 let term = Expr::Lit(Literal::Nat(42));
86 assert_eq!(ProofTerm::size(&term), 1);
87 }
88 #[test]
89 fn test_size_app() {
90 let f = Expr::Const(Name::str("f"), vec![]);
91 let a = Expr::Lit(Literal::Nat(1));
92 let app = Expr::App(Box::new(f), Box::new(a));
93 assert_eq!(ProofTerm::size(&app), 3);
94 }
95 #[test]
96 fn test_depth() {
97 let f = Expr::Const(Name::str("f"), vec![]);
98 let a = Expr::Lit(Literal::Nat(1));
99 let app = Expr::App(Box::new(f), Box::new(a));
100 assert_eq!(ProofTerm::depth(&app), 1);
101 }
102 #[test]
103 fn test_is_constructive() {
104 let term = Expr::BVar(0);
105 assert!(ProofTerm::is_constructive(&term));
106 }
107 #[test]
108 fn test_is_non_constructive() {
109 let term = Expr::Const(Name::str("Classical.choice"), vec![]);
110 assert!(!ProofTerm::is_constructive(&term));
111 }
112 #[test]
113 fn test_collect_constants() {
114 let f = Expr::Const(Name::str("f"), vec![]);
115 let g = Expr::Const(Name::str("g"), vec![]);
116 let app = Expr::App(Box::new(f), Box::new(g));
117 let consts = ProofTerm::collect_constants(&app);
118 assert!(consts.contains(&Name::str("f")));
119 assert!(consts.contains(&Name::str("g")));
120 }
121 #[test]
122 fn test_could_be_prop() {
123 assert!(ProofTerm::could_be_prop(&Expr::Sort(Level::zero())));
124 assert!(!ProofTerm::could_be_prop(&Expr::Sort(Level::succ(
125 Level::zero()
126 ))));
127 }
128 #[test]
129 fn test_is_sort_zero() {
130 assert!(ProofTerm::is_sort_zero(&Expr::Sort(Level::zero())));
131 assert!(!ProofTerm::is_sort_zero(&Expr::Sort(Level::succ(
132 Level::zero()
133 ))));
134 }
135 #[test]
136 fn test_same_proposition_structure() {
137 let p1 = Expr::Const(Name::str("True"), vec![]);
138 let p2 = Expr::Const(Name::str("True"), vec![]);
139 assert!(ProofTerm::same_proposition_structure(&p1, &p2));
140 let p3 = Expr::Const(Name::str("False"), vec![]);
141 assert!(!ProofTerm::same_proposition_structure(&p1, &p3));
142 }
143 #[test]
144 fn test_proof_irrelevance() {
145 let prop_ty = Expr::Sort(Level::zero());
146 let proof1 = Expr::Const(Name::str("p1"), vec![]);
147 let proof2 = Expr::Const(Name::str("p2"), vec![]);
148 assert!(is_proof_irrelevant(&prop_ty, &proof1, &proof2));
149 let type_ty = Expr::Sort(Level::succ(Level::zero()));
150 assert!(!is_proof_irrelevant(&type_ty, &proof1, &proof2));
151 }
152}
153#[allow(dead_code)]
155pub fn classify_proof(term: &Expr) -> ProofComplexity {
156 match term {
157 Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Sort(_) | Expr::Lit(_) => {
158 ProofComplexity::Atomic
159 }
160 Expr::Lam(_, _, _, _) => ProofComplexity::Abstraction,
161 Expr::App(_, _) => ProofComplexity::Application,
162 Expr::Let(_, _, _, _) => ProofComplexity::LetBinding,
163 Expr::Proj(_, _, _) => ProofComplexity::Projection,
164 Expr::Pi(_, _, _, _) => ProofComplexity::Composite,
165 }
166}
167#[allow(dead_code)]
171pub fn axiom_dependencies(term: &Expr) -> HashSet<Name> {
172 let mut deps = HashSet::new();
173 axiom_deps_impl(term, &mut deps);
174 deps
175}
176pub(super) fn axiom_deps_impl(term: &Expr, deps: &mut HashSet<Name>) {
177 match term {
178 Expr::Const(name, _) => {
179 if CLASSICAL_AXIOMS.contains(&name.to_string().as_str()) {
180 deps.insert(name.clone());
181 }
182 }
183 Expr::App(f, a) => {
184 axiom_deps_impl(f, deps);
185 axiom_deps_impl(a, deps);
186 }
187 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
188 axiom_deps_impl(ty, deps);
189 axiom_deps_impl(body, deps);
190 }
191 Expr::Let(_, ty, val, body) => {
192 axiom_deps_impl(ty, deps);
193 axiom_deps_impl(val, deps);
194 axiom_deps_impl(body, deps);
195 }
196 Expr::Proj(_, _, e) => axiom_deps_impl(e, deps),
197 _ => {}
198 }
199}
200#[allow(dead_code)]
202pub fn count_const_occurrences(term: &Expr, target: &Name) -> usize {
203 match term {
204 Expr::Const(name, _) => {
205 if name == target {
206 1
207 } else {
208 0
209 }
210 }
211 Expr::App(f, a) => count_const_occurrences(f, target) + count_const_occurrences(a, target),
212 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
213 count_const_occurrences(ty, target) + count_const_occurrences(body, target)
214 }
215 Expr::Let(_, ty, val, body) => {
216 count_const_occurrences(ty, target)
217 + count_const_occurrences(val, target)
218 + count_const_occurrences(body, target)
219 }
220 Expr::Proj(_, _, e) => count_const_occurrences(e, target),
221 _ => 0,
222 }
223}
224#[allow(dead_code)]
228pub fn is_closed_term(term: &Expr) -> bool {
229 match term {
230 Expr::FVar(_) => false,
231 Expr::BVar(_) | Expr::Const(_, _) | Expr::Sort(_) | Expr::Lit(_) => true,
232 Expr::App(f, a) => is_closed_term(f) && is_closed_term(a),
233 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
234 is_closed_term(ty) && is_closed_term(body)
235 }
236 Expr::Let(_, ty, val, body) => {
237 is_closed_term(ty) && is_closed_term(val) && is_closed_term(body)
238 }
239 Expr::Proj(_, _, e) => is_closed_term(e),
240 }
241}
242#[allow(dead_code)]
245pub fn same_proof_shape(a: &Expr, b: &Expr) -> bool {
246 match (a, b) {
247 (Expr::BVar(i), Expr::BVar(j)) => i == j,
248 (Expr::FVar(_), Expr::FVar(_)) => true,
249 (Expr::Const(_, _), Expr::Const(_, _)) => true,
250 (Expr::Sort(_), Expr::Sort(_)) => true,
251 (Expr::Lit(_), Expr::Lit(_)) => true,
252 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
253 same_proof_shape(f1, f2) && same_proof_shape(a1, a2)
254 }
255 (Expr::Lam(_, _, ty1, b1), Expr::Lam(_, _, ty2, b2)) => {
256 same_proof_shape(ty1, ty2) && same_proof_shape(b1, b2)
257 }
258 (Expr::Pi(_, _, ty1, b1), Expr::Pi(_, _, ty2, b2)) => {
259 same_proof_shape(ty1, ty2) && same_proof_shape(b1, b2)
260 }
261 (Expr::Let(_, ty1, v1, b1), Expr::Let(_, ty2, v2, b2)) => {
262 same_proof_shape(ty1, ty2) && same_proof_shape(v1, v2) && same_proof_shape(b1, b2)
263 }
264 (Expr::Proj(i1, _, e1), Expr::Proj(i2, _, e2)) => i1 == i2 && same_proof_shape(e1, e2),
265 _ => false,
266 }
267}
268#[allow(dead_code)]
271pub fn proof_effort(term: &Expr) -> u64 {
272 let size = ProofTerm::size(term) as u64;
273 let depth = ProofTerm::depth(term) as u64;
274 let classical_penalty: u64 = if ProofTerm::is_constructive(term) {
275 0
276 } else {
277 100
278 };
279 size + depth * 2 + classical_penalty
280}
281#[cfg(test)]
282mod extended_proof_tests {
283 use super::*;
284 fn mk_const(name: &str) -> Expr {
285 Expr::Const(Name::str(name), vec![])
286 }
287 fn mk_prop() -> Expr {
288 Expr::Sort(Level::zero())
289 }
290 #[allow(dead_code)]
291 fn mk_type1() -> Expr {
292 Expr::Sort(Level::succ(Level::zero()))
293 }
294 #[test]
295 fn test_classify_atomic_const() {
296 let term = mk_const("True");
297 assert_eq!(classify_proof(&term), ProofComplexity::Atomic);
298 }
299 #[test]
300 fn test_classify_bvar() {
301 let term = Expr::BVar(0);
302 assert_eq!(classify_proof(&term), ProofComplexity::Atomic);
303 }
304 #[test]
305 fn test_classify_app() {
306 let f = mk_const("f");
307 let a = mk_const("a");
308 let app = Expr::App(Box::new(f), Box::new(a));
309 assert_eq!(classify_proof(&app), ProofComplexity::Application);
310 }
311 #[test]
312 fn test_proof_analysis_size() {
313 let term = Expr::App(Box::new(mk_const("f")), Box::new(mk_const("a")));
314 let analysis = ProofAnalysis::analyse(&term);
315 assert_eq!(analysis.size, 3);
316 assert_eq!(analysis.app_count, 1);
317 assert_eq!(analysis.lambda_count, 0);
318 }
319 #[test]
320 fn test_proof_obligation_discharge() {
321 let prop = mk_prop();
322 let mut obl = ProofObligation::new("main", prop);
323 assert!(!obl.is_discharged());
324 obl.discharge(mk_const("proof"));
325 assert!(obl.is_discharged());
326 }
327 #[test]
328 fn test_proof_state_remaining() {
329 let mut state = ProofState::new();
330 state.add_obligation("goal1", mk_prop());
331 state.add_obligation("goal2", mk_prop());
332 assert_eq!(state.remaining(), 2);
333 assert!(!state.is_complete());
334 state.discharge_next(mk_const("p1"));
335 assert_eq!(state.remaining(), 1);
336 state.discharge_next(mk_const("p2"));
337 assert!(state.is_complete());
338 }
339 #[test]
340 fn test_beta_reduce_simple() {
341 let body = Expr::BVar(0);
342 let lam = Expr::Lam(
343 crate::BinderInfo::Default,
344 Name::str("x"),
345 Box::new(mk_prop()),
346 Box::new(body),
347 );
348 let arg = mk_const("myarg");
349 let app = Expr::App(Box::new(lam), Box::new(arg.clone()));
350 let reduced = ProofNormalizer::beta_reduce(&app);
351 assert_eq!(reduced, arg);
352 }
353 #[test]
354 fn test_count_redexes_none() {
355 let term = mk_const("pure");
356 assert_eq!(ProofNormalizer::count_redexes(&term), 0);
357 assert!(ProofNormalizer::is_beta_normal(&term));
358 }
359 #[test]
360 fn test_count_redexes_one() {
361 let body = Expr::BVar(0);
362 let lam = Expr::Lam(
363 crate::BinderInfo::Default,
364 Name::str("x"),
365 Box::new(mk_prop()),
366 Box::new(body),
367 );
368 let app = Expr::App(Box::new(lam), Box::new(mk_const("arg")));
369 assert_eq!(ProofNormalizer::count_redexes(&app), 1);
370 assert!(!ProofNormalizer::is_beta_normal(&app));
371 }
372 #[test]
373 fn test_axiom_dependencies_classical() {
374 let term = mk_const("Classical.em");
375 let deps = axiom_dependencies(&term);
376 assert!(deps.contains(&Name::str("Classical.em")));
377 }
378 #[test]
379 fn test_axiom_dependencies_constructive() {
380 let term = mk_const("Nat.succ");
381 let deps = axiom_dependencies(&term);
382 assert!(deps.is_empty());
383 }
384 #[test]
385 fn test_count_const_occurrences() {
386 let target = Name::str("f");
387 let f1 = Expr::Const(target.clone(), vec![]);
388 let f2 = Expr::Const(target.clone(), vec![]);
389 let app = Expr::App(Box::new(f1), Box::new(f2));
390 assert_eq!(count_const_occurrences(&app, &target), 2);
391 }
392 #[test]
393 fn test_is_closed_const() {
394 let term = mk_const("True");
395 assert!(is_closed_term(&term));
396 }
397 #[test]
398 fn test_is_not_closed_fvar() {
399 let term = Expr::FVar(crate::FVarId(0));
400 assert!(!is_closed_term(&term));
401 }
402 #[test]
403 fn test_same_proof_shape_bvar() {
404 let a = Expr::BVar(2);
405 let b = Expr::BVar(2);
406 let c = Expr::BVar(3);
407 assert!(same_proof_shape(&a, &b));
408 assert!(!same_proof_shape(&a, &c));
409 }
410 #[test]
411 fn test_proof_effort_classical() {
412 let classical_term = mk_const("Classical.em");
413 let constructive_term = mk_const("Nat.succ");
414 assert!(proof_effort(&classical_term) > proof_effort(&constructive_term));
415 }
416 #[test]
417 fn test_proof_normalizer_subst_bvar_shift() {
418 let term = Expr::BVar(1);
419 let result = ProofNormalizer::subst_bvar(term, 0, &mk_const("x"));
420 assert_eq!(result, Expr::BVar(0));
421 }
422}
423#[allow(dead_code)]
425pub(crate) fn contains_classical_sorry(term: &Expr) -> bool {
426 match term {
427 Expr::Const(n, _) => {
428 let s = n.to_string();
429 s.contains("sorry") || s.contains("Lean.Elab.Tactic.sorry")
430 }
431 Expr::App(f, a) => contains_classical_sorry(f) || contains_classical_sorry(a),
432 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
433 contains_classical_sorry(ty) || contains_classical_sorry(body)
434 }
435 Expr::Let(_, ty, val, body) => {
436 contains_classical_sorry(ty)
437 || contains_classical_sorry(val)
438 || contains_classical_sorry(body)
439 }
440 _ => false,
441 }
442}
443#[cfg(test)]
444mod extra_proof_tests {
445 use super::*;
446 fn mk_const(s: &str) -> Expr {
447 Expr::Const(Name::str(s), vec![])
448 }
449 #[test]
450 fn test_proof_skeleton_no_holes() {
451 let proof = mk_const("True.intro");
452 let ty = mk_const("True");
453 let skel = ProofSkeleton::new(proof, ty);
454 assert!(skel.is_complete());
455 assert_eq!(skel.num_holes(), 0);
456 }
457 #[test]
458 fn test_proof_skeleton_with_sorry() {
459 let sorry = mk_const("sorry");
460 let ty = mk_const("Nat");
461 let skel = ProofSkeleton::new(sorry, ty);
462 assert!(!skel.is_complete());
463 assert_eq!(skel.num_holes(), 1);
464 }
465 #[test]
466 fn test_proof_skeleton_display() {
467 let proof = mk_const("True.intro");
468 let ty = mk_const("True");
469 let skel = ProofSkeleton::new(proof, ty);
470 let s = format!("{}", skel);
471 assert!(s.contains("ProofSkeleton"));
472 }
473 #[test]
474 fn test_proof_certificate_no_sorry() {
475 let prop = mk_const("True");
476 let proof = mk_const("True.intro");
477 let cert = ProofCertificate::new(prop, proof);
478 assert!(!cert.has_sorry);
479 }
480 #[test]
481 fn test_proof_certificate_trusted() {
482 let prop = mk_const("True");
483 let proof = mk_const("True.intro");
484 let cert = ProofCertificate::new(prop, proof);
485 assert!(cert.is_trusted());
486 }
487 #[test]
488 fn test_proof_analyzer_constructive() {
489 let proof = mk_const("And.intro");
490 assert!(ProofAnalyzer::is_constructive(&proof));
491 }
492 #[test]
493 fn test_proof_analyzer_classical() {
494 let proof = mk_const("Classical.em");
495 assert!(ProofAnalyzer::uses_classical(&proof));
496 assert!(!ProofAnalyzer::is_constructive(&proof));
497 }
498 #[test]
499 fn test_proof_analyzer_count_apps() {
500 let f = mk_const("f");
501 let a = mk_const("a");
502 let app = Expr::App(Box::new(f), Box::new(a));
503 assert_eq!(ProofAnalyzer::count_applications(&app), 1);
504 }
505 #[test]
506 fn test_proof_analyzer_count_apps_nested() {
507 let f = mk_const("f");
508 let a = mk_const("a");
509 let b = mk_const("b");
510 let app1 = Expr::App(Box::new(f), Box::new(a));
511 let app2 = Expr::App(Box::new(app1), Box::new(b));
512 assert_eq!(ProofAnalyzer::count_applications(&app2), 2);
513 }
514 #[test]
515 fn test_contains_classical_sorry_false() {
516 let proof = mk_const("True.intro");
517 assert!(!contains_classical_sorry(&proof));
518 }
519 #[test]
520 fn test_contains_classical_sorry_true() {
521 let sorry = mk_const("sorry");
522 assert!(contains_classical_sorry(&sorry));
523 }
524}
525#[cfg(test)]
526mod tests_padding_infra {
527 use super::*;
528 #[test]
529 fn test_stat_summary() {
530 let mut ss = StatSummary::new();
531 ss.record(10.0);
532 ss.record(20.0);
533 ss.record(30.0);
534 assert_eq!(ss.count(), 3);
535 assert!((ss.mean().expect("mean should succeed") - 20.0).abs() < 1e-9);
536 assert_eq!(ss.min().expect("min should succeed") as i64, 10);
537 assert_eq!(ss.max().expect("max should succeed") as i64, 30);
538 }
539 #[test]
540 fn test_transform_stat() {
541 let mut ts = TransformStat::new();
542 ts.record_before(100.0);
543 ts.record_after(80.0);
544 let ratio = ts.mean_ratio().expect("ratio should be present");
545 assert!((ratio - 0.8).abs() < 1e-9);
546 }
547 #[test]
548 fn test_small_map() {
549 let mut m: SmallMap<u32, &str> = SmallMap::new();
550 m.insert(3, "three");
551 m.insert(1, "one");
552 m.insert(2, "two");
553 assert_eq!(m.get(&2), Some(&"two"));
554 assert_eq!(m.len(), 3);
555 let keys = m.keys();
556 assert_eq!(*keys[0], 1);
557 assert_eq!(*keys[2], 3);
558 }
559 #[test]
560 fn test_label_set() {
561 let mut ls = LabelSet::new();
562 ls.add("foo");
563 ls.add("bar");
564 ls.add("foo");
565 assert_eq!(ls.count(), 2);
566 assert!(ls.has("bar"));
567 assert!(!ls.has("baz"));
568 }
569 #[test]
570 fn test_config_node() {
571 let mut root = ConfigNode::section("root");
572 let child = ConfigNode::leaf("key", "value");
573 root.add_child(child);
574 assert_eq!(root.num_children(), 1);
575 }
576 #[test]
577 fn test_versioned_record() {
578 let mut vr = VersionedRecord::new(0u32);
579 vr.update(1);
580 vr.update(2);
581 assert_eq!(*vr.current(), 2);
582 assert_eq!(vr.version(), 2);
583 assert!(vr.has_history());
584 assert_eq!(*vr.at_version(0).expect("value should be present"), 0);
585 }
586 #[test]
587 fn test_simple_dag() {
588 let mut dag = SimpleDag::new(4);
589 dag.add_edge(0, 1);
590 dag.add_edge(1, 2);
591 dag.add_edge(2, 3);
592 assert!(dag.can_reach(0, 3));
593 assert!(!dag.can_reach(3, 0));
594 let order = dag.topological_sort().expect("order should be present");
595 assert_eq!(order, vec![0, 1, 2, 3]);
596 }
597 #[test]
598 fn test_focus_stack() {
599 let mut fs: FocusStack<&str> = FocusStack::new();
600 fs.focus("a");
601 fs.focus("b");
602 assert_eq!(fs.current(), Some(&"b"));
603 assert_eq!(fs.depth(), 2);
604 fs.blur();
605 assert_eq!(fs.current(), Some(&"a"));
606 }
607}
608#[cfg(test)]
609mod tests_extra_iterators {
610 use super::*;
611 #[test]
612 fn test_window_iterator() {
613 let data = vec![1u32, 2, 3, 4, 5];
614 let windows: Vec<_> = WindowIterator::new(&data, 3).collect();
615 assert_eq!(windows.len(), 3);
616 assert_eq!(windows[0], &[1, 2, 3]);
617 assert_eq!(windows[2], &[3, 4, 5]);
618 }
619 #[test]
620 fn test_non_empty_vec() {
621 let mut nev = NonEmptyVec::singleton(10u32);
622 nev.push(20);
623 nev.push(30);
624 assert_eq!(nev.len(), 3);
625 assert_eq!(*nev.first(), 10);
626 assert_eq!(*nev.last(), 30);
627 }
628}
629#[cfg(test)]
630mod tests_padding2 {
631 use super::*;
632 #[test]
633 fn test_sliding_sum() {
634 let mut ss = SlidingSum::new(3);
635 ss.push(1.0);
636 ss.push(2.0);
637 ss.push(3.0);
638 assert!((ss.sum() - 6.0).abs() < 1e-9);
639 ss.push(4.0);
640 assert!((ss.sum() - 9.0).abs() < 1e-9);
641 assert_eq!(ss.count(), 3);
642 }
643 #[test]
644 fn test_path_buf() {
645 let mut pb = PathBuf::new();
646 pb.push("src");
647 pb.push("main");
648 assert_eq!(pb.as_str(), "src/main");
649 assert_eq!(pb.depth(), 2);
650 pb.pop();
651 assert_eq!(pb.as_str(), "src");
652 }
653 #[test]
654 fn test_string_pool() {
655 let mut pool = StringPool::new();
656 let s = pool.take();
657 assert!(s.is_empty());
658 pool.give("hello".to_string());
659 let s2 = pool.take();
660 assert!(s2.is_empty());
661 assert_eq!(pool.free_count(), 0);
662 }
663 #[test]
664 fn test_transitive_closure() {
665 let mut tc = TransitiveClosure::new(4);
666 tc.add_edge(0, 1);
667 tc.add_edge(1, 2);
668 tc.add_edge(2, 3);
669 assert!(tc.can_reach(0, 3));
670 assert!(!tc.can_reach(3, 0));
671 let r = tc.reachable_from(0);
672 assert_eq!(r.len(), 4);
673 }
674 #[test]
675 fn test_token_bucket() {
676 let mut tb = TokenBucket::new(100, 10);
677 assert_eq!(tb.available(), 100);
678 assert!(tb.try_consume(50));
679 assert_eq!(tb.available(), 50);
680 assert!(!tb.try_consume(60));
681 assert_eq!(tb.capacity(), 100);
682 }
683 #[test]
684 fn test_rewrite_rule_set() {
685 let mut rrs = RewriteRuleSet::new();
686 rrs.add(RewriteRule::unconditional(
687 "beta",
688 "App(Lam(x, b), v)",
689 "b[x:=v]",
690 ));
691 rrs.add(RewriteRule::conditional("comm", "a + b", "b + a"));
692 assert_eq!(rrs.len(), 2);
693 assert_eq!(rrs.unconditional_rules().len(), 1);
694 assert_eq!(rrs.conditional_rules().len(), 1);
695 assert!(rrs.get("beta").is_some());
696 let disp = rrs
697 .get("beta")
698 .expect("element at \'beta\' should exist")
699 .display();
700 assert!(disp.contains("→"));
701 }
702}
703#[cfg(test)]
704mod tests_padding3 {
705 use super::*;
706 #[test]
707 fn test_decision_node() {
708 let tree = DecisionNode::Branch {
709 key: "x".into(),
710 val: "1".into(),
711 yes_branch: Box::new(DecisionNode::Leaf("yes".into())),
712 no_branch: Box::new(DecisionNode::Leaf("no".into())),
713 };
714 let mut ctx = std::collections::HashMap::new();
715 ctx.insert("x".into(), "1".into());
716 assert_eq!(tree.evaluate(&ctx), "yes");
717 ctx.insert("x".into(), "2".into());
718 assert_eq!(tree.evaluate(&ctx), "no");
719 assert_eq!(tree.depth(), 1);
720 }
721 #[test]
722 fn test_flat_substitution() {
723 let mut sub = FlatSubstitution::new();
724 sub.add("foo", "bar");
725 sub.add("baz", "qux");
726 assert_eq!(sub.apply("foo and baz"), "bar and qux");
727 assert_eq!(sub.len(), 2);
728 }
729 #[test]
730 fn test_stopwatch() {
731 let mut sw = Stopwatch::start();
732 sw.split();
733 sw.split();
734 assert_eq!(sw.num_splits(), 2);
735 assert!(sw.elapsed_ms() >= 0.0);
736 for &s in sw.splits() {
737 assert!(s >= 0.0);
738 }
739 }
740 #[test]
741 fn test_either2() {
742 let e: Either2<i32, &str> = Either2::First(42);
743 assert!(e.is_first());
744 let mapped = e.map_first(|x| x * 2);
745 assert_eq!(mapped.first(), Some(84));
746 let e2: Either2<i32, &str> = Either2::Second("hello");
747 assert!(e2.is_second());
748 assert_eq!(e2.second(), Some("hello"));
749 }
750 #[test]
751 fn test_write_once() {
752 let wo: WriteOnce<u32> = WriteOnce::new();
753 assert!(!wo.is_written());
754 assert!(wo.write(42));
755 assert!(!wo.write(99));
756 assert_eq!(wo.read(), Some(42));
757 }
758 #[test]
759 fn test_sparse_vec() {
760 let mut sv: SparseVec<i32> = SparseVec::new(100);
761 sv.set(5, 10);
762 sv.set(50, 20);
763 assert_eq!(*sv.get(5), 10);
764 assert_eq!(*sv.get(50), 20);
765 assert_eq!(*sv.get(0), 0);
766 assert_eq!(sv.nnz(), 2);
767 sv.set(5, 0);
768 assert_eq!(sv.nnz(), 1);
769 }
770 #[test]
771 fn test_stack_calc() {
772 let mut calc = StackCalc::new();
773 calc.push(3);
774 calc.push(4);
775 calc.add();
776 assert_eq!(calc.peek(), Some(7));
777 calc.push(2);
778 calc.mul();
779 assert_eq!(calc.peek(), Some(14));
780 }
781}
782#[cfg(test)]
783mod tests_final_padding {
784 use super::*;
785 #[test]
786 fn test_min_heap() {
787 let mut h = MinHeap::new();
788 h.push(5u32);
789 h.push(1u32);
790 h.push(3u32);
791 assert_eq!(h.peek(), Some(&1));
792 assert_eq!(h.pop(), Some(1));
793 assert_eq!(h.pop(), Some(3));
794 assert_eq!(h.pop(), Some(5));
795 assert!(h.is_empty());
796 }
797 #[test]
798 fn test_prefix_counter() {
799 let mut pc = PrefixCounter::new();
800 pc.record("hello");
801 pc.record("help");
802 pc.record("world");
803 assert_eq!(pc.count_with_prefix("hel"), 2);
804 assert_eq!(pc.count_with_prefix("wor"), 1);
805 assert_eq!(pc.count_with_prefix("xyz"), 0);
806 }
807 #[test]
808 fn test_fixture() {
809 let mut f = Fixture::new();
810 f.set("key1", "val1");
811 f.set("key2", "val2");
812 assert_eq!(f.get("key1"), Some("val1"));
813 assert_eq!(f.get("key3"), None);
814 assert_eq!(f.len(), 2);
815 }
816}