Skip to content

Commit ffe202d

Browse files
author
Lukasz A.J. Wrona
committed
JSON equality operator and tests
1 parent c24ff8a commit ffe202d

File tree

3 files changed

+156
-0
lines changed

3 files changed

+156
-0
lines changed

src/util/json.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ Author: Daniel Kroening, [email protected]
77
\*******************************************************************/
88

99
#include "json.h"
10+
#include <util/narrow.h>
1011

1112
#include <ostream>
13+
#include <algorithm>
1214

1315
const jsont jsont::null_json_object(jsont::kindt::J_NULL);
1416

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

src/util/json.h

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

461+
bool operator==(const jsont &left, const jsont &right);
462+
461463
#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][test-gen-util][state][type]")
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)