axioms/axioms.hh

00001 // This file is a part of Catsfoot.
00002 // Copyright (C) 2011  Uni Research
00003 // Copyright (C) 2011  Valentin David
00004 //
00005 // This program is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU Lesser Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU Lesser Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser Public License
00016 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 
00018 #ifndef __AXIOMS_HH
00019 # define __AXIOMS_HH
00020 
00023 
00024 # include <string>
00025 # include <sstream>
00026 # include <catsfoot-config.hh>
00027 # include <iostream>
00028 # include "../type_traits/always_false.hh"
00029 
00030 namespace catsfoot {
00032   struct axiom_failure {
00033   private:
00034     std::string _msg;
00035 
00036   public:
00038     const std::string& msg() const { return _msg; }
00039 
00040     axiom_failure(const std::string& _msg):
00041       _msg(_msg) {}
00042 
00043     axiom_failure(std::string&& _msg):
00044       _msg(std::move(_msg)) {}
00045 
00046     axiom_failure(std::string&& func,
00047                   std::string&& file,
00048                   unsigned line,
00049                   std::string&& expr):
00050       _msg() {
00051       std::stringstream ss;
00052       ss << std::move(file) << ":" << line << ":";
00053       ss << " Axiom " << std::move(func) << " failed.";
00054       ss << std::endl << std::endl;
00055       ss << "Expression was: " << std::move(expr) << std::endl;
00056       _msg = ss.str();
00057     }
00058 
00060     axiom_failure(const axiom_failure&) = default;
00061 
00063     axiom_failure(axiom_failure&& other): _msg(std::move(other._msg)) {}
00064 
00066     axiom_failure& operator=(axiom_failure&& other) {
00067       std::swap(_msg, other._msg);
00068       return *this;
00069     }
00070 
00072     axiom_failure& operator=(const axiom_failure& other) {
00073       return *this = axiom_failure(other);
00074     }
00075   };
00076 
00077 # ifdef __CATSFOOT_ENABLE_TESTING_RT
00078 #  include "../extern_decl.hh"
00079 
00080   namespace details {
00082     EXTERN
00083     void reached_function(std::string&& func,
00084                           std::string&& file,
00085                           unsigned line);
00086 
00088     EXTERN
00089     void register_function(std::string&& func,
00090                            std::string&& file,
00091                            unsigned line);
00092   }
00093 
00095   EXTERN
00096   bool check_unverified(std::ostream& s = std::cerr);
00097 # else
00098   namespace details {
00099     template <typename T = std::string>
00100     extern
00101     void reached_function(T&&,
00102                           std::string&&,
00103                           unsigned) {
00104       static_assert(details::always_false<T>::value,
00105                     "You probably called a functionality that is available "
00106                     "only if you link with the runtime library. In this case "
00107                     "include catsfoot_testing.hh instead of catsfoot.hh");
00108     }
00109 
00110     template <typename T = std::string>
00111     extern
00112     void register_function(T&&,
00113                            std::string&&,
00114                            unsigned) {
00115       static_assert(details::always_false<T>::value,
00116                     "You probably called a functionality that is available "
00117                     "only if you link with the runtime library. In this case "
00118                     "include catsfoot_testing.hh instead of catsfoot.hh");
00119     }
00120   }
00121 
00122   template <typename T = std::ostream>
00123   extern
00124   bool check_unverified(T& = std::cerr) {
00125     static_assert(details::always_false<T>::value,
00126                   "You probably called a functionality that is available "
00127                   "only if you link with the runtime library. In this case "
00128                   "include catsfoot_testing.hh instead of catsfoot.hh");
00129     return false;
00130   }
00131 # endif
00132 }
00133 
00135 # define _catsfoot__test_axiom(FUN, FILE, LINE, EXPR)        \
00136   { ::catsfoot::details::reached_function(FUN, FILE, LINE);  \
00137     if (!(EXPR))                                             \
00138       throw ::catsfoot::axiom_failure(FUN,                   \
00139                                       FILE, LINE, #EXPR); }  \
00140   ::catsfoot::details::register_function(FUN, FILE, LINE);
00141 
00142 # if defined(DEFINE___PRETTY_FUNCTION__) && \
00143   defined(DEFINE___FILE__) && \
00144   defined(DEFINE___LINE__)
00145 #   define axiom_assert(expr) _catsfoot__test_axiom(__PRETTY_FUNCTION__, \
00146                                   __FILE__, \
00147                                   __LINE__, \
00148                                   expr)
00149 # elif defined(DEFINE___func__) && \
00150   defined(DEFINE___FILE__) && \
00151   defined(DEFINE___LINE__)
00152 #   define axiom_assert(expr) _catsfoot__test_axiom(__func__, \
00153                                   __FILE__, \
00154                                   __LINE__, \
00155                                   expr)
00156 # else
00157 
00158 
00159 #   define axiom_assert(expr) _catsfoot__test_axiom("<unknown>", \
00160                                   "<unknown>", \
00161                                   0, \
00162                                   expr)
00163 # endif
00164 
00165 #endif