Commit 9b7e2694 authored by Martin Marinov's avatar Martin Marinov
Browse files

Merged the latest test system changes from dev/amaglim branch to ReForm.

[git-p4: depot-paths = "//ReForm/ReForm/main/Base/": change = 14046]
parent 975c301d
set(my_headers
${CMAKE_CURRENT_SOURCE_DIR}/CodeLink.hh
${CMAKE_CURRENT_SOURCE_DIR}/Quality.hh
PARENT_SCOPE
)
......
// (C) Copyright 2016 by Autodesk, Inc.
//
// The information contained herein is confidential, proprietary
// to Autodesk, Inc., and considered a trade secret as defined
// in section 499C of the penal code of the State of California.
// Use of this information by anyone other than authorized
// employees of Autodesk, Inc. is granted only under a written
// non-disclosure agreement, expressly prescribing the scope
// and manner of such use.
#ifndef BASE_CODELINK_HH_INCLUDED
#define BASE_CODELINK_HH_INCLUDED
#include <string.h>
namespace Base {
//! Convenient wrapper around a preprocessor source code link
struct CodeLink
{
CodeLink(
const char* _fnct,
const char* _file,
const int _line
)
: fnct(_fnct), file(_file), line(_line)
{}
const char* fnct;
const char* file;
int line;
};
// TODO: Replace StreamT w. IOutputStream, move to a .cc file, hide <string.h>!
template <class StreamT>
StreamT& operator<<(StreamT& _os, const CodeLink& _lnk)
{
#ifdef WIN32
const char path_sep = '\\';
#else//!WIN32
const char path_sep = '/';
#endif//WIN32
auto flnm_pntr = strrchr(_lnk.file, path_sep);
if (flnm_pntr == nullptr)
flnm_pntr = _lnk.file;
else
++flnm_pntr;
return _os << " @ [" << _lnk.fnct << "() in "
<< flnm_pntr << ":" << _lnk.line << "]";
}
}//namespace Base
#define BASE_CODELINK Base::CodeLink(__FUNCTION__, __FILE__, __LINE__)
#endif//BASE_CODELINK_HH_INCLUDED
......@@ -10,10 +10,11 @@
#include "DebUtils.hh"
#include "DebDefault.hh"
#include "Base/Code/CodeLink.hh"
#include "Base/Utils/ThrowError.hh"
#include "Base/Utils/Environment.hh"
#include "Base/Test/IChecksum.hh"
#include "Base/Test/ChecksumCount.hh"
#include "Base/Test/ChecksumDebugEvent.hh"
#ifdef DEB_ON
......@@ -799,43 +800,6 @@ Stream& global_stream()
return glbl_strm;
}
// Stream together <__FUNCTION__, __FILE__, __LINE__>
// Cannot use std::tupple, we are not using C++11 in Base
struct TriggerPoint
{
TriggerPoint(
const char* _fnct,
const char* _file,
const int _line
)
: fnct(_fnct), file(_file), line(_line)
{}
const char* fnct;
const char* file;
int line;
};
Stream& operator<<(Stream& _os, const TriggerPoint& _trgr_pnt)
{
#ifdef WIN32
const char path_sep = '\\';
#else//!WIN32
const char path_sep = '/';
#endif//WIN32
auto flnm_pntr = strrchr(_trgr_pnt.file, path_sep);
if (flnm_pntr == nullptr)
flnm_pntr = _trgr_pnt.file;
else
++flnm_pntr;
return _os << " @ [" << _trgr_pnt.fnct << "() in "
<< flnm_pntr << ":" << _trgr_pnt.line << "]";
}
#define TRIGGER_POINT TriggerPoint(_fnct, _file, _line)
}//namespace
......@@ -844,19 +808,20 @@ Stream& operator<<(Stream& _os, const TriggerPoint& _trgr_pnt)
void warning(const std::string& _wrng, const char* const _fnct,
const char* const _file, const int _line)
{
TEST_only(Test::Checksum::checksum_count_add_warning());
global_stream() << WARNING << ": " << _wrng << TRIGGER_POINT
<< Command::END_LF;
Base::CodeLink code_link(_fnct, _file, _line);
TEST_only(Test::Checksum::Debug::warning.record(_wrng, code_link));
global_stream() << WARNING << ": " << _wrng << code_link << Command::END_LF;
}
void error(const std::string& _err, const char* const _fnct,
const char* const _file, const int _line)
{
TEST_only(Test::Checksum::checksum_count_add_error());
global_stream() << ERROR << ": " << _err << TRIGGER_POINT << Command::END_ERR;
Base::CodeLink code_link(_fnct, _file, _line);
TEST_only(Test::Checksum::Debug::error.record(_err, code_link));
global_stream() << ERROR << ": " << _err << code_link << Command::END_ERR;
}
#undef FUNCTION_IN_FILE
#undef TRIGGER_POINT
//////////////////////////////////////////////////////////////////////////
......
set(my_headers
${CMAKE_CURRENT_SOURCE_DIR}/ChecksumCount.hh
${CMAKE_CURRENT_SOURCE_DIR}/ChecksumDebugEvent.hh
${CMAKE_CURRENT_SOURCE_DIR}/ChecksumFile.hh
${CMAKE_CURRENT_SOURCE_DIR}/ChecksumLogValueT.hh
${CMAKE_CURRENT_SOURCE_DIR}/IChecksum.hh
......@@ -17,7 +17,7 @@ SET(my_t_impls
)
set(my_sources
${CMAKE_CURRENT_SOURCE_DIR}/ChecksumCount.cc
${CMAKE_CURRENT_SOURCE_DIR}/ChecksumDebugEvent.cc
${CMAKE_CURRENT_SOURCE_DIR}/ChecksumFile.cc
${CMAKE_CURRENT_SOURCE_DIR}/ChecksumLogValue.cc
${CMAKE_CURRENT_SOURCE_DIR}/IChecksum.cc
......
......@@ -10,63 +10,58 @@
#if defined(TEST_ON) && defined(DEB_ON)
#include "ChecksumCount.hh"
#include "ChecksumLogValueT.hh"
#include "ChecksumDebugEvent.hh"
#include "TestResult.hh"
#include "TestStream.hh"
#include "Base/Code/CodeLink.hh"
#include "Base/Debug/DebOut.hh"
namespace Test {
namespace Checksum {
namespace Debug {
namespace {
// put test checksum tag and separators in the required format
// Counts the number of occurrences of some event and records the
// result in the text log file when the object is destroyed.
struct Count : public LogValueT<size_t>
void Event::record(const std::string& _evnt, const Base::CodeLink& _lnk)
{
size_t nmbr_; // Number of errors.
Result bad_res_; // Error to record if nmbr_ is bigger than 0.
Count(const char* _name, const Result _res)
: LogValueT<size_t>(_name), nmbr_(0), bad_res_(_res) {}
~Count()
{
if (nmbr_ > 0)
record(bad_res_, nmbr_);
}
};
Result res(name() == ::Debug::ERROR ? Result::ERROR : Result::WARNING);
stream_out() << res << " " << name() << "#" << nmbr_++ << ": " << _evnt
<< _lnk << std::endl;
}
// This function is intended to count the occurrences of error and warnings with
// the goal to log them at the end of the test.
void checksum_count_add(const bool _err)
void Event::record_number() const
{
stream_out(); // Ensure that the static stream output object has been created.
// This force the destructor of cnt_err and cnt_warn to be called
// stream destructor.
static Count cnt_err(Debug::ERROR, Result::ERROR);
static Count cnt_warn(Debug::WARNING, Result::WARNING);
if (_err)
++cnt_err.nmbr_;
else
++cnt_warn.nmbr_;
Result res(nmbr_ == 0 ? Result::OK : // the checksum will appear in all cases
(name() == ::Debug::ERROR ? Result::ERROR : Result::WARNING));
stream_out() << res << " " << name() << " total#: " << nmbr_ << std::endl;
}
}//namespace
Severity Event::compare(
IStream& _str0,
IStream& _str1,
OStream& _os,
const Path* /*_dir0 */,
const Path* /*_dir1*/
) const
{
std::string line0, line1;
std::getline(_str0, (line0));
std::getline(_str1, (line1));
void checksum_count_add_warning()
{
checksum_count_add(false);
}
if (line0 == line1)
{
_os << line0 << std::endl;
return 0;
}
void checksum_count_add_error()
{
checksum_count_add(true);
}
_os << "Diff: L={"<< line0 << "}; R={" << line1 << "}" << std::endl;
return 1;
}
Event error(::Debug::ERROR);
Event warning(::Debug::WARNING);
}//namespace Debug
}//Checksum
}//namespace Test
......
......@@ -11,20 +11,47 @@
#ifndef BASE_CHECKSUMCOUNT_HH_INCLUDE
#define BASE_CHECKSUMCOUNT_HH_INCLUDE
#include <Base/Debug/DebOut.hh>
#include <Base/Test/IChecksum.hh>
#if defined(TEST_ON) && defined(DEB_ON)
// The functions in this file are used to count the number of errors and warnings
// and makes sense only if both the debug and test macro are on.
namespace Base {
struct CodeLink;
}//namespace Base
namespace Test {
namespace Checksum {
namespace Debug {
class Event : public IChecksum
{
public:
Event(const char* _name) : IChecksum(_name), nmbr_(0) {}
virtual void record(const std::string& _evnt, const Base::CodeLink& _lnk);
virtual Severity compare(
IStream& _str0, //!<[in] First stream with checksum data
IStream& _str1, //!<[in] Second stream with checksum data
OStream& _os, //!<[out] Description of the difference.
const Path* _dir0 = nullptr, //!<[in] FIrst test directory
const Path* _dir1 = nullptr //!<[in] Second test directory
) const;
virtual void record_number() const;
/*!Tells to the test system that there has been a debug warning*/
void checksum_count_add_warning();
protected:
int nmbr_;
};
/*!Tells to the test system that there has been a debug error*/
void checksum_count_add_error();
extern Event error;
extern Event warning;
}//namespace Debug
}//namespace Checksum
}//namespace Test
......
......@@ -13,6 +13,7 @@
#include "ChecksumFile.hh"
#include <boost/functional/hash.hpp>
#include <boost/filesystem.hpp>
#include <fstream>
......@@ -20,7 +21,10 @@
namespace Test {
namespace Checksum {
File::File(const char* _name) : LogValueT<std::string>(_name) {}
File::File(std::string _name)
: LogValueT<std::string>((_name += File::tag()).c_str()),
mod_chksm_name_(std::move(_name))
{}
void File::record(const char* _flnm)
{
......@@ -43,6 +47,109 @@ void File::record(const char* _flnm)
LogValueT<std::string>::record(Result::OK, log_val);
}
namespace {
namespace fs = boost::filesystem;
/*! Compares two files. First compare their size. If the seize is the same finds
out if they are bitwise equal.
*/
struct CompareTwoFiles
{
CompareTwoFiles(const Path& _flnm_0, const Path& _flnm_1)
{
if (!fs::is_regular_file(_flnm_0) || !fs::is_regular_file(_flnm_1))
sizes_[0] = sizes_[1] = 0;
else
{
sizes_[0] = fs::file_size(_flnm_0);
sizes_[1] = fs::file_size(_flnm_1);
paths_[0] = _flnm_0;
paths_[1] = _flnm_1;
}
}
size_t size(const size_t _ind) const { return sizes_[_ind]; }
bool same_size() const { return sizes_[0] == sizes_[1]; }
double size_difference() const
{
return double(sizes_[1]) - double(sizes_[0]);
}
bool bitwise_equal() const
{
if (!valid() || !same_size())
return false;
std::array<char, 100> buff_a, buff_b;
std::ifstream str_a(paths_[0].string());
std::ifstream str_b(paths_[1].string());
bool bit_wise_eq = true;
while (bit_wise_eq)
{
bool eof_a = !str_a.read(buff_a.data(), buff_a.size());
bool eof_b = !str_b.read(buff_b.data(), buff_b.size());
if (eof_a != eof_b)
bit_wise_eq = false;
else if (str_a.gcount() != str_b.gcount())
bit_wise_eq = false;
else
bit_wise_eq = std::memcmp(buff_a.data(), buff_b.data(), str_a.gcount()) == 0;
if (eof_a)
break;
}
return bit_wise_eq;
}
bool valid() const { return sizes_[0] > 0 || sizes_[1] > 0; }
private:
boost::filesystem::path paths_[2];
size_t sizes_[2];
};
}//namespace
Severity File::compare(IStream& _str0, IStream& _str1, OStream& _os,
const Path* _dir0, const Path* _dir1) const
{
Path path0, path1;
_str0 >> path0;
_str1 >> path1;
if (path0 != path1)
{
_os << "Different file names: " << path0 << ", " << path1;
return 2;
}
if (_dir0 == nullptr || _dir1 == nullptr)
return 0;
CompareTwoFiles cmp(*_dir0 / path0, *_dir1 / path0);
if (cmp.bitwise_equal())
return 0;
_os << "Diff in " << path0;
if (!cmp.valid())
{
_os << " files not found";
if (cmp.size(0) == cmp.size(1)) {}
else if (cmp.size(0) == 0)
_os << " in left suite!";
else
_os << " in right suite!";
return 1;
}
_os << ", SizeDiff = " << cmp.size_difference();
return 1;
}
}//namespace Checksum
}//namespace Test
......
......@@ -23,9 +23,19 @@ checksum for output files. It has a method record that add a file hash.
class File : public LogValueT<std::string>
{
public:
File(const char* _name); //!<[in] Checksum name.
File(std::string _name); /*!<[in] Checksum name root.
Checksum name will be _name + File::tag() */
void record(const char* _flnm);
virtual Severity compare(IStream& _str0, IStream& _str1, OStream& _os,
const Path* _dir0, const Path* _dir1) const;
static const char* tag() { return "-file"; }
private:
std::string mod_chksm_name_;
};
......
......@@ -34,6 +34,31 @@ std::ostream& operator<<(std::ostream& _out_str, const std::vector<ValueT>& _val
return write_container(_out_str, _vals);
}
#define ARITHMETICTYPE(ValueT) \
typename std::enable_if<std::is_arithmetic<ValueT>::value, ValueT>::type
#define NOTARITHMETICTYPE(ValueT) \
typename std::enable_if<!std::is_arithmetic<ValueT>::value, ValueT>::type
// Arithmetic types prints the value difference.
template <typename ValueT> void print_values(OStream& _os,
const ARITHMETICTYPE(ValueT)& _a,
const ARITHMETICTYPE(ValueT)& _b)
{
_os << "Diff: " << double(_b) - double(_a) << ", L = " << _a << ", R = " << _b;
}
// Not arithmetic types prints the two value.
template <typename ValueT> void print_values(OStream& _os,
const NOTARITHMETICTYPE(ValueT)& _a,
const NOTARITHMETICTYPE(ValueT)& _b)
{
_os << _a << " , " << _b;
}
#undef NOTARITHMETICTYPE
#undef ARITHMETICTYPE
}//namespace
// Class LogValueT
......@@ -44,28 +69,18 @@ LogValueT<ValueT, CompareT>::LogValueT(const char* _name, const CompareT& _comp)
{}
template <typename ValueT, class CompareT>
Severity LogValueT<ValueT, CompareT>::compare(const Path& _dir0,
const Path& _dir1, OStream& _os) const
Severity LogValueT<ValueT, CompareT>::compare(IStream& _str0, IStream& _str1,
OStream& _os,
const Path*, const Path*) const
{
auto list0 = read_values<ValueT>("", "", _dir0);
auto list1 = read_values<ValueT>("", "", _dir1);
if (list0.size() != list1.size())
{
_os << '#' << list0.size() << " #" << list1.size();
return 1;
}
for (auto i = list0.size(); i-- > 0; )
{
if (comp_.same(list0[i], list1[i]))
{
list0.erase(list0.begin() + i);
list1.erase(list1.begin() + i);
}
}
if (list0.empty() && list1.empty())
ValueT val[2];
_str0 >> val[0];
_str1 >> val[1];
if (val[0] == val[1])
return 0;
_os << list0 << " " << list1;
return 0.5;
print_values<ValueT>(_os, val[0], val[1]);
return 1;
}
template <typename ValueT, class CompareT>
......
......@@ -63,8 +63,10 @@ public:
const CompareT& _comp = CompareT() //!<[in] Comparison function.
);
void record(const Result& _rep_res, const ValueT& _val);
virtual Severity compare(const Path& _dir0, const Path& _dir1, OStream& _os) const;
void record(const Result& _rep_res, const ValueT& _val);
virtual Severity compare(IStream& _str0, IStream& _str1, OStream& _os,
const Path* _dir0 = nullptr, const Path* _dir1 = nullptr) const;
private:
CompareT comp_; // Compare class.
......
......@@ -3,12 +3,7 @@
#include "IChecksum.hh"
#include <boost/filesystem.hpp>
#include <array>
#include <iostream>
#include <tuple>
#include <vector>
namespace Test {
namespace Checksum {
......
......@@ -40,12 +40,15 @@ public:
/*!
Override compare to perform a comparison of the results stored in
directories _dir0 and _dir1.
Returns an estimation of the difference between the two test run.
Returns an estimation of the difference between the two test run and
a description of the difference.
*/
virtual Severity compare(
const Path& _dir0, //!< [in] Directory with the reference result
const Path& _dir1, //!< [in] Directory with the new result
OStream& _os //!< [out] Description of the difference.
IStream& _str0, //!<[in] First stream with checksum data
IStream& _str1, //!<[in] Second stream with checksum data
OStream& _os, //!<[out] Description of the difference.
const Path* _dir0 = nullptr, //!<[in] FIrst test directory
const Path* _dir1 = nullptr //!<[in] Second test directory
) const = 0;
protected:
......
......@@ -27,11 +27,14 @@ warnings reported, etc. Hence it is more future-proof than an enum.
class Result
{
public:
enum Type
enum Type // keep descriptions updated.
{
OK,
OK,
WARNING,
ERROR
ERROR,
FAILURE,
CRASH,
HANG
};
public:
......@@ -39,28 +42,34 @@ public:
// Short Result description!
template <class StreamT>
friend inline StreamT& operator<<(StreamT& _os, const Result& _rslt)
friend inline StreamT& operator>>(StreamT& _is, Result& _rslt)
{
switch (_rslt.type())
char c;
_is >> c;
size_t descr_nmbr;
auto descr = descriptions(&descr_nmbr);
for (size_t i = 0; i < descr_nmbr; ++i)
{
case OK : _os << " "; break;
case WARNING : _os << "?"; break;