Skip to content

Commit 799768e

Browse files
author
Lukasz A.J. Wrona
committed
JSON equality operator and tests
Because it'd be useful to be able to compare whole JSON objects (for instance in unit tests)
1 parent 6ed1c12 commit 799768e

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed

src/util/json.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Author: Daniel Kroening, [email protected]
99
#include "json.h"
1010

1111
#include <ostream>
12+
#include <algorithm>
1213

1314
const jsont jsont::null_json_object(jsont::kindt::J_NULL);
1415

@@ -162,3 +163,44 @@ void jsont::swap(jsont &other)
162163
other.object.swap(object);
163164
other.value.swap(value);
164165
}
166+
167+
bool operator==(const jsont &left, const jsont &right)
168+
{
169+
if(left.kind != right.kind)
170+
return false;
171+
switch(left.kind)
172+
{
173+
case jsont::kindt::J_NULL:
174+
return true;
175+
case jsont::kindt::J_TRUE:
176+
return true;
177+
case jsont::kindt::J_FALSE:
178+
return true;
179+
case jsont::kindt::J_NUMBER:
180+
return left.value == right.value;
181+
case jsont::kindt::J_STRING:
182+
return left.value == right.value;
183+
case jsont::kindt::J_ARRAY:
184+
{
185+
const auto &left_array = static_cast<const json_arrayt &>(left);
186+
const auto &right_array = static_cast<const json_arrayt &>(right);
187+
return left_array.size() == right_array.size() &&
188+
std::equal(
189+
left_array.begin(), left_array.end(), right_array.begin());
190+
}
191+
case jsont::kindt::J_OBJECT:
192+
{
193+
const auto &left_object = static_cast<const json_objectt &>(left);
194+
const auto &right_object = static_cast<const json_objectt &>(right);
195+
if(left_object.size() != left_object.size())
196+
return false;
197+
return std::all_of(
198+
left_object.begin(),
199+
left_object.end(),
200+
[&](const std::pair<std::string, jsont> &pair) {
201+
return right_object[pair.first] == pair.second;
202+
});
203+
}
204+
}
205+
UNREACHABLE;
206+
}

src/util/json.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,4 +463,6 @@ inline const json_stringt &to_json_string(const jsont &json)
463463
return static_cast<const json_stringt &>(json);
464464
}
465465

466+
bool operator==(const jsont &left, const jsont &right);
467+
466468
#endif // CPROVER_UTIL_JSON_H

unit/json/json_parser.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,110 @@ SCENARIO("Loading JSON files")
133133
}
134134
}
135135
}
136+
137+
TEST_CASE("json equality", "[core][util][json]")
138+
{
139+
SECTION("null")
140+
{
141+
REQUIRE(jsont::null_json_object == jsont::null_json_object);
142+
}
143+
144+
SECTION("boolean")
145+
{
146+
REQUIRE(jsont::json_boolean(false) == jsont::json_boolean(false));
147+
REQUIRE(jsont::json_boolean(true) == jsont::json_boolean(true));
148+
REQUIRE_FALSE(jsont::json_boolean(true) == jsont::json_boolean(false));
149+
REQUIRE_FALSE(jsont::json_boolean(false) == jsont::null_json_object);
150+
}
151+
152+
SECTION("number")
153+
{
154+
REQUIRE(json_numbert("0") == json_numbert("0"));
155+
REQUIRE(json_numbert("1") == json_numbert("1"));
156+
REQUIRE(json_numbert("-1") == json_numbert("-1"));
157+
REQUIRE(json_numbert("1.578") == json_numbert("1.578"));
158+
REQUIRE_FALSE(json_numbert("0") == json_numbert("1"));
159+
REQUIRE_FALSE(json_numbert("1") == json_numbert("-1"));
160+
REQUIRE_FALSE(json_numbert("-1") == json_numbert("1"));
161+
REQUIRE_FALSE(json_numbert("1.578") == json_numbert("1.5789"));
162+
REQUIRE_FALSE(json_numbert("0") == jsont::json_boolean(false));
163+
REQUIRE_FALSE(jsont::json_boolean(false) == json_numbert("0"));
164+
REQUIRE_FALSE(json_numbert("0") == jsont::null_json_object);
165+
REQUIRE_FALSE(jsont::null_json_object == json_numbert("0"));
166+
}
167+
168+
SECTION("string")
169+
{
170+
REQUIRE(json_stringt("") == json_stringt(""));
171+
REQUIRE(json_stringt("foo") == json_stringt("foo"));
172+
REQUIRE(json_stringt("bar") == json_stringt("bar"));
173+
REQUIRE_FALSE(json_stringt("foo") == json_stringt("bar"));
174+
REQUIRE_FALSE(json_stringt("bar") == json_stringt("baz"));
175+
REQUIRE_FALSE(json_stringt("foo") == json_stringt("food"));
176+
REQUIRE_FALSE(json_stringt("1") == json_numbert("1"));
177+
REQUIRE_FALSE(json_stringt("true") == jsont::json_boolean("true"));
178+
REQUIRE_FALSE(json_stringt("") == jsont::json_boolean("false"));
179+
REQUIRE_FALSE(json_stringt("") == jsont::null_json_object);
180+
}
181+
182+
SECTION("array")
183+
{
184+
REQUIRE(json_arrayt{} == json_arrayt{});
185+
REQUIRE(
186+
json_arrayt{jsont::null_json_object} ==
187+
json_arrayt{jsont::null_json_object});
188+
REQUIRE(
189+
json_arrayt{json_numbert{"9"}, json_numbert{"6"}} ==
190+
json_arrayt{json_numbert{"9"}, json_numbert{"6"}});
191+
REQUIRE(
192+
json_arrayt{
193+
json_stringt{"foo"}, json_stringt{"bar"}, json_stringt{"baz"}} ==
194+
json_arrayt{
195+
json_stringt{"foo"}, json_stringt{"bar"}, json_stringt{"baz"}});
196+
197+
// different lengths
198+
REQUIRE_FALSE(
199+
json_arrayt{json_stringt{"foo"}, json_stringt{"bar"}} ==
200+
json_arrayt{
201+
json_stringt{"foo"}, json_stringt{"bar"}, json_stringt{"baz"}});
202+
// different elements
203+
REQUIRE_FALSE(
204+
json_arrayt{
205+
json_stringt{"foo"}, json_stringt{"bar"}, json_stringt{"foo"}} ==
206+
json_arrayt{
207+
json_stringt{"foo"}, json_stringt{"bar"}, json_stringt{"baz"}});
208+
// different kind
209+
REQUIRE_FALSE(json_arrayt{} == jsont::json_boolean(false));
210+
REQUIRE_FALSE(json_arrayt{} == jsont::null_json_object);
211+
}
212+
213+
SECTION("object")
214+
{
215+
REQUIRE(json_objectt{} == json_objectt{});
216+
REQUIRE(
217+
json_objectt{{"key", json_stringt{"value"}}} ==
218+
json_objectt{{"key", json_stringt{"value"}}});
219+
REQUIRE(
220+
json_objectt{{"key1", json_stringt{"value1"}},
221+
{"key2", json_stringt{"value2"}}} ==
222+
json_objectt{{"key1", json_stringt{"value1"}},
223+
{"key2", json_stringt{"value2"}}});
224+
225+
// Extra property
226+
REQUIRE_FALSE(
227+
json_objectt{{"key1", json_stringt{"value1"}},
228+
{"key2", json_stringt{"value2"}},
229+
{"key3", json_stringt{"value3"}}} ==
230+
json_objectt{{"key1", json_stringt{"value1"}},
231+
{"key2", json_stringt{"value2"}}});
232+
// different field values
233+
REQUIRE_FALSE(
234+
json_objectt{{"key1", json_stringt{"foo"}},
235+
{"key2", json_stringt{"bar"}}} ==
236+
json_objectt{{"key1", json_stringt{"foo"}},
237+
{"key2", json_stringt{"baz"}}});
238+
// different kind
239+
REQUIRE_FALSE(json_objectt{} == json_arrayt{});
240+
REQUIRE_FALSE(json_objectt{} == jsont::null_json_object);
241+
}
242+
}

0 commit comments

Comments
 (0)