Figures

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