obey-0.1.1/.cargo_vcs_info.json0000644000000001360000000000100117710ustar { "git": { "sha1": "3a0eb9c9a6b5e7d5b37ef9773726f5232d4511e7" }, "path_in_vcs": "" }obey-0.1.1/.gitignore000064400000000000000000000000101046102023000125400ustar 00000000000000/target obey-0.1.1/Cargo.toml0000644000000015640000000000100077750ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "obey" version = "0.1.1" authors = ["RĂ¼diger Klaehn "] description = "Test utilities for collections" homepage = "https://github.com/rklaehn" readme = "README.md" keywords = [ "testing", "property", "fuzz", ] categories = ["development-tools::testing"] license = "MIT OR Apache-2.0" repository = "https://github.com/rklaehn/obey" [dependencies] obey-0.1.1/Cargo.toml.orig000064400000000000000000000007641046102023000134570ustar 00000000000000[package] name = "obey" version = "0.1.1" edition = "2021" authors = ["RĂ¼diger Klaehn "] description = "Test utilities for collections" repository = "https://github.com/rklaehn/obey" license = "MIT OR Apache-2.0" keywords = ["testing", "property", "fuzz"] categories = ["development-tools::testing"] readme = "README.md" homepage = "https://github.com/rklaehn" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] obey-0.1.1/README.md000064400000000000000000000000571046102023000120420ustar 00000000000000# Tools for property based tests of collectionsobey-0.1.1/src/lib.rs000064400000000000000000000001541046102023000124640ustar 00000000000000#![doc = include_str!("../README.md")] mod obey; mod test_macros; pub use obey::*; pub use test_macros::*; obey-0.1.1/src/obey.rs000064400000000000000000000047111046102023000126570ustar 00000000000000#![allow(dead_code)] use core::fmt::Debug; use std::collections::BTreeSet; /// A support trait for testing any kind of collection. /// /// Almost anything can be viewed as a collection. E.g. an integer can be viewed as a collection of bit offsets at which it has /// a boolean value. pub trait TestSamples { /// produces "interesting" sample points to test a property for. fn samples(&self, res: &mut BTreeSet); /// gets the value of the collection at position k fn at(&self, k: K) -> V; } pub fn unary_element_test(a: &C, r: C, op: impl Fn(V) -> V) -> bool where C: TestSamples + Debug + Clone, K: Ord + Clone + Debug, V: Eq + Debug, { let mut s: BTreeSet = BTreeSet::new(); a.samples(&mut s); r.samples(&mut s); s.into_iter().all(|key| { let value = a.at(key.clone()); let actual = op(value); let expected = r.at(key.clone()); if expected != actual { println!( "expected!=actual at: {:?}. {:?}!={:?}", key, expected, actual ); println!("a: {:?}", a); println!("r: {:?}", r); false } else { true } }) } pub fn binary_element_test(a: &C, b: &C, r: C, op: impl Fn(V, V) -> V) -> bool where C: TestSamples + Debug, K: Ord + Clone + Debug, V: Eq + Debug, { let mut s: BTreeSet = BTreeSet::new(); a.samples(&mut s); b.samples(&mut s); r.samples(&mut s); s.into_iter().all(|key| { let a_value = a.at(key.clone()); let b_value = b.at(key.clone()); let actual = op(a_value, b_value); let expected = r.at(key.clone()); if expected != actual { println!( "expected!=actual at: {:?}. {:?}!={:?}", key, expected, actual ); println!("a: {:?}", a); println!("b: {:?}", b); println!("r: {:?}", r); false } else { true } }) } pub fn binary_property_test(a: &C, b: &C, r: bool, op: impl Fn(V, V) -> bool) -> bool where C: TestSamples + Debug, K: Ord + Clone + Debug, V: Eq + Debug, { let mut s: BTreeSet = BTreeSet::new(); a.samples(&mut s); b.samples(&mut s); if r { s.iter().cloned().all(|e| op(a.at(e.clone()), b.at(e))) } else { s.iter().cloned().any(|e| !op(a.at(e.clone()), b.at(e))) } } obey-0.1.1/src/test_macros.rs000064400000000000000000000104011046102023000142350ustar 00000000000000/// checks that bitops are symmetric #[macro_export] macro_rules! bitop_symmetry { ($test:ty) => { #[quickcheck] fn bitor_symmetric(a: $test, b: $test) -> bool { &a | &b == &b | &a } #[quickcheck] fn bitxor_symmetric(a: $test, b: $test) -> bool { &a ^ &b == &b ^ &a } #[quickcheck] fn bitand_symmetric(a: $test, b: $test) -> bool { &a & &b == &b & &a } }; } /// checks properties of the empty element vs. bitops and sub #[macro_export] macro_rules! bitop_empty { ($test:ty) => { #[quickcheck] fn bitand_empty_neutral(a: $test) -> bool { let e = Test::empty(); (&a & &e) == e && (&e & &a) == e } #[quickcheck] fn bitor_empty_neutral(a: $test) -> bool { let e = Test::empty(); (&a | &e) == a && (&e | &a) == a } #[quickcheck] fn bitxor_empty_neutral(a: $test) -> bool { let e = Test::empty(); (&a ^ &e) == a && (&e ^ &a) == a } #[quickcheck] fn sub_empty_neutral(a: $test) -> bool { let e = Test::empty(); (&a - &e) == a } }; } /// checks properties of the all element vs. bitops and sub/not #[macro_export] macro_rules! bitop_sub_not_all { ($test:ty) => { #[quickcheck] fn bitand_all_neutral(x: $test) -> bool { let a = Test::all(); (&x & &a) == x && (&a & &x) == x } #[quickcheck] fn bitor_all_all(x: $test) -> bool { let a = Test::all(); (&x | &a) == a && (&a | &x) == a } #[quickcheck] fn bitxor_all_not(x: $test) -> bool { let a = Test::all(); (&a ^ &x) == !&x && (&x ^ &a) == !&x } #[quickcheck] fn sub_all_not(x: $test) -> bool { let a = Test::all(); (&a - &x) == !&x } #[quickcheck] fn sub_bitand_not(a: $test, b: $test) -> bool { (&a).sub(&b) == (&a).bitand(&b.not()) } #[quickcheck] fn not_not_neutral(a: $test) -> bool { &a == &((&a).not()).not() } #[quickcheck] fn all_is_all(a: $test) -> bool { let r1 = a.is_all(); let r2 = a == Test::all(); r1 == r2 } }; } /// checks consistency between op and op_assign #[macro_export] macro_rules! bitop_assign_consistent { ($test:ty) => { #[quickcheck] fn bitand_assign_consistent(a: $test, b: $test) -> bool { let r1 = &a & &b; let mut r2 = a; r2 &= b; r1 == r2 } #[quickcheck] fn bitor_assign_consistent(a: $test, b: $test) -> bool { let r1 = &a | &b; let mut r2 = a; r2 |= b; r1 == r2 } #[quickcheck] fn bitxor_assign_consistent(a: $test, b: $test) -> bool { let r1 = &a ^ &b; let mut r2 = a; r2 ^= b; r1 == r2 } #[quickcheck] fn sub_assign_consistent(a: $test, b: $test) -> bool { let r1 = &a - &b; let mut r2 = a; r2 -= b; r1 == r2 } }; } // checks that the set predicates is_disjoint, is_subset, is_empty, is_all etc. are consistent with the operations #[macro_export] macro_rules! set_predicate_consistent { ($test:ty) => { #[quickcheck] fn is_disjoint_bitand_consistent(a: $test, b: $test) -> bool { let r1 = a.is_disjoint(&b); let r2 = (&a & &b).is_empty(); r1 == r2 } #[quickcheck] fn is_subset_bitand_consistent(a: $test, b: $test) -> bool { let r1 = a.is_subset(&b); let r2 = &(&a & &b) == &a; r1 == r2 } #[quickcheck] fn is_subset_is_superset_consistent(a: $test, b: $test) -> bool { let r1 = a.is_subset(&b); let r2 = b.is_superset(&a); r1 == r2 } #[quickcheck] fn empty_is_empty_consistent(a: $test) -> bool { let r1 = a.is_empty(); let r2 = a == Test::empty(); r1 == r2 } }; }