Made on Kubuntu
00001 // Copyright (C) 2009-2010 Ferdinand Majerech 00002 // This file is part of MiniINI 00003 // For conditions of distribution and use, see copyright notice in LICENSE.txt 00004 00005 #ifndef TESTER_H_INCLUDED 00006 #define TESTER_H_INCLUDED 00007 00008 #include <cstring> 00009 #include <string> 00010 #include <iostream> 00011 #include <sstream> 00012 00013 #include "../../miniini.h" 00014 00016 00018 template <class Data> 00019 class TestData : public Data 00020 { 00021 private: 00022 std::string __TestName__; 00023 00024 public: 00025 00026 TestData() 00027 :__TestName__() 00028 {} 00029 00031 template <int n> 00032 void Test() 00033 { 00034 throw std::string(""); 00035 } 00036 00037 void SetName(const std::string & name) 00038 { 00039 __TestName__ = name; 00040 } 00041 00042 const std::string & GetName() const 00043 { 00044 return __TestName__; 00045 } 00046 00047 static void AssertEqual(const char * in1, const char * in2, 00048 const std::string & errorstr) 00049 { 00050 if(strcmp(in1, in2)) 00051 { 00052 throw errorstr; 00053 } 00054 } 00055 00056 template<class T> 00057 static void AssertEqual(T in1, T in2, const std::string & errorstr) 00058 { 00059 if(!(in1 == in2)) 00060 { 00061 throw errorstr; 00062 } 00063 } 00064 00065 template<class T> 00066 static void AssertTrue(T in, const std::string & errorstr) 00067 { 00068 AssertEqual(static_cast<bool>(in), true, errorstr); 00069 } 00070 00071 00073 //MINIINI SPECIFIC ASSERTS// 00075 00076 #define ASSERTREAD(section, tag, expectedvalue, readmethod, type)\ 00077 {\ 00078 type readvalue;\ 00079 std::ostringstream error;\ 00080 error << "Couldn't read " << tag << "= from [" << section->GetName()\ 00081 << "]";\ 00082 AssertTrue(section->readmethod(tag.c_str(), readvalue), \ 00083 error.str());\ 00084 error.str("");\ 00085 error << "Read unexpected value from " << tag << "= from ["\ 00086 << section->GetName() << "]\nExpected value: " <<\ 00087 expectedvalue << "\nRead value: " << readvalue;\ 00088 AssertEqual(readvalue, expectedvalue, error.str());\ 00089 } 00090 00091 static void AssertRString(INISection * section, const std::string & tag, 00092 const std::string & expectedvalue) 00093 { 00094 ASSERTREAD(section, tag, expectedvalue.c_str(), ReadString, 00095 const char *); 00096 } 00097 00098 static void AssertRInt(INISection * section, const std::string & tag, 00099 int expectedvalue) 00100 { 00101 ASSERTREAD(section, tag, expectedvalue, ReadInt, int); 00102 } 00103 00104 static void AssertRFloat(INISection * section, const std::string & tag, 00105 float expectedvalue) 00106 { 00107 ASSERTREAD(section, tag, expectedvalue, ReadFloat, float); 00108 } 00109 00110 static void AssertRBool(INISection * section, const std::string & tag, 00111 bool expectedvalue) 00112 { 00113 ASSERTREAD(section, tag, expectedvalue, ReadBool, bool); 00114 } 00115 00116 #undef ASSERTREAD 00117 }; 00118 00119 enum TGroupFailed 00120 { 00121 TGF_INIT, 00122 TGF_DESTROY, 00123 TGF_TEST 00124 }; 00125 00127 template<class Data, int MaxTests=64> 00128 class TestGroup 00129 { 00130 public: 00131 00132 typedef TestData<Data> DataObject; 00133 00134 private: 00135 00137 template <class Test, class Group, int methods> 00138 struct TestRegisterer 00139 { 00140 static void Register(Group& group) 00141 { 00142 group.Register(methods, &Test::template Test<methods>); 00143 TestRegisterer<Test, Group, methods - 1>::Register(group); 00144 } 00145 }; 00146 00147 template <class Test, class Group> 00148 struct TestRegisterer<Test, Group, 0> 00149 { 00150 static void Register(Group&) 00151 { 00152 } 00153 }; 00154 00155 00156 typedef void (DataObject::*TestMethod)(); 00157 00159 std::string Name; 00160 00162 DataObject * GroupData; 00163 00165 TestMethod Tests [MaxTests]; 00166 00167 public: 00168 00170 TestGroup(const std::string & name) 00171 :Name(name) 00172 ,GroupData(NULL) 00173 { 00174 //Generate and register all test methods 00175 TestRegisterer<DataObject, TestGroup, MaxTests>::Register(*this); 00176 std::cout << "\n\nRunning test group: " << Name << "\n"; 00177 00178 //Initialize test data 00179 std::cout << "\nInitializing test data\n"; 00180 try 00181 { 00182 GroupData = new DataObject; 00183 } 00184 catch(const std::string & errorstr) 00185 { 00186 std::cout << "Initialization FAILED\nCause: " << errorstr << "\n"; 00187 throw TGF_INIT; 00188 } 00189 00190 //Total number of valid (not dummy) tests in the group 00191 unsigned tests = 0; 00192 //Number of failed tests in the group 00193 unsigned failedtests = 0; 00194 00195 //Run tests 00196 std::cout << "\nRunning tests\n\n"; 00197 for(unsigned test = 0; test < MaxTests; ++test) 00198 { 00199 try 00200 { 00201 (GroupData->*Tests[test])(); 00202 std::cout << "Test successful: " << GroupData->GetName() 00203 << "\n"; 00204 ++tests; 00205 } 00206 catch(const std::string & errorstr) 00207 { 00208 //Dummy tests throw an empty string 00209 if(!errorstr.empty()) 00210 { 00211 std::cout << "Test FAILED: " << GroupData->GetName() << 00212 "\nCause: " << errorstr << "\n"; 00213 ++tests; 00214 ++failedtests; 00215 } 00216 } 00217 } 00218 00219 //Destroy test data 00220 std::cout << "\nDestroying test data\n"; 00221 try 00222 { 00223 delete GroupData; 00224 } 00225 catch(const std::string & errorstr) 00226 { 00227 std::cout << "Destruction FAILED\nCause: " << errorstr << "\n"; 00228 throw TGF_DESTROY; 00229 } 00230 00231 std::cout << "\nTests:\nTotal: " << tests << "\nFailed: " << 00232 failedtests << "\n"; 00233 00234 //If any test failed, the test group failed as well. 00235 if(failedtests) 00236 { 00237 std::cout << "Test group FAILED\n"; 00238 throw TGF_TEST; 00239 } 00240 00241 } 00242 00243 void Register(int n, TestMethod method) 00244 { 00245 Tests[n - 1] = method; 00246 } 00247 00248 private: 00249 00250 TestGroup(const TestGroup &); 00251 00252 void operator = (const TestGroup &); 00253 }; 00254 00255 #define TEST(data, number)\ 00256 template<>\ 00257 template<>\ 00258 void TestGroup<data>::DataObject::Test<number>() 00259 00260 #endif 00261