JsonComparer.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * JsonComparer.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "JsonComparer.h"
  12. #include "../lib/ScopeGuard.h"
  13. //JsonComparer
  14. JsonComparer::JsonComparer(bool strict_)
  15. : strict(strict_)
  16. {
  17. }
  18. vstd::ScopeGuard<JsonComparer::TScopeGuard> JsonComparer::pushName(const std::string & name)
  19. {
  20. namePath.push_back(name);
  21. return vstd::makeScopeGuard<TScopeGuard>([this](){namePath.pop_back();});
  22. }
  23. std::string JsonComparer::buildMessage(const std::string & message)
  24. {
  25. std::stringstream buf;
  26. for(auto & s : namePath)
  27. buf << s << "|";
  28. buf << " " << message;
  29. return buf.str();
  30. }
  31. bool JsonComparer::isEmpty(const JsonNode & value)
  32. {
  33. switch (value.getType())
  34. {
  35. case JsonNode::JsonType::DATA_NULL:
  36. return true;
  37. case JsonNode::JsonType::DATA_BOOL:
  38. return !value.Bool();
  39. case JsonNode::JsonType::DATA_FLOAT:
  40. return vstd::isAlmostEqual(value.Float(), 0.0);
  41. case JsonNode::JsonType::DATA_INTEGER:
  42. return value.Integer() == 0;
  43. case JsonNode::JsonType::DATA_STRING:
  44. return value.String() == "";
  45. case JsonNode::JsonType::DATA_VECTOR:
  46. return value.Vector().empty();
  47. case JsonNode::JsonType::DATA_STRUCT:
  48. return value.Struct().empty();
  49. break;
  50. default:
  51. EXPECT_TRUE(false) << "Unknown Json type";
  52. return false;
  53. }
  54. }
  55. void JsonComparer::check(const bool condition, const std::string & message)
  56. {
  57. if(!condition)
  58. {
  59. if(strict)
  60. {
  61. GTEST_FAIL() << buildMessage(message);
  62. }
  63. else
  64. {
  65. ADD_FAILURE() << buildMessage(message);
  66. }
  67. }
  68. }
  69. void JsonComparer::checkEqualInteger(const si64 actual, const si64 expected)
  70. {
  71. if(actual != expected)
  72. {
  73. check(false, boost::str(boost::format("actual: '%d' ,expected: '%d'") % actual % expected));
  74. }
  75. }
  76. void JsonComparer::checkEqualFloat(const double actual, const double expected)
  77. {
  78. if(std::abs(actual - expected) > 1e-8)
  79. {
  80. check(false, boost::str(boost::format("actual: '%lf' ,expected: '%lf' (diff %lf)") % actual % expected % (expected - actual)));
  81. }
  82. }
  83. void JsonComparer::checkEqualString(const std::string & actual, const std::string & expected)
  84. {
  85. if(actual != expected)
  86. {
  87. check(false, boost::str(boost::format("actual: '%s' , expected: '%s'") % actual % expected));
  88. }
  89. }
  90. void JsonComparer::checkEqualJson(const JsonMap & actual, const JsonMap & expected)
  91. {
  92. for(const auto & p : expected)
  93. checkStructField(actual, p.first, p.second);
  94. for(const auto & p : actual)
  95. checkExcessStructField(p.second, p.first, expected);
  96. }
  97. void JsonComparer::checkEqualJson(const JsonVector & actual, const JsonVector & expected)
  98. {
  99. check(actual.size() == expected.size(), "size mismatch");
  100. size_t sz = std::min(actual.size(), expected.size());
  101. for(size_t idx = 0; idx < sz; idx ++)
  102. {
  103. auto guard = pushName(std::to_string(idx));
  104. checkEqualJson(actual.at(idx), expected.at(idx));
  105. }
  106. }
  107. void JsonComparer::checkEqualJson(const JsonNode & actual, const JsonNode & expected)
  108. {
  109. //name has been pushed before
  110. const bool validType = actual.getType() == expected.getType();
  111. //do detail checks avoiding assertions in JsonNode
  112. if(validType)
  113. {
  114. switch (actual.getType())
  115. {
  116. case JsonNode::JsonType::DATA_NULL:
  117. break; //do nothing
  118. case JsonNode::JsonType::DATA_BOOL:
  119. check(actual.Bool() == expected.Bool(), "mismatch");
  120. break;
  121. case JsonNode::JsonType::DATA_FLOAT:
  122. checkEqualFloat(actual.Float(),expected.Float());
  123. break;
  124. case JsonNode::JsonType::DATA_STRING:
  125. checkEqualString(actual.String(),expected.String());
  126. break;
  127. case JsonNode::JsonType::DATA_VECTOR:
  128. checkEqualJson(actual.Vector(), expected.Vector());
  129. break;
  130. case JsonNode::JsonType::DATA_STRUCT:
  131. checkEqualJson(actual.Struct(), expected.Struct());
  132. break;
  133. case JsonNode::JsonType::DATA_INTEGER:
  134. checkEqualInteger(actual.Integer(), expected.Integer());
  135. break;
  136. default:
  137. check(false, "Unknown Json type");
  138. break;
  139. }
  140. }
  141. else if(actual.isNumber() && expected.isNumber())
  142. {
  143. checkEqualFloat(actual.Float(),expected.Float());
  144. }
  145. else
  146. {
  147. check(false, "type mismatch. \n expected:\n"+expected.toCompactString()+"\n actual:\n" +actual.toCompactString());
  148. }
  149. }
  150. void JsonComparer::checkExcessStructField(const JsonNode & actualValue, const std::string & name, const JsonMap & expected)
  151. {
  152. auto guard = pushName(name);
  153. if(!vstd::contains(expected, name))
  154. check(isEmpty(actualValue), "excess");
  155. }
  156. void JsonComparer::checkStructField(const JsonMap & actual, const std::string & name, const JsonNode & expectedValue)
  157. {
  158. auto guard = pushName(name);
  159. if(!vstd::contains(actual, name))
  160. check(isEmpty(expectedValue), "missing");
  161. else
  162. checkEqualJson(actual.at(name), expectedValue);
  163. }
  164. void JsonComparer::compare(const std::string & name, const JsonNode & actual, const JsonNode & expected)
  165. {
  166. auto guard = pushName(name);
  167. checkEqualJson(actual, expected);
  168. }