diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b1dd49113daaacbe0eccdaf670e4fe5e397015f..7865e8cebc9af41ccc553f06794af4d467b003b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ base_add_subdir(Code) base_add_subdir(Config) base_add_subdir(Debug) base_add_subdir(Journal) +base_add_subdir(Paths) base_add_subdir(Progress) base_add_subdir(Security) base_add_subdir(Test) diff --git a/Paths/CMakeLists.txt b/Paths/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..92db745614852ba13fdd8260586ac5169b838dc3 --- /dev/null +++ b/Paths/CMakeLists.txt @@ -0,0 +1,9 @@ +set(my_headers + ${CMAKE_CURRENT_SOURCE_DIR}/Filesystem.hh + ${CMAKE_CURRENT_SOURCE_DIR}/PathLink.hh + PARENT_SCOPE +) + +set(my_sources + PARENT_SCOPE +) diff --git a/Test/TestFilesystem.hh b/Paths/Filesystem.hh similarity index 66% rename from Test/TestFilesystem.hh rename to Paths/Filesystem.hh index 96593766865a037a1204670ea01eafe49d71210f..93ac9f80dde23682a90758efa154a26e48a0815e 100755 --- a/Test/TestFilesystem.hh +++ b/Paths/Filesystem.hh @@ -1,34 +1,29 @@ // (C) Copyright 2021 by Autodesk, Inc. -#ifndef BASE_TEST_FILESYSTEM_HH_INCLUDE -#define BASE_TEST_FILESYSTEM_HH_INCLUDE - -#ifdef TEST_ON +#ifndef BASE_FILESYSTEM_HH_INCLUDE +#define BASE_FILESYSTEM_HH_INCLUDE #include <Base/Security/Mandatory.hh> #ifdef __APPLE__ #include <boost/filesystem.hpp> -namespace Test +namespace Base { namespace filesystem = boost::filesystem; typedef boost::filesystem::path Path; typedef boost::system::error_code error_code; -} // namespace Test +} // namespace Base #else // __APPLE__ // Include <filesystem> but silence resulting C4995 warnings INSECURE_INCLUDE_SECTION_BEGIN #include <filesystem> INSECURE_INCLUDE_SECTION_END -namespace Test +namespace Base { namespace filesystem = std::filesystem; -typedef std::filesystem::path Path; typedef std::error_code error_code; -} // namespace Test +} // namespace Base #endif // __APPLE__ -#endif // TEST_ON - -#endif // BASE_TEST_FILESYSTEM_HH_INCLUDE +#endif // BASE_FILESYSTEM_HH_INCLUDE diff --git a/Paths/PathLink.hh b/Paths/PathLink.hh new file mode 100755 index 0000000000000000000000000000000000000000..695d40f9638e59d247d74d751455cbcdd59c4ac3 --- /dev/null +++ b/Paths/PathLink.hh @@ -0,0 +1,32 @@ +// (C) Copyright 2020 by Autodesk, Inc. + +#ifndef BASE_PATHLINK_HH_INCLUDED +#define BASE_PATHLINK_HH_INCLUDED + +#include <Base/Paths/Filesystem.hh> + +namespace Base +{ +namespace fs = Base::filesystem; + +class PathLink +{ +public: + explicit PathLink(const fs::path& _path) : path_(_path) {} + + template <class StreamT> + friend StreamT& operator<<(StreamT& _os, const PathLink& _link) + { + _os << "\"" + << "file://" << fs::weakly_canonical(_link.path_).generic_string() + << "\""; + return _os; + } + +private: + const fs::path& path_; +}; + +} // namespace Base + +#endif // BASE_PATHLINK_HH_INCLUDED diff --git a/Test/CMakeLists.txt b/Test/CMakeLists.txt index a28da381b1201bdcdc8eb08fae1a30e066cab11f..fa9d180af00456b476960f2555d843be3637b05d 100644 --- a/Test/CMakeLists.txt +++ b/Test/CMakeLists.txt @@ -1,6 +1,7 @@ set(my_headers ${CMAKE_CURRENT_SOURCE_DIR}/LongestCommonSubsequenceT.hh ${CMAKE_CURRENT_SOURCE_DIR}/TestArgs.hh + ${CMAKE_CURRENT_SOURCE_DIR}/TestCase.hh ${CMAKE_CURRENT_SOURCE_DIR}/TestChecksum.hh ${CMAKE_CURRENT_SOURCE_DIR}/TestChecksumCompare.hh ${CMAKE_CURRENT_SOURCE_DIR}/TestChecksumCompletion.hh @@ -11,7 +12,6 @@ set(my_headers ${CMAKE_CURRENT_SOURCE_DIR}/TestChecksumLevel.hh ${CMAKE_CURRENT_SOURCE_DIR}/TestChecksumNumberT.hh ${CMAKE_CURRENT_SOURCE_DIR}/TestChecksumOutcome.hh - ${CMAKE_CURRENT_SOURCE_DIR}/TestFilesystem.hh ${CMAKE_CURRENT_SOURCE_DIR}/TestOutcome.hh ${CMAKE_CURRENT_SOURCE_DIR}/TestPaths.hh ${CMAKE_CURRENT_SOURCE_DIR}/TestReport.hh diff --git a/Test/TestCase.hh b/Test/TestCase.hh new file mode 100755 index 0000000000000000000000000000000000000000..6a1dea61d1fc27f674f4f2c56516aff1f5cc514d --- /dev/null +++ b/Test/TestCase.hh @@ -0,0 +1,80 @@ +// (C) Copyright 2021 by Autodesk, Inc. + +#ifndef BASE_TESTCASE_HH_INCLUDED +#define BASE_TESTCASE_HH_INCLUDED + +#ifdef TEST_ON + +/* +The BASE_TEST() macro wraps around an existing test declaration macro (e.g. +TEST_CASE() for Catch2), augmenting it with a checksum comparison. For now, the +existing test declaration macro must define a void function. + +In order to use BASE_TEST(), the following macros *must* be defined (before this +file is included): + +- TEST_DECLARATION: a placeholder for the existing test declaration macro; + +- TEST_COMPARE_CHECKSUMS: a placeholder for a function that compares checksums + output by the currently-running test against the corresponding baseline. + +As an example, to use this with Catch2, one would write: + + #define TEST_DECLARATION TEST_CASE + +And to compare the checksums using Test::compare_checksums(), one would write: + + #define TEST_COMPARE_CHECKSUMS Test::compare_checksums() + +It is not required to use BASE_TEST(), and it is straightforward to define a +custom macro with a similar function. The following macros are available for +use: + +- INTERNAL_UNIQUE_NAME(STEM): uses the compiler extension __COUNTER__ to provide + a unique name that starts with STEM. + +- INTERNAL_BASE_TEST_FUNCTION_STEM: A stem that can be used when defining your + own "Test and Compare" macros. + +- INTERNAL_UNIQUE_BASE_TEST_FUNCTION_NAME: A unique function name that can be + utilised in your own "Test and Compare" macros. +*/ + +#define INTERNAL_UNIQUE_NAME3(STEM, COUNTER) STEM##COUNTER +#define INTERNAL_UNIQUE_NAME2(STEM, COUNTER) \ + INTERNAL_UNIQUE_NAME3(STEM, COUNTER) +#define INTERNAL_UNIQUE_NAME(STEM) INTERNAL_UNIQUE_NAME2(STEM, __COUNTER__) + +#define INTERNAL_BASE_TEST_FUNCTION_STEM ____B_A_S_E____T_E_S_T____ +#define INTERNAL_UNIQUE_BASE_TEST_FUNCTION_NAME \ + INTERNAL_UNIQUE_NAME(BASE_TEST_FUNCTION_STEM) + +// Both TEST_DECLARATION and TEST_COMPARE_CHECKSUMS must be defined in order to +// use the BASE_TEST() macro. +#if defined(TEST_DECLARATION) && defined(TEST_COMPARE_CHECKSUMS) + +#define INTERNAL_BASE_TEST_VOID(TEST_FUNCTION, ...) \ + static void TEST_FUNCTION(); \ + TEST_DECLARATION(__VA_ARGS__) \ + { \ + TEST_FUNCTION(); \ + TEST_COMPARE_CHECKSUMS; \ + } \ + void TEST_FUNCTION() + +#define BASE_TEST(...) \ + INTERNAL_BASE_TEST_VOID(INTERNAL_UNIQUE_BASE_TEST_FUNCTION_NAME, __VA_ARGS__) + +#else // defined(TEST_DECLARATION) && defined(TEST_COMPARE_CHECKSUMS) + +#define BASE_TEST(...) \ + static_assert(false, \ + "Both TEST_DECLARATION and TEST_COMPARE_CHECKSUMS must be " \ + "defined in order to use the BASE_TEST() macro. Please ensure " \ + "they are defined before TestCase.hh is included."); \ + static void INTERNAL_UNIQUE_BASE_TEST_FUNCTION_NAME() + +#endif // defined(TEST_DECLARATION) && defined(TEST_COMPARE_CHECKSUMS) + +#endif // TEST_ON +#endif // BASE_TESTCASE_HH_INCLUDED diff --git a/Test/TestChecksum.cc b/Test/TestChecksum.cc index 2d5f486b0f3c9cd3b9ef650bc585e1f8929a0aef..bfe1f659c7d037ead4e39a13e7098576aa823070 100644 --- a/Test/TestChecksum.cc +++ b/Test/TestChecksum.cc @@ -5,6 +5,7 @@ #include "TestChecksum.hh" #include "Base/Debug/DebCallStack.hh" +#include <algorithm> #include <fstream> #include <iostream> #include <map> @@ -31,6 +32,15 @@ Registry& registry_modify() return chksm_reg; } +// Trim (remove whitespace) from the end of a std::string (in place) +inline void rtrim(std::string& s) +{ + s.erase(std::find_if(s.rbegin(), s.rend(), + [](unsigned char ch) { return !std::isspace(ch); }) + .base(), + s.end()); +} + }//namespace const Registry& registry() @@ -162,12 +172,14 @@ std::string Object::format_checksum(const Result& _rslt, const String& _data) void Object::add(const Result& _rslt, const String& _data) { - static std::mutex mtx; //synchronize access to the checksum report stream + static std::mutex mtx; // synchronize access to the checksum report stream std::lock_guard<std::mutex> lock(mtx); - static Base::OutputStreamAdaptT<std::ofstream> test_strm(REPORT_FILENAME); + static Base::OutputStreamAdaptT<std::ofstream> rprt_strm(REPORT_FILENAME); static bool tag_out = false; + Base::OStringStream strm; + #ifdef DEB_ON static String prev_call_stck; String call_stck("/"); @@ -175,21 +187,30 @@ void Object::add(const Result& _rslt, const String& _data) if (prev_call_stck != call_stck) { - test_strm << call_stck << ::Base::ENDL; + strm << call_stck << ::Base::ENDL; prev_call_stck = call_stck; } -#endif//DEB_ON +#endif // DEB_ON if (!tag_out) { tag_out = true; - test_strm << REPORT_LEVEL_TAG << LEVEL_TEXT[run_lvl] << ::Base::ENDL; + strm << REPORT_LEVEL_TAG << LEVEL_TEXT[run_lvl] << ::Base::ENDL; + } + + // Write checksum data and remove trailing whitespace + strm << format_checksum(_rslt, _data); + rtrim(strm.str); + + // Write stream data to the report file if non-empty + if (!strm.str.empty()) + { + rprt_strm << strm.str << ::Base::ENDL; + rprt_strm.stream().flush(); } - test_strm << format_checksum(_rslt, _data); - test_strm.stream().flush(); } -}//Checksum -}//namespace Test +} // namespace Checksum +} // namespace Test #endif//TEST_ON diff --git a/Test/TestChecksumCompletion.cc b/Test/TestChecksumCompletion.cc index 22d191324347fb6e209118fc76b44fe42f2775cd..e8b2077603bf4e932a08e868b7b2ddc3c27b7027 100644 --- a/Test/TestChecksumCompletion.cc +++ b/Test/TestChecksumCompletion.cc @@ -36,19 +36,12 @@ const char* const END = "END"; } // namespace -Completion::Completion() - : Object("Completion", L_STABLE), - start_time_(std::chrono::system_clock::now()) -{ -} +Completion::Completion() : Object("Completion", L_STABLE) {} void Completion::record_end() { - auto end_time = std::chrono::system_clock::now(); - std::chrono::duration<double> time_diff_sec = end_time - start_time_; - std::stringstream mess; - mess << "Success: " << END << " Time: " << time_diff_sec.count(); + mess << "Success: " << END; add(Result::OK, mess.str()); } diff --git a/Test/TestChecksumCompletion.hh b/Test/TestChecksumCompletion.hh index 78c7fc81cf6ebf6ef0b8b84859381dda30f3ed7d..ee48b3c6bb2c10275aa6a7a3be923bd6a2cd13fa 100644 --- a/Test/TestChecksumCompletion.hh +++ b/Test/TestChecksumCompletion.hh @@ -16,7 +16,7 @@ namespace Test namespace Checksum { -// Checks it the test has completed and, if not, detect the problem for compare. +// Writes a checksum when the test completes. class Completion : public Object { public: @@ -27,9 +27,6 @@ public: //! Get if the line contains the end completion checksum record static bool end(const std::string& _line); - -private: - std::chrono::time_point<std::chrono::system_clock> start_time_; }; // Register the checksum to check test completion. diff --git a/Test/TestOutcome.cc b/Test/TestOutcome.cc index 86dfce6c67aeeab20041132725ee79614731dd5e..decf45a64e155de6c42579ffdd5f616cae275523 100755 --- a/Test/TestOutcome.cc +++ b/Test/TestOutcome.cc @@ -50,7 +50,7 @@ void ignore_unstable_outcome(const char* const _call) { std::cout << "-----------------------\n" - "INFO: Unstable outcome from the following call has been ignored:" + "Info: Unstable outcome from the following call has been ignored:" "\n\n " << _call << "\n\n" "Replace IGNORE_UNSTABLE_OUTCOME() with CHECK_OUTCOME() once " "the functionality is stable.\n" diff --git a/Test/TestReport.cc b/Test/TestReport.cc index 12cca98e418e626084cb331bfc9700e35a6ae4fc..a191bcafdfb67e32fdb6855c85ac4460fb2b2931 100644 --- a/Test/TestReport.cc +++ b/Test/TestReport.cc @@ -3,13 +3,13 @@ #ifdef TEST_ON #include <Base/Security/Mandatory.hh> +#include <Base/Paths/Filesystem.hh> +#include <Base/Paths/PathLink.hh> #include "TestChecksumCompletion.hh" -#include "TestFilesystem.hh" #include "TestReport.hh" #include "TestResult.hh" #include "TestResultAnalysis.hh" -#include <algorithm> #include <array> #include <cctype> #include <cstring> @@ -26,13 +26,16 @@ namespace Test { + +using PathLink = Base::PathLink; + namespace { const char* const INDENT = " "; const char CR = (char)'\r'; -namespace fs = Test::filesystem; +namespace fs = Base::filesystem; /*! Contains the test path and, if the CTest log is parsed, any associated error @@ -379,20 +382,6 @@ struct TestDiffSummary Test::DifferenceDistribution diffs_; }; -struct PathLink -{ - const fs::path& path_; - explicit PathLink(const fs::path& _path) : path_(_path) {} - - template <class StreamT> - friend StreamT& operator<<(StreamT& _os, const PathLink& _link) - { - _os << "\"file:////" - << fs::canonical(fs::absolute(_link.path_)).generic_string() << "\""; - return _os; - } -}; - /*! Reads the report information from a test output directory and: - copies it to the output stream; @@ -447,77 +436,25 @@ Result parse_report(const fs::path& _test_dir, const std::string& _err_msg, return rslt; } -// Trim (remove whitespace) from the end of a std::string -inline std::string& rtrim(std::string& s) -{ - s.erase(std::find_if(s.rbegin(), s.rend(), - [](unsigned char ch) { return !std::isspace(ch); }) - .base(), - s.end()); - return s; -} - -// Apply report content filters. For now this only removes blank lines and time -// information -void filter_report(const Test::Path& _rprt_src, const Test::Path& _rprt_trgt) -{ -#if __APPLE__ - std::ifstream ifs(_rprt_src.string()); -#else // __APPLE__ - std::ifstream ifs(_rprt_src); -#endif // __APPLE__ - std::vector<std::string> rprt_lines; - - // Read the report contents line-by-line (to improve performance) and filter - // out the time information - for (std::string line; std::getline(ifs, line);) - { - // Search for time information - const auto time_pos = line.find("Time:"); - if (time_pos != std::string::npos) - { - // Trim the time information - line.resize(time_pos); - - // Filter the line if it is only whitespace - if (std::all_of(line.begin(), line.end(), isspace)) - continue; - } - rprt_lines.push_back(rtrim(line)); - } - ifs.close(); - - // Write all of the stored lines to the target report file -#if __APPLE__ - std::ofstream ofs(_rprt_trgt.string()); -#else // __APPLE__ - std::ofstream ofs(_rprt_trgt); -#endif // __APPLE__ - for (const auto& line : rprt_lines) - ofs << line << std::endl; - ofs.close(); -} - // Make a 'clean' copy of a test directory, i.e. a 'baseline', which contains // the same directory structure as the test directory, but only the report.txt -// files (with some bits filtered out). -void make_baseline(const Path& _test_root_dir, const Path& _bsln_root_dir, - const TestList& _test_list) +// files. +void make_baseline(const fs::path& _test_root_dir, + const fs::path& _bsln_root_dir, const TestList& _test_list) { if (fs::exists(_bsln_root_dir)) return; // Baseline already present. fs::create_directory(_bsln_root_dir); - // Copy a 'cleaned' version of the global report to the baseline directory. + // Copy the global report to the baseline directory. std::cout << "Processing the global report... "; const auto main_rep_flnm(_test_root_dir / Test::REPORT_FILENAME); const auto bsln_rep_flnm(_bsln_root_dir / Test::REPORT_FILENAME); - filter_report(main_rep_flnm, bsln_rep_flnm); + fs::copy(main_rep_flnm, bsln_rep_flnm); std::cout << " ...done." << std::endl; - // Copy a 'cleaned' version of each test report to the corresponding place in - // the baseline directory. + // Copy each test report to the corresponding place in the baseline directory. size_t test_idx = 0; size_t num_tests = _test_list.tests().size(); for (auto& test : _test_list.tests()) @@ -531,8 +468,8 @@ void make_baseline(const Path& _test_root_dir, const Path& _bsln_root_dir, // Create the baseline directory (and all parents if necessary) fs::create_directories(bsln_test_dir); - // Copy and filter the report - filter_report(curr_test_dir / Test::REPORT_FILENAME, + // Copy the report to the baseline directory + fs::copy(curr_test_dir / Test::REPORT_FILENAME, bsln_test_dir / Test::REPORT_FILENAME); } std::cout << std::endl; @@ -672,7 +609,7 @@ void copy(const fs::path& _root_from, const fs::path& _root_to, fs::create_directories(dir_to); // Copy the contents of dir_from to dir_to - Test::error_code err_code; + Base::error_code err_code; fs::copy(dir_from, dir_to, err_code); if (err_code) { @@ -824,13 +761,15 @@ ExitStatus make_comparison(const char* const _dir_left, Base::OutputStreamAdaptT<TestStream> test_log; - // Get the path to the test directory for both suites - const auto test_dir_left = test_lists[0].root_dir() / test.path_; - const auto test_dir_right = test_lists[1].root_dir() / test.path_; + // Get the path to the report for both suites + const auto report_path_left = + test_lists[0].root_dir() / test.path_ / Test::REPORT_FILENAME; + const auto report_path_right = + test_lists[1].root_dir() / test.path_ / Test::REPORT_FILENAME; // Compare the checksums for the test between the two suites - const auto diff_stats = compare(test_dir_left, test_dir_right, test_log, - _chks_cmpr, _cot == COT_SHORT_DIFF); + const auto diff_stats = compare_reports(report_path_left, report_path_right, + test_log, _chks_cmpr, _cot == COT_SHORT_DIFF); if (!diff_stats.empty()) { @@ -965,8 +904,8 @@ ExitStatus make_comparison(const char* const _dir_left, if (create_diff_report && (found_diff || !is_subset[0] || !is_subset[1])) { - std::cout << "\nPlease check the compare log:\n" - << diff_path.generic_string() << std::endl; + std::cout << "\nPlease check the compare log: " << PathLink(diff_path) + << std::endl; // Return an error if a difference was found or if there is a test in the // right suite that does not exist in the left suite. diff --git a/Test/TestReport.hh b/Test/TestReport.hh index aa5ce7040369a6b7ebf55360b2025954081be10f..d1eae96e364a27c371828728df71260e11e26207 100644 --- a/Test/TestReport.hh +++ b/Test/TestReport.hh @@ -6,11 +6,11 @@ #ifdef TEST_ON #include <Base/Test/TestChecksumCompare.hh> + #include <functional> namespace Test { - enum ExitStatus { ES_OK = 0, @@ -50,7 +50,7 @@ enum CompareOutputType Produces a summary report (e.g. number of tests executed, which tests had errors, how many of each error were observed, etc.) of all test outputs below <_root_dir>/. Also produce a clean copy of the test directory (at -<_root_dir>_base/) that contains only the (cleaned up) individual test reports. +<_root_dir>_base/) that contains only the individual test reports. */ ExitStatus make_summary_report(const char* const _root_dir); diff --git a/Test/TestResultAnalysis.cc b/Test/TestResultAnalysis.cc index 98975621d35ea26c44f646f6a13f20a29f8a9b21..b84d36571f7adee473adbc68136cc3ebe5170844 100644 --- a/Test/TestResultAnalysis.cc +++ b/Test/TestResultAnalysis.cc @@ -3,13 +3,13 @@ #ifdef TEST_ON #include <Base/Security/Mandatory.hh> +#include <Base/Paths/Filesystem.hh> #include "TestResultAnalysis.hh" #include "LongestCommonSubsequenceT.hh" #include "TestChecksum.hh" #include "TestChecksumCompletion.hh" #include "TestChecksumFile.hh" -#include "TestFilesystem.hh" #include <algorithm> #include <cctype> @@ -23,11 +23,12 @@ namespace Test namespace { -namespace fs = Test::filesystem; +namespace fs = Base::filesystem; -// Remove code links from _str +// Remove code links from _str. Code links are expected to be in the format for +// Base::CodeLink used in IOutputStream.cc void erase_code_links(std::string& _str) -{ // refers to the format for Base::CodeLink used in IOutputStream.cc +{ const char* const CODE_LINK_BEGIN = "@ ["; const char* const CODE_LINK_END = "]"; @@ -42,6 +43,15 @@ void erase_code_links(std::string& _str) } } +// Trim (remove whitespace) from the end of a std::string (in place) +inline void rtrim(std::string& s) +{ + s.erase(std::find_if(s.rbegin(), s.rend(), + [](unsigned char ch) { return !std::isspace(ch); }) + .base(), + s.end()); +} + // Read and parse lines of a report to get the checksum Result, name and content. class Report { @@ -54,15 +64,22 @@ public: explicit Entry(const std::string& _line) : line_(_line) { + // Ignore lines that represent (debug) callstack groups if (group()) return; - // the line should be a checksum, extract the checksum data + + // Remove whitespace and newline characters from the end of the line + rtrim(line_); + + // The line should be a checksum. Extract the checksum data. std::istringstream line_strm(line_); line_strm >> std::noskipws >> rcrd_.rslt; line_strm >> std::skipws >> name_; if (!name_.empty() && name_.back() == ':') name_.pop_back(); std::getline(line_strm, rcrd_.data); + + // Erase any code links of the form "@ [ ..... ]" from the data erase_code_links(rcrd_.data); } @@ -102,27 +119,26 @@ public: public: Report() : lvl_(Checksum::L_ALL) {} - explicit Report(const fs::path& _test_dir) : lvl_(Checksum::L_ALL) - { - read(_test_dir); - } - - void read(const fs::path& _test_dir) + explicit Report(const fs::path& _rprt_path) : lvl_(Checksum::L_ALL) { - std::ifstream rprt((_test_dir / REPORT_FILENAME).string()); // report stream + std::ifstream rprt(_rprt_path.string()); // report stream for (std::string line; std::getline(rprt, line); ) { + // Skip empty lines if (line.empty()) - continue;// skip empty lines + continue; + // Find the checksum run level for this report by looking for the line + // "Report Level: <LEVEL>" const auto rprt_lvl_tag_idx = line.find(REPORT_LEVEL_TAG); - if (rprt_lvl_tag_idx != std::string::npos) // report level entry? - {// find what is the checksum run level for this report + if (rprt_lvl_tag_idx != std::string::npos) + { + // Found such a line. Parse it to extract <LEVEL>. for (int i = (int)Checksum::L_NONE; i <= Checksum::L_ALL; ++i) { if (line.find(Checksum::LEVEL_TEXT[i], rprt_lvl_tag_idx) != - std::string::npos) - {// found it! + std::string::npos) + { lvl_ = (Checksum::Level)i; break; } @@ -143,10 +159,10 @@ private: EntryVector entrs_; }; -}//namespace +} // namespace -DifferenceDistribution compare(const fs::path& _old_dir, - const fs::path& _new_dir, Base::IOutputStream& _log, +DifferenceDistribution compare_reports(const fs::path& _rprt_path0, + const fs::path& _rprt_path1, Base::IOutputStream& _log, const Checksum::Compare& _chks_cmpr, const bool _shrt_frmt) { using Base::ENDL; @@ -162,7 +178,7 @@ DifferenceDistribution compare(const fs::path& _old_dir, const char* const DIFF_TAG = "! "; const char* const RESULT_TAG = " "; - const Report rprts[2] = { Report(_old_dir), Report(_new_dir) }; + const Report rprts[2] = {Report(_rprt_path0), Report(_rprt_path1)}; LongestCommonSubsequenceT<Report> rprt_lcs(rprts[0], rprts[1]); rprt_lcs.trace(); @@ -171,10 +187,10 @@ DifferenceDistribution compare(const fs::path& _old_dir, DifferenceDistribution test_diff; - for (const auto& ij : rprt_mtch)// iterate the mis-/matched index pairs + for (const auto& ij : rprt_mtch) // iterate the mis-/matched index pairs { if (ij.matched()) // matched entries ? - { // compare the checksums, print if anything else + { // compare the checksums, print if anything else const auto& old_entr = rprts[0][ij.i]; const auto& new_entr = rprts[1][ij.j]; @@ -193,24 +209,25 @@ DifferenceDistribution compare(const fs::path& _old_dir, _log << SAME_TAG << old_entr.line() << ENDL; // just print it } else - {// print difference - _log << NAME_TAG << old_entr.name() << ": " << diff.type_text() << - ENDL; - _log << OLD_TAG << old_entr.record().rslt << RESULT_TAG << - old_entr.record().data << ENDL; - _log << NEW_TAG << new_entr.record().rslt << RESULT_TAG << - new_entr.record().data << ENDL; + { // print difference + _log << NAME_TAG << old_entr.name() << ": " << diff.type_text() + << ENDL; + _log << OLD_TAG << old_entr.record().rslt << RESULT_TAG + << old_entr.record().data << ENDL; + _log << NEW_TAG << new_entr.record().rslt << RESULT_TAG + << new_entr.record().data << ENDL; const char rslt_mark = - old_entr.record().rslt.type() == new_entr.record().rslt.type() ? - ' ' : '!'; + old_entr.record().rslt.type() == new_entr.record().rslt.type() + ? ' ' + : '!'; _log << DIFF_TAG << rslt_mark << RESULT_TAG << diff.description() - << ENDL; + << ENDL; } ++test_diff[diff]; } } else if (ij.i_valid() && rprts[0].level() <= rprts[1].level()) - {// old entry removed and the old checksum level is equal or stricter + { // old entry removed and the old checksum level is equal or stricter const auto& old_entr = rprts[0][ij.i]; _log << REMOVED_TAG << old_entr.line() << ENDL; // just print it if (!old_entr.group()) // if it is a group change, just ignore it @@ -222,7 +239,7 @@ DifferenceDistribution compare(const fs::path& _old_dir, } } else if (ij.j_valid() && rprts[0].level() >= rprts[1].level()) - {// new entry added and the new checksum level is stricter or equal + { // new entry added and the new checksum level is stricter or equal const auto& new_entr = rprts[1][ij.j]; _log << ADDED_TAG << new_entr.line() << ENDL; // just print it if (!new_entr.group()) // if it is a group change, just ignore it @@ -238,6 +255,6 @@ DifferenceDistribution compare(const fs::path& _old_dir, return test_diff; } -}//namespace Test +} // namespace Test -#endif//TEST_ON +#endif // TEST_ON diff --git a/Test/TestResultAnalysis.hh b/Test/TestResultAnalysis.hh index 0e9fb79c35006cfb469742b7c3d34a4f15833510..65ceec1935ad48f58e1045cc3c8f82c67cab8dc0 100644 --- a/Test/TestResultAnalysis.hh +++ b/Test/TestResultAnalysis.hh @@ -6,28 +6,35 @@ #ifdef TEST_ON #include <Base/Test/TestChecksumCompare.hh> -#include <Base/Test/TestFilesystem.hh> +#include <Base/Paths/Filesystem.hh> + #include <map> +#include <string> namespace Test { +namespace fs = Base::filesystem; typedef Checksum::Difference Difference; - typedef std::map<Difference, size_t> DifferenceDistribution; /*! -Compares two test directories to detect differences in test execution and/or -test results. Returns a map with the difference statistics (counts for each type -of difference). Equal checksums are reported if _short_frmt = false. +Compares the checksums listed in two test reports. Returns a map with the +difference statistics (counts for each type of difference). Equal checksums are +ignored if _short_frmt = true. + +Arguments: + +* [in] _rprt_path0: Path to the left-suite report file. +* [in] _rprt_path1: Path to the right-suite report file. +* [out] _log: Description of the differences. +* [in] _chks_cmpr: Checksum compare function. +* [in] _short_frmt: Remove identical checksums (short format) [default = false]. + */ -DifferenceDistribution compare( - const Path& _test_dir0, /*< [in] Test directory. */ - const Path& _test_dir1, /*< [in] Test directory. */ - Base::IOutputStream& _log, /*< [out] Description of the checksums and differences. */ - const Checksum::Compare& _chks_cmpr, /*<[in] Checksum compare function */ - const bool _short_frmt = false /*![in] Remove identical checksums */ -); +DifferenceDistribution compare_reports(const fs::path& _rprt_path0, + const fs::path& _rprt_path1, Base::IOutputStream& _log, + const Checksum::Compare& _chks_cmpr, const bool _short_frmt = false); } // namespace Test