Commit 975c301d authored by Marco Amagliani's avatar Marco Amagliani

submission of test system improvements in the main branch. Now it is able to...

submission of test system improvements in the main branch. Now it is able to create a baseline for test execution.

[git-p4: depot-paths = "//ReForm/ReForm/main/Base/": change = 13990]
parent bbf13645
......@@ -38,28 +38,26 @@
namespace Debug {
typedef unsigned int uint;
const int INVALID_LEVEL = -1;
const char* const ERROR = "ERROR";
const char* const WARNING = "WARNING";
class Stream;
class Command
struct Command
{
public:
enum CommandType
enum Type
{
END = 0x01,
END_LF = 0x03,
END_ERR = 0x07
};
Type cmd;
CommandType com_;
CommandType com() const
{
return com_;
}
Command(CommandType _com) : com_(_com) {}
Command(Type _cmd) : cmd(_cmd) {}
};
......@@ -84,19 +82,20 @@ public:
//! pass the output on the level or not?
bool pass(const int _lvl) const { return _lvl <= lvl_; }
Stream& stream(const int _warn = 0, const bool _print = true);
Stream& stream();
Command end() const { return Command(Command::CommandType::END); }
Command end_lf() const { return Command(Command::CommandType::END_LF); }
Command end_err() const { return Command(Command::CommandType::END_ERR); }
Command end() const { return Command::END; }
Command end_lf() const { return Command::END_LF; }
Command end_err() const { return Command::END_ERR; }
};
//! This is a private implementation for Stream
class File;
class Stream
{
public:
enum StreamType
enum Flags
{
APPEND = 0x01,
HTML = 0x02,
......@@ -104,21 +103,16 @@ public:
KEEP_OPEN = 0x08
};
private:
File* dfile_;
public:
File* dfile() const
{
return dfile_;
}
//! Constructor.
Stream(
const char* _file_name = nullptr, //!< [in] File name if file based.
const StreamType _type = APPEND //!< [in] bitsfield enum type identifier
) ;
const char* _flnm = nullptr, //!< [in] Filename if file based.
const uint _flags = APPEND //!< [in] bit-field type identifier
);
~Stream();
const char* string_out() const;
const std::string& string() const;
const char* c_str() const { return string().c_str(); }
Stream& print(const int);
Stream& print(const double);
......@@ -126,13 +120,18 @@ public:
Stream& print(const char);
Stream& print(const Command&);
//! Get the currently active Stream
static Stream& get_global(int _warn = 0);
private:
File* dfile_;
private:
// inhibit copy
Stream(const Stream&);
Stream& operator=(const Stream&);
File* dfile() const { return dfile_; }
friend class Enter;
friend class Controller;
};
Stream& operator<<(Stream& _ds, const int i);
......@@ -147,6 +146,10 @@ Stream& operator<<(Stream& _ds, const char* const s);
Stream& operator<<(Stream& _ds, const std::string& s);
Stream& operator<<(Stream& _ds, const Command& co);
inline Stream& operator<<(Stream& _ds, const Command::Type _cmd_type)
{
return _ds << Command(_cmd_type);
}
// Stream operator for std::vector<>
template< typename ElementT>
......@@ -189,6 +192,13 @@ Stream& operator<<(Stream& _ds, const std::pair<T0, T1>& _pair)
return _ds;
}
extern void warning(const std::string& _wrng, const char* const _fnct,
const char* const _file, const int _line);
extern void error(const std::string& _err, const char* const _fnct,
const char* const _file, const int _line);
}//namespace Debug
#define DEB_module(MODULE)
//TODO: This should use an atomic thread-safe static int(s)
......@@ -211,9 +221,11 @@ Stream& operator<<(Stream& _ds, const std::pair<T0, T1>& _pair)
#define DEB_warning(LL, AA) DEB_warning_if(true, LL, AA)
#define DEB_warning_if(CC, LL, AA) { if (deb.pass(LL) && (CC)) \
{ deb.stream(1) << "WARNING: " << AA << deb.end_lf(); } }
{ Debug::Stream strm; strm << AA; \
Debug::warning(strm.string(), __FUNCTION__, __FILE__, __LINE__); } }
#define DEB_error(AA) { deb.stream(2) << "ERROR: " << AA << deb.end_err(); }
#define DEB_error(AA) { Debug::Stream strm; strm << AA; \
Debug::error(strm.string(), __FUNCTION__, __FILE__, __LINE__); }
#define DEB_error_if(CC, AA) { if (CC) DEB_error(AA); }
// Stream does not fulfill ostream. If you want to exploit an existing
......@@ -223,8 +235,6 @@ Stream& operator<<(Stream& _ds, const std::pair<T0, T1>& _pair)
#define DEB_os_str(AA) \
dynamic_cast<std::ostringstream &&>((std::ostringstream() << AA )).str()
}//namespace Debug
#endif // DEB_ON
#endif // BASE_DEBOUT_HH_INCLUDED
......@@ -12,6 +12,8 @@
#include "DebDefault.hh"
#include "Base/Utils/ThrowError.hh"
#include "Base/Utils/Environment.hh"
#include "Base/Test/IChecksum.hh"
#include "Base/Test/ChecksumCount.hh"
#ifdef DEB_ON
......@@ -32,7 +34,9 @@
#define sprintf_s snprintf
#endif
namespace { // LOCAL_PROC
namespace {
// TODO: make this use std::string; check for html extension; case insensitive
bool is_html_filename(const char* const str)
{
if (str == nullptr) return false;
......@@ -41,6 +45,7 @@ bool is_html_filename(const char* const str)
++dot;
return (!strncmp(dot, "htm", 3)) || (!strncmp(dot, "HTM", 3)) ;
}
}
namespace Debug {
......@@ -159,7 +164,7 @@ public:
}; // endclass FunctionCallSequence
//////////////////////////////////////////////////////////////////////////
class CallStack
{
std::vector<FunctionCallSequence> calls_;
......@@ -223,78 +228,20 @@ public:
bool get_indent(std::string& _str, File* _dfile, const bool is_html);
}; // endclass CallStack
//////////////////////////////////////////////////////////////////////////
class File
{
private:
class module_stats
{
public:
int lev_; // Level set for this module
int col_; // Colour (24 bit RGB, MSB=Red) for this module's DEB_out
module_stats(int _lev = 0) : lev_(_lev), col_(0x808080) {}
~module_stats() {}
};
// We use this data to decide the debug level of a function in a file.
class FilterLevelSelector
{
public:
void add_file_string(const std::string& _str) { file_selct_strngs_.push_back(_str); }
void add_func_string(const std::string& _str) { func_selct_strngs_.push_back(_str); }
bool select_file(const char* _flnm) const
{
std::string flnm(_flnm);
const std::string root_dir("ReForm");
auto pos = flnm.rfind(root_dir);
if (pos != std::string::npos)
flnm = flnm.substr(pos + root_dir.size());
return search(flnm, file_selct_strngs_);
}
bool select_function(const char* _func) const
{
return search(_func, func_selct_strngs_);
}
private:
static bool search(const std::string& _name,
const std::list<std::string>& _sel_strings)
{
for (const auto& sel : _sel_strings)
{
if (_name.find(sel) != std::string::npos)
return true;
}
return false;
}
private:
std::list<std::string> file_selct_strngs_; // list of strings to be found inside the file name.
std::list<std::string> func_selct_strngs_; // list of strings to be found inside the function name.
};
Stream::StreamType type_;
int lev_;
int num_flush_;
int priority_; // Last permission granted
int indent_size_;
std::map<int, FilterLevelSelector> level_selc_map_; // A map filter_level ==> filter_selector
bool at_line_start_;
std::string current_;
std::string output_;
std::string file_name_;
std::fstream file_stream_;
std::string double_format_;
//std::string indent_string_;
Stream* deb_stream_;
CallStack call_stack_;
public:
File(const char* _flnm = nullptr,
const uint _flags = Stream::APPEND | Stream::RETAIN)
: flags_(_flags), lev_(5), num_flush_(0)
{
if (_flnm != nullptr)
read_debug_config();// TODO: not sure if this is the right location
set_filename(_flnm);
indent_size_ = 3;
at_line_start_ = false; // Don't want to indent header
}
CallStack& call_stack()
{
......@@ -303,19 +250,19 @@ public:
bool is_kept_open() const
{
return 0 != (type_ & Stream::StreamType::KEEP_OPEN);
return 0 != (flags_ & Stream::KEEP_OPEN);
}
bool is_html() const
{
return 0 != (type_ & Stream::StreamType::HTML);
return 0 != (flags_ & Stream::HTML);
}
bool is_retained() const
{
return 0 != (type_ & Stream::StreamType::RETAIN);
return 0 != (flags_ & Stream::RETAIN);
}
bool is_appended() const
{
return 0 != (type_ & Stream::StreamType::APPEND);
return 0 != (flags_ & Stream::APPEND);
}
// Only applies to HTML DEB_out
bool is_white_on_black() const
......@@ -331,6 +278,7 @@ public:
{
return file_stream_.is_open();
}
int priority() const
{
return priority_;
......@@ -340,15 +288,15 @@ public:
{
return false;
}
bool fork_to_cerr()
{
return true;
}
const char* file_name() const
const char* filename() const
{
if (this && (!file_name_.empty())) return file_name_.c_str();
if (this && (!flnm_.empty())) return flnm_.c_str();
return nullptr;
}
......@@ -356,7 +304,7 @@ public:
{
current_.clear();
output_.clear();
file_name_.clear();
flnm_.clear();
}
char prev_char() const
......@@ -366,7 +314,6 @@ public:
return '\0';
}
void indent(bool _full_text)
{
std::string str;
......@@ -488,7 +435,7 @@ public:
void print(const Command& _co)
{
switch (_co.com())
switch (_co.cmd)
{
case Command::END :
if (is_html()) print_direct("</FONT>");
......@@ -512,11 +459,6 @@ public:
}
}
Stream& stream()
{
return *deb_stream_;
}
// Append current asctime to given string
bool add_time(std::string& str)
{
......@@ -624,9 +566,9 @@ public:
bool date_header = true;
if (date_header)
{
if (!file_name_.empty())
if (!flnm_.empty())
{
str.append(file_name_);
str.append(flnm_);
str.append(" opened ");
}
add_time(str);
......@@ -642,14 +584,15 @@ public:
if (date_footer)
{
std::string str("\n");
if (!file_name_.empty()) str.append(file_name_);
if (!flnm_.empty()) str.append(flnm_);
str.append(" Closed: ");
add_time(str);
stream() << str << "\n";
str.append("\n");
print(str.c_str());
}
if (is_html())
stream().print("\n</BODY></HTML>", false);
print("\n</BODY></HTML>", false);
}
bool is_first_flush()
......@@ -662,7 +605,7 @@ public:
int res = 0;
if (!current_.empty())
{
const char* fname = file_name();
const char* fname = filename();
if ((fname != nullptr) || file_is_open())
{
if (!file_is_open())
......@@ -710,8 +653,7 @@ public:
} // endfunc flush
// Use with extreme caution.
const char * string_out() const
{ return current_.c_str(); }
const std::string& string() const { return current_; }
void close()
{
......@@ -719,11 +661,11 @@ public:
flush();
}
void set_file_name(const char* _name)
void set_filename(const char* _flnm)
{
file_name_ = _name ? _name : "";
if (is_html_filename(_name))
type_ = (Stream::StreamType)(type_ | Stream::StreamType::HTML);
flnm_ = _flnm != nullptr ? _flnm : "";
if (is_html_filename(_flnm))
flags_ = flags_ | Stream::HTML;
}
int permission(const char* const _flnm)
......@@ -746,18 +688,6 @@ public:
return at_line_start_;
}
File(
Stream* _deb_stream,
Stream::StreamType _type = (Stream::StreamType)(Stream::APPEND | Stream::RETAIN),
const char* _file_name = nullptr) :
type_(_type), lev_(5), num_flush_(0), deb_stream_(_deb_stream)
{
read_debug_config();
set_file_name(_file_name);
indent_size_ = 3;
at_line_start_ = false; // Don't want to indent header
}
void read_debug_config()
{
const auto flnm =
......@@ -797,20 +727,149 @@ public:
}
}
private:
// We use this data to decide the debug level of a function in a file.
class FilterLevelSelector
{
public:
void add_file_string(const std::string& _str) { file_selct_strngs_.push_back(_str); }
void add_func_string(const std::string& _str) { func_selct_strngs_.push_back(_str); }
bool select_file(const char* _flnm) const
{
std::string flnm(_flnm);
const std::string root_dir("ReForm");
auto pos = flnm.rfind(root_dir);
if (pos != std::string::npos)
flnm = flnm.substr(pos + root_dir.size());
return search(flnm, file_selct_strngs_);
}
bool select_function(const char* _func) const
{
return search(_func, func_selct_strngs_);
}
private:
static bool search(const std::string& _flnm,
const std::list<std::string>& _sel_strings)
{
for (const auto& sel : _sel_strings)
{
if (_flnm.find(sel) != std::string::npos)
return true;
}
return false;
}
private:
std::list<std::string> file_selct_strngs_; // list of strings to be found inside the file name.
std::list<std::string> func_selct_strngs_; // list of strings to be found inside the function name.
};
uint flags_;
int lev_;
int num_flush_;
int priority_; // Last permission granted
int indent_size_;
// A map filter_level ==> filter_selector
std::map<int, FilterLevelSelector> level_selc_map_;
bool at_line_start_;
std::string current_;
std::string output_;
std::string flnm_;
std::fstream file_stream_;
std::string double_format_;
//std::string indent_string_;
CallStack call_stack_;
}; // endclass File
//////////////////////////////////////////////////////////////////////////
namespace {
Stream& global_stream()
{
// TODO: Replace with a Singleton?? ThreadArray??
static Stream glbl_strm(Debug::Default::LOG_FILENAME);
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
// put test checksum tag and separators in the required format
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;
}
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;
}
#undef FUNCTION_IN_FILE
//////////////////////////////////////////////////////////////////////////
Enter::Enter(const char* const _flnm, const char* const _fnct,
int& _nmbr, int& _lvl)
: flnm_(_flnm), outs_(0), lns_(0)
{// TODO: for thread-safety we will need to make the constructor body atomic!
stream(0, false).dfile()->call_stack().add(_fnct, this);
global_stream().dfile()->call_stack().add(_fnct, this);
nmbr_ = _nmbr++;
if (_lvl == INVALID_LEVEL)
_lvl = Stream::get_global().dfile()->permission(flnm_);
_lvl = global_stream().dfile()->permission(flnm_);
lvl_ = _lvl;
static int id_cnt = 0;
......@@ -819,7 +878,7 @@ Enter::Enter(const char* const _flnm, const char* const _fnct,
Enter::~Enter()
{
File* impl = stream(0, false).dfile();
File* impl = global_stream().dfile();
impl->call_stack().pop();
std::string str;
......@@ -830,50 +889,47 @@ Enter::~Enter()
}
}
Stream& Enter::stream(const int _warn, const bool _print)
Stream& Enter::stream()
{
Stream& ds = Stream::get_global(_warn);
Stream& ds = global_stream();
File* impl = ds.dfile();
if (_print)
if (impl->is_html())
{
// bool is_deb_error = (_warn == 2);
// DEB_error font powerup goes here. BLINK is deprecated sadly.
// if (is_deb_error) impl->print_direct("<BLINK>");
const int col = 0xFF0000; // RED
char buffer[256];
sprintf_s(buffer, sizeof(buffer), "<FONT COLOR=\"#%06X\" SIZE=%i>",
col, impl->priority() + 1);
impl->print_direct(buffer);
}
if (outs_ < 1)
{
if (impl->is_html())
// First DEB_out in this function so output callstack, and flush.
impl->indent(true);
std::string str;
bool is_html = impl->is_html();
if (is_html)
{
// bool is_deb_error = (_warn == 2);
// DEB_error font powerup goes here. BLINK is deprecated sadly.
// if (is_deb_error) impl->print_direct("<BLINK>");
const int col = 0xFF0000; // RED
char buffer[256];
sprintf_s(buffer, sizeof(buffer), "<FONT COLOR=\"#%06X\" SIZE=%i>",
col, impl->priority() + 1);
impl->print_direct(buffer);
str.append("<FONT SIZE=2><u>");
impl->anchor(str, id_, "enter", true);
}