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