00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "unit_base.h"
00014
00015 #include <application/application_shell.h>
00016 #include <basis/astring.h>
00017 #include <basis/functions.h>
00018 #include <configuration/application_configuration.h>
00019 #include <loggers/program_wide_logger.h>
00020 #include <filesystem/byte_filer.h>
00021 #include <filesystem/filename.h>
00022 #include <structures/string_table.h>
00023 #include <textual/xml_generator.h>
00024
00025 using namespace application;
00026 using namespace basis;
00027 using namespace configuration;
00028 using namespace filesystem;
00029 using namespace loggers;
00030 using namespace structures;
00031 using namespace textual;
00032
00033 #define BASE_LOG(s) EMERGENCY_LOG(program_wide_logger::get(), s)
00034
00035 namespace unit_test {
00036
00037 const int EXPECTED_MAXIMUM_TESTS = 10008;
00038
00039 const char *name_for_bools(bool bv)
00040 { if (bv) return "true"; else return "false"; }
00041
00042 unit_base::unit_base()
00043 : c_lock(),
00044 c_total_tests(0),
00045 c_passed_tests(0),
00046 c_successful(EXPECTED_MAXIMUM_TESTS),
00047 c_failed(EXPECTED_MAXIMUM_TESTS)
00048 {
00049 }
00050
00051 unit_base::~unit_base() {}
00052
00053 int unit_base::total_tests() const { return c_total_tests; }
00054
00055 int unit_base::passed_tests() const { return c_passed_tests; }
00056
00057 int unit_base::failed_tests() const
00058 { return c_total_tests - c_passed_tests; }
00059
00060 void unit_base::count_successful_test(const basis::astring &class_name, const basis::astring &test_name)
00061 {
00062 auto_synchronizer synch(c_lock);
00063 outcome ret = c_successful.add(class_name + " -- " + test_name, "");
00064 if (ret == common::IS_NEW) {
00065 c_total_tests++;
00066 c_passed_tests++;
00067 }
00068 }
00069
00070 void unit_base::record_pass(const basis::astring &class_name, const astring &test_name,
00071 const astring &diag)
00072 {
00073 auto_synchronizer synch(c_lock);
00074 count_successful_test(class_name, test_name);
00075
00076
00077 #ifdef DEBUG
00078 astring message = astring("OKAY: ") + class_name + " in test [" + test_name + "]";
00079 BASE_LOG(message);
00080 #endif
00081 }
00082
00083 void unit_base::count_failed_test(const basis::astring &class_name, const basis::astring &test_name,
00084 const basis::astring &diag)
00085 {
00086 auto_synchronizer synch(c_lock);
00087 outcome ret = c_failed.add(class_name + " -- " + test_name, diag);
00088 if (ret == common::IS_NEW) {
00089 c_total_tests++;
00090 }
00091 }
00092
00093 void unit_base::record_fail(const basis::astring &class_name, const astring &test_name, const astring &diag)
00094 {
00095 count_failed_test(class_name, test_name, diag);
00096 astring message = astring("\nFAIL: ") + class_name + " in test [" + test_name + "]\n" + diag + "\n";
00097 BASE_LOG(message);
00098 }
00099
00100 void unit_base::record_successful_assertion(const basis::astring &class_name, const astring &test_name,
00101 const astring &assertion_name)
00102 {
00103 record_pass(class_name, test_name,
00104 astring("no problem with: ") + assertion_name);
00105 }
00106
00107 void unit_base::record_failed_object_compare(const hoople_standard &a, const hoople_standard &b,
00108 const basis::astring &class_name, const astring &test_name, const astring &assertion_name)
00109 {
00110 astring a_state, b_state;
00111 a.text_form(a_state);
00112 b.text_form(b_state);
00113 record_fail(class_name, test_name,
00114 astring("Error in assertion ") + assertion_name + ":\n"
00115 + "==============\n"
00116 + a_state + "\n"
00117 + "=== versus ===\n"
00118 + b_state + "\n"
00119 + "==============");
00120 }
00121
00122 void unit_base::record_failed_int_compare(int a, int b,
00123 const basis::astring &class_name, const astring &test_name, const astring &assertion_name)
00124 {
00125 record_fail(class_name, test_name,
00126 astring("Error in assertion ") + assertion_name
00127 + a_sprintf(": inappropriate values: %d & %d", a, b));
00128 }
00129
00130 void unit_base::record_failed_double_compare(double a, double b,
00131 const basis::astring &class_name, const astring &test_name, const astring &assertion_name)
00132 {
00133 record_fail(class_name, test_name,
00134 astring("Error in assertion ") + assertion_name
00135 + a_sprintf(": inappropriate values: %f & %f", a, b));
00136 }
00137
00138 void unit_base::record_failed_pointer_compare(const void *a, const void *b,
00139 const basis::astring &class_name, const astring &test_name, const astring &assertion_name)
00140 {
00141 record_fail(class_name, test_name,
00142 astring("Error in assertion ") + assertion_name
00143 + a_sprintf(": inappropriate values: %p & %p", a, b));
00144 }
00145
00146 void unit_base::record_failed_tf_assertion(bool result,
00147 bool expected_result, const basis::astring &class_name, const astring &test_name,
00148 const astring &assertion_name)
00149 {
00150 record_fail(class_name, test_name, astring("Error in assertion ") + assertion_name
00151 + ": expected " + name_for_bools(expected_result)
00152 + " but found " + name_for_bools(result));
00153 }
00154
00155 void unit_base::assert_equal(const hoople_standard &a, const hoople_standard &b,
00156 const basis::astring &class_name, const astring &test_name, const astring &diag)
00157 {
00158 FUNCDEF("assert_equal");
00159 bool are_equal = (a == b);
00160 if (are_equal) record_successful_assertion(class_name, test_name, astring(func) + ": " + diag);
00161 else record_failed_object_compare(a, b, class_name, test_name, func);
00162 }
00163
00164 void unit_base::assert_not_equal(const hoople_standard &a, const hoople_standard &b,
00165 const basis::astring &class_name, const astring &test_name, const astring &diag)
00166 {
00167 FUNCDEF("assert_not_equal");
00168 bool are_equal = (a == b);
00169 if (!are_equal) record_successful_assertion(class_name, test_name, astring(func) + ": " + diag);
00170 else record_failed_object_compare(a, b, class_name, test_name, func);
00171 }
00172
00173 const char *byte_array_phrase = "byte_array[%d]";
00174
00175 void unit_base::assert_equal(const basis::byte_array &a, const basis::byte_array &b,
00176 const basis::astring &class_name, const basis::astring &test_name, const astring &diag)
00177 {
00178 FUNCDEF("assert_equal");
00179 bool are_equal = (a == b);
00180 if (are_equal) record_successful_assertion(class_name, test_name, astring(func) + ": " + diag);
00181 else {
00182 astring a_s = a_sprintf(byte_array_phrase, a.length());
00183 astring b_s = a_sprintf(byte_array_phrase, b.length());
00184 record_failed_object_compare(a_s, b_s, class_name, test_name, func);
00185 }
00186 }
00187
00188 void unit_base::assert_not_equal(const basis::byte_array &a, const basis::byte_array &b,
00189 const basis::astring &class_name, const basis::astring &test_name, const astring &diag)
00190 {
00191 FUNCDEF("assert_not_equal");
00192 bool are_equal = (a == b);
00193 if (!are_equal) record_successful_assertion(class_name, test_name, func);
00194 else {
00195 astring a_s = a_sprintf(byte_array_phrase, a.length());
00196 astring b_s = a_sprintf(byte_array_phrase, b.length());
00197 record_failed_object_compare(a_s, b_s, class_name, test_name, func);
00198 }
00199 }
00200
00201 void unit_base::assert_equal(int a, int b, const basis::astring &class_name, const astring &test_name, const astring &diag)
00202 {
00203 FUNCDEF("assert_equal integer");
00204 bool are_equal = a == b;
00205 if (are_equal) record_successful_assertion(class_name, test_name, astring(func) + ": " + diag);
00206 else record_failed_int_compare(a, b, class_name, test_name, astring(func) + ": " + diag);
00207 }
00208
00209 void unit_base::assert_not_equal(int a, int b, const basis::astring &class_name, const astring &test_name, const astring &diag)
00210 {
00211 FUNCDEF("assert_not_equal integer");
00212 bool are_inequal = a != b;
00213 if (are_inequal) record_successful_assertion(class_name, test_name, astring(func) + ": " + diag);
00214 else record_failed_int_compare(a, b, class_name, test_name, astring(func) + ": " + diag);
00215 }
00216
00217 void unit_base::assert_equal(double a, double b, const basis::astring &class_name, const astring &test_name, const astring &diag)
00218 {
00219 FUNCDEF("assert_equal double");
00220 bool are_equal = a == b;
00221 if (are_equal) record_successful_assertion(class_name, test_name, astring(func) + ": " + diag);
00222 else record_failed_double_compare(a, b, class_name, test_name, astring(func) + ": " + diag);
00223 }
00224
00225 void unit_base::assert_not_equal(double a, double b, const basis::astring &class_name, const astring &test_name, const astring &diag)
00226 {
00227 FUNCDEF("assert_not_equal double");
00228 bool are_inequal = a != b;
00229 if (are_inequal) record_successful_assertion(class_name, test_name, astring(func) + ": " + diag);
00230 else record_failed_double_compare(a, b, class_name, test_name, astring(func) + ": " + diag);
00231 }
00232
00233
00234 void unit_base::assert_equal(const void *a, const void *b,
00235 const basis::astring &class_name, const astring &test_name, const astring &diag)
00236 {
00237 FUNCDEF("assert_equal void pointer");
00238 bool are_equal = a == b;
00239 if (are_equal) record_successful_assertion(class_name, test_name, astring(func) + ": " + diag);
00240 else record_failed_pointer_compare(a, b, class_name, test_name, astring(func) + ": " + diag);
00241 }
00242
00243 void unit_base::assert_not_equal(const void *a, const void *b,
00244 const basis::astring &class_name, const astring &test_name, const astring &diag)
00245 {
00246 FUNCDEF("assert_not_equal void pointer");
00247 bool are_inequal = a != b;
00248 if (are_inequal) record_successful_assertion(class_name, test_name, astring(func) + ": " + diag);
00249 else record_failed_pointer_compare(a, b, class_name, test_name, astring(func) + ": " + diag);
00250 }
00251
00252 void unit_base::assert_true(bool result, const basis::astring &class_name, const astring &test_name, const astring &diag)
00253 {
00254 FUNCDEF("assert_true");
00255 if (result) record_successful_assertion(class_name, test_name, astring(func) + ": " + diag);
00256 else record_failed_tf_assertion(result, true, class_name, test_name, astring(func) + ": " + diag);
00257 }
00258
00259 void unit_base::assert_false(bool result, const basis::astring &class_name, const astring &test_name, const astring &diag)
00260 {
00261 FUNCDEF("assert_false");
00262 if (!result) record_successful_assertion(class_name, test_name, astring(func) + ": " + diag);
00263 else record_failed_tf_assertion(result, false, class_name, test_name, astring(func) + ": " + diag);
00264 }
00265
00266 int unit_base::final_report()
00267 {
00268 auto_synchronizer synch(c_lock);
00269 int to_return = 0;
00270
00271 astring keyword = "FAILURE";
00272
00273
00274 if (c_total_tests == c_passed_tests) keyword = "SUCCESS";
00275 else to_return = 12;
00276
00277 if (!c_total_tests) keyword = "LAMENESS (no tests!)";
00278
00279
00280
00281
00282
00283
00284
00285 astring message = keyword + " for "
00286 + filename(application_configuration::application_name()).basename().raw()
00287 + a_sprintf(": %d of %d unit tests passed.",
00288 c_successful.symbols(), c_successful.symbols() + c_failed.symbols());
00289 BASE_LOG(message);
00290
00291
00292 write_cppunit_xml();
00293
00294 return to_return;
00295 }
00296
00297 void unit_base::write_cppunit_xml()
00298 {
00299 auto_synchronizer synch(c_lock);
00300 astring logs_dir = environment::get("LOGS_DIR");
00301 if (logs_dir == astring::empty_string()) logs_dir = "logs";
00302 astring outfile = logs_dir + "/"
00303 + filename(application_configuration::application_name()).basename().raw()
00304 + ".xml";
00305
00306
00307
00308 int id = 1;
00309
00310 xml_generator report;
00311 string_table attribs;
00312
00313
00314
00315 report.open_tag("TestRun");
00316
00317 report.open_tag("FailedTests");
00318 for (int i = 0; i < c_failed.symbols(); i++) {
00319 attribs.reset();
00320 attribs.add("id", a_sprintf("%d", id++));
00321 report.open_tag("FailedTest", attribs);
00322 attribs.reset();
00323
00324 report.open_tag("Name");
00325 report.add_content(c_failed.name(i));
00326 report.close_tag("Name");
00327
00328 report.open_tag("FailureType", attribs);
00329 report.add_content("Assertion");
00330 report.close_tag("FailureType");
00331
00332 report.open_tag("Location", attribs);
00333
00334 report.open_tag("File", attribs);
00335 report.add_content(application_configuration::application_name());
00336 report.close_tag("File");
00337
00338 report.open_tag("Line", attribs);
00339 report.add_content("0");
00340 report.close_tag("Line");
00341
00342 report.close_tag("Location");
00343
00344 report.open_tag("Message");
00345 report.add_content(c_failed[i]);
00346 report.close_tag("Message");
00347
00348 report.close_tag("FailedTest");
00349 }
00350 report.close_tag("FailedTests");
00351
00352 report.open_tag("SuccessfulTests");
00353 for (int i = 0; i < c_successful.symbols(); i++) {
00354 attribs.reset();
00355 attribs.add("id", a_sprintf("%d", id++));
00356 attribs.reset();
00357 report.open_tag("Test", attribs);
00358 report.open_tag("Name");
00359 report.add_content(c_successful.name(i));
00360 report.close_tag("Name");
00361 report.close_tag("Test");
00362 }
00363 report.close_tag("SuccessfulTests");
00364
00365 report.open_tag("Statistics");
00366 report.open_tag("Tests");
00367 report.add_content(a_sprintf("%d", c_failed.symbols() + c_successful.symbols()));
00368 report.close_tag("Tests");
00369
00370 report.open_tag("FailuresTotal");
00371 report.add_content(a_sprintf("%d", c_failed.symbols()));
00372 report.close_tag("FailuresTotal");
00373
00374 report.open_tag("Errors");
00375 report.add_content("0");
00376 report.close_tag("Errors");
00377
00378 report.open_tag("Failures");
00379 report.add_content(a_sprintf("%d", c_failed.symbols()));
00380 report.close_tag("Failures");
00381
00382 report.close_tag("Statistics");
00383
00384 report.close_tag("TestRun");
00385
00386 astring text_report = report.generate();
00387
00388
00389 byte_filer xml_out(outfile, "wb");
00390 xml_out.write(text_report);
00391 xml_out.close();
00392 }
00393
00394 }
00395