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