drivers/test_driver.hh

00001 // This file is a part of Catsfoot.
00002 // Copyright (C) 2011  Uni Research
00003 //
00004 // This program is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU Lesser Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser Public License
00015 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #ifndef __TEST_DRIVER_HH
00018 # define __TEST_DRIVER_HH
00019 
00020 # include <memory>
00021 # include "../dataset/dataset.hh"
00022 # include <iostream>
00023 # include "../axioms/axioms.hh"
00024 # include "../utils/type_to_string.hh"
00025 # include "../type_traits/always_false.hh"
00026 # include "../type_traits/identity.hh"
00027 
00028 namespace catsfoot {
00029 
00030   template <typename T, typename U>
00031   struct printable;
00032 
00033   namespace details {
00035     template <
00036       typename Stream,
00037       typename T,
00038       ENABLE_IF(printable<Stream&, T>)>
00039     void print_if_printable(Stream& s, T&& t) {
00040       s << t;
00041     }
00042 
00044     template <
00045       typename Stream,
00046       typename T,
00047       ENABLE_IF_NOT(printable<Stream&, T>),
00048       typename = void>
00049     void print_if_printable(Stream& s, T&&) {
00050       s << "Values of type " << type_to_string<T>() << " are not printable";
00051     }
00052 
00054     void display_values() {
00055     }
00056 
00058     template <typename T, typename... U>
00059     void display_values(T&& t, U&&... u) {
00060       std::cerr << " * ";
00061       if (std::is_same<typename std::remove_reference<T>::type, T&&>::value) {
00062         std::cerr << "Moved variable not printable.";
00063       }
00064       else
00065         print_if_printable(std::cerr, std::forward<T>(t));
00066       std::cerr << std::endl;
00067       display_values(std::forward<U>(u)...);
00068     }
00069 
00070     template <typename... T>
00071     struct tester;
00072 
00073     template <>
00074     struct tester<> {
00075       template <typename Generator, typename Fun, typename... Params,
00076                 typename Stream>
00077       static bool call_gen_final(Stream& s,
00078                                  Generator&, Fun f, Params&&... values) {
00079         try {
00080           f((std::forward<Params>(values))...);
00081           return true;
00082         } catch (axiom_failure af) {
00083           s << "-----------------------------------------"
00084             "---------------------------------------" << std::endl;
00085           s << af.msg() << std::endl;
00086           s << "Values were: " << std::endl;
00087           display_values(std::forward<Params>(values)...);
00088           s << std::endl;
00089           return false;
00090         }
00091       }
00092       template <typename Generator, typename Fun, typename... Params,
00093                 typename Stream>
00094       static bool call_gen(Stream& s,
00095                            Generator& g, Fun f, Params&&... values) {
00096         return call_gen_final(s, g, f, *std::forward<Params>(values)...);
00097       }
00098     };
00099 
00100     //FIXME: We should verify that g.get(selector<T>{}) is callable.
00101     template <typename T, typename... U>
00102     struct tester<T, U...> {
00103       template <typename Generator, typename Fun, typename... Params,
00104                 typename Stream>
00105       static bool call_gen(Stream& s, Generator& g, Fun f,
00106                            Params&&... values) {
00107         auto container = g.get(selector<T>{});
00108         bool ret = true;
00109         for (auto i = container.begin();
00110              i != container.end(); ++i) {
00111           bool ret2 =
00112             tester<U...>::call_gen(s, g,
00113                                    f,
00114                                    std::forward<Params>(values)...,
00115                                    i);
00116           ret = ret && ret2;
00117         }
00118         return ret;
00119       }
00120     };
00121   }
00122 
00124   template <typename Generator,
00125             typename... T, typename Stream = decltype(std::cerr)>
00126   bool test(Generator& g,
00127             void f(T...),
00128             std::string name = "<unknown>",
00129             Stream& s = std::cerr) {
00130     if (details::tester<T...>::call_gen(s, g, f)) {
00131       s << name << ": passed." << std::endl;
00132       return true;
00133     } else {
00134       s << name << ": failed." << std::endl;
00135       return false;
00136     }
00137   }
00138 
00149   template <typename Fun, typename... Params>
00150   bool catch_errors(Fun f, Params&&... values) {
00151     default_generator d;
00152     return details::tester<>::call_gen_final(std::cerr,
00153                                              d,
00154                                              f,
00155                                              std::forward<Params>(values)...);
00156   }
00157 }
00158 
00159 #endif