This is the exact source code used in the code listings of the article Testing with Axioms in C++ 2011. Each listing is delimited by a "\start" and an "\end" command.
//%% Use non-used C++ characters for block. //\catcode`\}=9 //\catcode`\{=9 //\catcode`\$=2 //\catcode`\`=1 //\ignoreinput // Checked with r49 #include <catsfoot_testing.hh> namespace testerns { using namespace catsfoot; template <typename... T> struct tester { }; //\start`tester$ template <> struct tester<> { template <typename Generator, typename Fun, typename... Params> static bool call(Generator, Fun f, Params... values) { try { f(values...); return true; } catch (axiom_failure af) { return false; } } }; template <typename T, typename... U> struct tester<T, U...> { template <typename Generator, typename Fun, typename... Params> static bool call(Generator g, Fun f, Params... values) { auto container = g.get(selector<T>()); for (auto i = container.begin(); i != container.end(); ++i) { if (!tester<U...>::call(g, f, values..., *i)) return false; } return true; } }; template <typename Generator, typename... T> bool test(Generator g, void f(T...)) { return tester<T...>::call(g, f); } //\end void axiom(int a, int b, int c) { if ((a == b) && (b == c)) axiom_assert(a == c); } void axiom_fail(int a, int b, int c) { if ((a == b) && (b == c)) axiom_assert(a != c); } bool dotest() { auto generator = choose(list_data_generator<int> ({0, 1, 2, -1, 41, 52}), default_generator()); if ( ::testerns::test(generator, axiom_fail)) return false; return ::testerns::test(generator, axiom); } } namespace equivalencens { using namespace catsfoot; //\start`equivalence$ template <typename T, typename Rel> struct equivalence: public concept { typedef concept_list< is_callable<Rel(T, T)>, std::is_convertible<typename is_callable<Rel(T, T)>::result_type, bool> > requirements; static void reflexivity(const Rel& rel, const T& a) { axiom_assert(rel(a,a)); } static void symmetry(const Rel& rel, const T& a, const T& b) { if (rel(a, b)) axiom_assert(rel(b, a)); } static void transitivity(const Rel& rel, const T& a, const T& b, const T& c) { if (rel(a, b) && rel(b, c)) axiom_assert(rel(a, c)); } AXIOMS(reflexivity, symmetry, transitivity); }; //\end #ifdef SHOULDBE //\start`congruence$ template <typename Rel, typename Op, typename... Args> struct congruence: public concept { typedef concept_list< equivalence<Args, Rel>..., is_callable<Op(Args...)>, equivalence<typename is_callable<Op(Args...)>::result_type, Rel> > requirements; static void congruence_axiom(const Args&... args1, const Args&... args2, const Op& op, const Rel& rel) { if (rel(args1, args2)...) axiom_assert(rel(op(args1...), op(args2...))); } AXIOMS(congruence_axiom); }; //\end #else template <typename Rel, typename Op, typename... Args> struct congruence: public concept { typedef concept_list< equivalence<Args, Rel>..., is_callable<Op(Args...)>, equivalence<typename is_callable<Op(Args...)>::result_type, Rel> > requirements; static void congruence_axiom(const std::tuple<Args...>& args1, const std::tuple<Args...>& args2, const Op& op, const Rel& rel) { if (tuple_rel(rel,args1, args2)) axiom_assert(rel(call_with(op,args1), call_with(op,args2))); } AXIOMS(congruence_axiom); }; #endif } # include <drivers/test_driver.hh> # include <drivers/test_all_driver.hh> # include <dataset/choose.hh> namespace equivalencens { bool f() { auto generator = choose(list_data_generator<int> ({0, 1, 2, -1, 41, 52}), default_generator()); return //\start`testall$ test_all<congruence<op_eq, op_plus, int, int> >(generator); //\end } } namespace wrapped { //\start`wrappingmethods$ struct foo_wrapped { template<typename T, typename... Args, typename Ret = decltype(std::declval<T>() .foo(std::declval<Args>()...))> Ret operator()(T&& object, Args&&... args) const { return std::forward<T>(object).foo(std::forward<Args>(args)...); } }; struct foo_functionalized { template<typename T, typename... Args, typename = decltype(std::declval<T>() .foo(std::declval<Args>()...))> T operator()(const T& object, Args&&... args) const { T ret(object); ret.foo(std::forward<Args>(args)...); return ret; } }; //\end struct A { bool flag; A(): flag(false) {} A(const A& other): flag(other.flag) { } A* clone() { return new A(*this); } void foo() { flag = true; } }; bool test() { A a; A other = foo_functionalized()(a); if (!(other.flag && !a.flag)) return false; foo_wrapped()(a); return other.flag && a.flag; } } namespace wrapped2 { template <typename T> struct clone_ptr { private: T* ptr; public: ~clone_ptr() { delete ptr; } template <typename... Args> explicit clone_ptr(Args&&... args): ptr(new T(std::forward<Args>(args)...)) {} explicit clone_ptr(T* ptr): ptr(ptr) {} clone_ptr(const T& t): ptr(t->clone()) {} template <typename U, typename = typename std::enable_if<std::is_base_of<T, U>::value>::type> clone_ptr(const clone_ptr<T>& other): ptr(other.ptr->clone()) { } clone_ptr(const clone_ptr& other): ptr(other.ptr->clone()) { } template <typename U, typename = typename std::enable_if<std::is_base_of<T, U>::value>::type> clone_ptr(clone_ptr<U>&& other): ptr(other.ptr) { other.ptr = NULL; } clone_ptr(clone_ptr&& other): ptr(other.ptr) { other.ptr = NULL; } T* get() { return ptr; } const T* get() const { return ptr; } T& operator*() { return *get(); } const T& operator*() const { return *get(); } T* operator->() { return get(); } const T* operator->() const { return get(); } }; //\start`inheritanceclone$ struct foo_functionalized { template<typename T, typename... Args, typename = decltype(std::declval<T>() .foo(std::declval<Args>()...))> clone_ptr<T> operator()(clone_ptr<T> object, Args&&... args) const { object->foo(std::forward<Args>(args)...); return std::move(object); } }; //\end struct A { bool flag; A(): flag(false) {} A(const A& other): flag(other.flag) { } A* clone() { return new A(*this); } void foo() { flag = true; } }; bool test() { clone_ptr<A> a; clone_ptr<A> other = foo_functionalized()(a); return other->flag && !a->flag; } } namespace codeforannotation { using namespace catsfoot; template <typename T> struct verified; template <typename T> struct container; template <typename T> struct plus_monoid; //\start`codeforannotation$ template <typename T, typename Op, typename Id> struct monoid: public concept { typedef concept_list< is_callable<Op(T, T)>, is_callable<Id()>, std::is_convertible<typename is_callable<Op(T, T)> ::result_type, T>, std::is_convertible<typename is_callable<Id()> ::result_type, T> > requirements; static void associativity(const Op& op, const T& a, const T& b, const T& c) { axiom_assert(op(a, op(b, c)) == op(op(a, b), c)); } static void identity(const Op& op, const T& a, const Id& id) { axiom_assert((op(id(), a) == a) && (op(a, id()) == a)); } AXIOMS(associativity, identity); }; // This predicate is a example of predicate coming from the // standard library. template <typename T> struct is_lvalue_reference: public std::false_type { }; template <typename T> struct is_lvalue_reference<T&>: public std::true_type { }; template <> struct verified<monoid<int, op_plus, constant<int, 0> > > : public std::true_type {}; template <typename C, ENABLE_IF(container<C>), typename T = typename container<C>::element_type, ENABLE_IF(plus_monoid<T>)> T sum(C set); //\end } #include <limits> #include <dataset/dataset.hh> bool g() { using namespace catsfoot; //\start`static_list$ auto generator = choose (list_data_generator<int> ({-1, 0, 1, 2, 3, std::numeric_limits<int>::min(), std::numeric_limits<int>::max()}), default_generator()); //\end generator.get(selector<int>{}); return true; } #include <dataset/random_term_generator.hh> #include <set> bool h() { using namespace catsfoot; std::mt19937 engine; //\start`randomterm$ auto int_set_generator = term_generator_builder <std::set<int>, // list of supported types std::set<int>::iterator, int>() (engine, // random generator engine // generate random integers std::function<int()>([&engine] () { return std::uniform_int_distribution<int>()(engine); }), // generate set: initial constructor<std::set<int>()>(), // generate set: insert std::function<std::set<int>(std::set<int>, int)> ([](std::set<int> in, int i) { in.insert(i); return std::move(in); }), // generate random iterator for a given set std::function<std::set<int>::iterator(std::set<int>&)> ([&engine] (std::set<int>& s) { auto n = std::uniform_int_distribution<decltype(s.size())> (0, s.size())(engine); auto i = s.begin(); for (decltype(n) j = 0; j < n; ++j, ++i) ; return i; // will point to random element in s })); //\end int_set_generator.get(selector<int>{}); //\start`powerset$ typedef std::set<int> elt; auto power_set_generator = term_generator_builder <std::set<elt>, // list of supported types std::set<elt>::iterator, elt>() (engine, // random generator engine // generate random sets pick<elt>(int_set_generator), // generate set: initial constructor<std::set<elt>()>(), // generate set: insert std::function<std::set<elt>(std::set<elt>, const elt&)> ([](std::set<elt> in, const elt& i) { in.insert(i); return std::move(in); }), // generate random iterator for a given set std::function<std::set<elt>::iterator(std::set<elt>&)> ([&engine] (std::set<elt>& s) { auto n = std::uniform_int_distribution<decltype(s.size())> (0, s.size())(engine); auto i = s.begin(); for (decltype(n) j = 0; j < n; ++j, ++i) ; return i; // will point to random element in s })); //\end power_set_generator.get(selector<std::set<int> >{}); return true; } template <typename AssociativeContainer, typename Iterator> struct something { //\start`erasure$ static void erasure(AssociativeContainer c, Iterator i) { if ((i == find(c, i)) && (i != end(c))) axiom_assert(size(erase(c, i)) == size(c) - 1); } //\end }; namespace monoiddef { using namespace catsfoot; //\start`monoid$ template <typename T, typename Op, typename Id> struct monoid: public concept { typedef concept_list< is_callable<Op(T, T)>, is_callable<Id()>, std::is_convertible<typename is_callable<Op(T, T)> ::result_type, T>, std::is_convertible<typename is_callable<Id()> ::result_type, T> > requirements; static void associativity(const Op& op, const T& a, const T& b, const T& c) { axiom_assert(op(a, op(b, c)) == op(op(a, b), c)); } static void identity(const Op& op, const T& a, const Id& id) { axiom_assert((op(id(), a) == a) && (op(a, id()) == a)); } AXIOMS(associativity, identity); }; //\end } //\start`predicate_dflt$ template <typename T> struct is_lvalue_reference: public std::false_type { }; //\end //\start`predicate$ template <typename T> struct is_lvalue_reference<T&>: public std::true_type { }; //\end namespace catsfoot { using namespace monoiddef; //\start`verified_monoid$ template <> struct verified<monoid<int, op_plus, constant<int, 0> > > : public std::true_type {}; //\end } namespace monoiddef { template <typename T> struct verified {}; //\start`monoid_plus$ template <typename T> struct plus_monoid: public concept { typedef monoid<T, op_plus, wrapped_constructor<T()> > requirements; }; template <typename T> struct verified<monoid<T, op_plus, wrapped_constructor<T()> > > : public verified<plus_monoid<T> > {}; //\end } namespace monoiddef { template <typename T> struct container; //\start`sum$ template <typename C, ENABLE_IF(container<C>), typename T = typename container<C>::element_type, ENABLE_IF(plus_monoid<T>)> T sum(C set); //\end } namespace monoiddecomposed { using namespace catsfoot; //\start`monoidhead$ template <typename T, typename Op, typename Id> struct monoid: public concept { //\end //\start`monoidreqs$ typedef concept_list< // operations are callable with the given parameter types is_callable<Op(T, T)>, is_callable<Id()>, // results are convertible to T std::is_convertible<typename is_callable<Op(T, T)> ::result_type, T>, std::is_convertible<typename is_callable<Id()> ::result_type, T> > requirements; //\end //\start`monoidaxioms$ static void associativity(const Op& op, const T& a, const T& b, const T& c) { axiom_assert(op(a, op(b, c)) == op(op(a, b), c)); } static void identity(const Op& op, const T& a, const Id& id) { axiom_assert((op(id(), a) == a) && (op(a, id()) == a)); } //\end //\start`monoidgetaxioms$ AXIOMS(associativity, identity); }; // end of concept monoid //\end template <typename T> struct verified; //\start`monoidverified$ template <> struct verified<monoid<int, op_plus, constant<int,0> > > : public std::true_type {}; //\end } namespace ringdef { using namespace monoiddef; template <typename T, typename Op, typename Minus, typename Id> struct group: public concept { typedef concept_list< monoid<T, Op, Id> > requirements; static void inverse(const T& a, const Id& id, const Minus& minus, const Op& op) { axiom_assert(op(a, minus(a)) == id()); axiom_assert(op(minus(a), a) == id()); } AXIOMS(inverse); }; template <typename T, typename Op> struct commutative: public concept { typedef concept_list< is_callable<Op(T, T)>, std::is_convertible<typename is_callable<Op(T, T)> ::result_type, T>, > requirements; static void commutativity(const T& a, const T& b, const Op& op) { axiom_assert(op(a, b) == op(b, a)); } AXIOMS(commutativity); }; template <typename T, typename MOp, typename AOp> struct distributive { typedef concept_list< is_callable<MOp(T, T)>, is_callable<AOp(T, T)>, std::is_convertible<typename is_callable<MOp(T, T)> ::result_type, T>, std::is_convertible<typename is_callable<AOp(T, T)> ::result_type, T> > requirements; static void distributivity(const T& a, const T& b, const T& c, const MOp& mop, const AOp& aop) { axiom_assert(mop(a, aop(b, c)) == aop(mop(a, b), mop(a, c))); axiom_assert(mop(aop(a, b), c) == aop(mop(a, c), mop(a, c))); } AXIOMS(distributivity); }; //\start`ring$ template <typename T, typename MOp, typename AOp, typename Minus, typename Zero, typename One> struct ring: public concept { typedef monoid<T, AOp, Zero> add_monoid; typedef group<T, AOp, Minus, Zero> add_group; typedef monoid<T, MOp, One> mul_monoid; typedef concept_list< mul_monoid, add_group, // implies add_monoid distributive<T, MOp, AOp>, commutative<T, AOp> > requirements; // check that we also have add_monoid class_assert_concept<add_monoid> check; }; //\end struct op_minus { template <typename T, typename Ret = decltype(-std::declval<T>())> Ret operator()(T&& t) const { return -std::forward<T>(t); } }; } namespace ringdef { bool test() { auto generator = choose (list_data_generator<int> ({-1, 0, 1, 2, 3, std::numeric_limits<int>::min(), std::numeric_limits<int>::max()}), default_generator()); return test_all<ring<int, op_times, op_plus, op_minus, constant<int, 0>, constant<int, 1> > > (generator); } } namespace monoiddef { bool test() { using catsfoot::test; auto generator = choose (list_data_generator<int> ({-1, 0, 1, 2, 3, std::numeric_limits<int>::min(), std::numeric_limits<int>::max()}), default_generator()); //\start`monoiddef_test$ test(generator, monoid<int, op_plus, constant<int, 0>>::associativity); //\end if (!test(generator, monoid<int, op_plus, constant<int, 0>>::associativity, "associativity")) return false; return //\start`monoiddef_testall$ test_all<monoid<int, op_plus, constant<int, 0>>>(generator); //\end } bool test_fail() { auto generator = choose (list_data_generator<int> ({-1, 0, 1, 2, 3, std::numeric_limits<int>::min(), std::numeric_limits<int>::max()}), default_generator()); return //\start`monoiddef_testfail$ test_all<monoid<int, op_plus, constant<int, 1>>>(generator); //\end } } namespace hashdef { using namespace catsfoot; //\start`hash$ template <typename T, typename Hash> struct hash: public concept { typedef concept_list< congruence<op_eq, Hash, T> > requirements; }; //\end bool test() { auto generator = choose (list_data_generator<std::string> ({"aaa", "bbb", "ccc"}), default_generator()); return test_all<hash<std::string, std::hash<std::string> > > (generator); } } namespace orderdef { using namespace catsfoot; //\start`strict_weak_order$ template <typename T, typename Rel> struct strict_weak_order: public concept { typedef concept_list< is_callable<Rel(T, T)>, std::is_convertible<typename is_callable<Rel(T, T)> ::result_type, bool>, > requirements; static void irreflexivity(const T& a, const Rel& rel) { axiom_assert(!rel(a, a)); } static void asymmetry(const T& a, const T& b, const Rel& rel) { if (a != b) axiom_assert(!(rel(a,b) && rel(b,a))); } static void transitivity(const T& a, const T& b, const T& c, const Rel& rel) { if ((rel(a, b) && rel(b, c))) axiom_assert(rel(a,c)); } static void transitivity_of_equivalence (const T& a, const T&b, const T& c, const Rel& rel) { if (rel(a, b)) axiom_assert(rel(a, c) || rel(c, b)); } AXIOMS(irreflexivity, asymmetry, transitivity, transitivity_of_equivalence) }; //\end bool test() { auto generator = choose (list_data_generator<int> ({-1, 0, 1, 2, 3, std::numeric_limits<int>::min(), std::numeric_limits<int>::max()}), default_generator()); return test_all<strict_weak_order<int, op_lt> > (generator); } } namespace exception { using namespace catsfoot; //\start`exception$ template <typename T, typename Fun, typename... Args, ENABLE_IF(is_callable<Fun(Args...)>)> bool throwing(Fun&& fun, Args&&... args) { try { std::forward<Fun>(fun)(std::forward<Args>(args)...); } catch (T) { return true; } return false; } //\end struct Bidule {}; void f(int i) { if (i == 0) throw Bidule(); } bool test() { return throwing<Bidule>(f, 0) && !throwing<Bidule>(f, 1); } } int main() { bool ret = true; ret = ret && equivalencens::f(); ret = ret && g(); ret = ret && h(); ret = ret && ringdef::test(); ret = ret && monoiddef::test(); ret = ret && !monoiddef::test_fail(); ret = ret && exception::test(); ret = ret && orderdef::test(); ret = ret && hashdef::test(); ret = ret && wrapped::test(); ret = ret && wrapped2::test(); ret = ret && testerns::dotest(); return !ret; } //\endignore