Checksum.cc 4.24 KB
Newer Older
1
// (C) Copyright 2019 by Autodesk, Inc.
2
3
4
5

#ifdef TEST_ON

#include "Checksum.hh"
6
#include "Base/Debug/DebCallStack.hh"
7
8
#include <fstream>
#include <iostream>
9
#include <mutex>
10
11
12
13

namespace Test {
namespace Checksum {

14
Level run_lvl = L_NONE;
15

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
namespace {

Registry& registry_modify()
{
  static Registry chksm_reg;
  return chksm_reg;
}

}//namespace

const Registry& registry()
{
  return registry_modify();
}

///////////////////////////////////////////////////////////////////////////////
// class Checksum implementation

34
Object::Object(const char* const _name, const Level _lvl)
35
  : lvl_(_lvl), name_(_name)
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
{
  auto pos = registry_modify().emplace(name_, this);
  if (!pos.second)
  {
    std::cout << "Duplicate checksum definition: " << _name << std::endl;
    throw;
  }
}

Difference Object::compare_data(const String& _old, const String& _new) const
{
  if (_old == _new)
    return Difference::EQUAL;

  String diff;
  diff.resize((std::max(_old.length(), _new.length())));
  for (int i = 0; i < diff.size(); ++i)
  {
    diff[i] = i < _old.length() && i < _new.length() && _old[i] == _new[i] ?
      ' ' : '*';
  }
  return Difference(Difference::UNKNOWN, diff);
}

Difference Object::compare(
  const Path& /*_old_path*/,
  const Record& _old_rcrd,
  const Path& /*_new_path*/,
  const Record& _new_rcrd
  ) const
{
  const auto old_rslt_type = _old_rcrd.rslt.type();
  const auto new_rslt_type = _new_rcrd.rslt.type();
  auto data_diff = compare_data(_old_rcrd.data, _new_rcrd.data);
  if (old_rslt_type == new_rslt_type) // same result, so just data compare
    return data_diff;

  // result types are different, qualify the difference
#define DIFFERENCE(TYPE) data_diff += Difference(Difference::TYPE)
  switch (old_rslt_type)
  {
77
78
  case Result::OK: 
    switch (new_rslt_type)
79
    {
80
81
82
83
84
    case Result::WARNING: DIFFERENCE(SUSPICIOUS); break;
    case Result::ERROR: DIFFERENCE(REGRESSED); break;
    default: DIFFERENCE(FAILED); break; // FAILURE, CRASH, HANG
    };
    break;
85
  case Result::WARNING : 
86
    switch (new_rslt_type)
87
    {
88
89
90
91
92
93
94
    case Result::OK: DIFFERENCE(IMPROVED); break;
    case Result::ERROR: DIFFERENCE(REGRESSED); break;
    default: DIFFERENCE(FAILED); break; // FAILURE, CRASH, HANG
    };
    break;
  case Result::ERROR : 
    switch (new_rslt_type)
95
    {
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
    case Result::OK:
    case Result::WARNING: DIFFERENCE(IMPROVED); break;
    default: DIFFERENCE(FAILED); break; // FAILURE, CRASH, HANG
    };
    break;
  case Result::FAILURE: 
    switch (new_rslt_type)
    {
    // worked with or w/o issues, now fails
    case Result::OK:
    case Result::WARNING: 
    case Result::ERROR: DIFFERENCE(WORKED); break;
    // gracious failure replaced by HANG or CRASH?!
    default: DIFFERENCE(FAILED); break; // CRASH, HANG
    };
    break;
  case Result::CRASH: 
    switch (new_rslt_type)
    {
    case Result::OK:
    case Result::WARNING: 
    case Result::ERROR: DIFFERENCE(WORKED); break;
    // CRASH replaced by gracious failure!
    case Result::FAILURE: DIFFERENCE(IMPROVED); break; 
    default: DIFFERENCE(FAILED); break; // CRASH replaced by HANG?!
    };
    break;
  case Result::HANG: 
    switch (new_rslt_type)
    {
    case Result::OK:
    case Result::WARNING: 
    case Result::ERROR: DIFFERENCE(WORKED); break;
    // HANG replaced by gracious failure!
    case Result::FAILURE: DIFFERENCE(IMPROVED); break; 
    case Result::CRASH: DIFFERENCE(SUSPICIOUS); break; // HANG is now CRASH!
132
    default: ; // disable warnings
133
134
    };
    break;
135
  }
136
  return data_diff;
137
138
139
140
}

void Object::add(const Result& _rslt, const String& _data)
{
141
142
143
  static std::mutex mtx; //synchronize access to the checksum report stream
  std::lock_guard<std::mutex> lock(mtx);

144
  static Base::OutputStreamAdaptT<std::ofstream> test_strm(REPORT_FILENAME);
145
  static bool tag_out = false;
146
147

#ifdef DEB_ON
148
149
150
  static String prev_call_stck;
  String call_stck("/");
  Debug::CallStack::query().append(call_stck);
151

152
153
  if (prev_call_stck != call_stck)
  {
Martin Marinov's avatar
Martin Marinov committed
154
    test_strm << call_stck << ::Base::ENDL;
155
156
    prev_call_stck = call_stck;
  }
157
#endif//DEB_ON
158

159
160
161
  if (!tag_out)
  {
    tag_out = true;
Martin Marinov's avatar
Martin Marinov committed
162
    test_strm << REPORT_LEVEL_TAG << LEVEL_TEXT[run_lvl] << ::Base::ENDL;
163
  }
Martin Marinov's avatar
Martin Marinov committed
164
  test_strm << _rslt << "   " << name() << ": " << _data << ::Base::ENDL;
165
  test_strm.stream().flush();
166
167
168
169
170
171
}

}//Checksum
}//namespace Test

#endif//TEST_ON