Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions libs/common/include/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,4 +427,10 @@ class Value final {
bool operator==(Value const& lhs, Value const& rhs);
bool operator!=(Value const& lhs, Value const& rhs);

bool operator==(Value::Array const& lhs, Value::Array const& rhs);
bool operator!=(Value::Array const& lhs, Value::Array const& rhs);

bool operator==(Value::Object const& lhs, Value::Object const& rhs);
bool operator!=(Value::Object const& lhs, Value::Object const& rhs);

} // namespace launchdarkly
16 changes: 16 additions & 0 deletions libs/common/src/value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,20 @@ bool operator!=(Value const& lhs, Value const& rhs) {
return !(lhs == rhs);
}

bool operator==(Value::Array const& lhs, Value::Array const& rhs) {
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

bool operator!=(Value::Array const& lhs, Value::Array const& rhs) {
return !(lhs == rhs);
}

bool operator==(Value::Object const& lhs, Value::Object const& rhs) {
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

bool operator!=(Value::Object const& lhs, Value::Object const& rhs) {
return !(lhs == rhs);
}

} // namespace launchdarkly
69 changes: 69 additions & 0 deletions libs/common/tests/value_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,4 +269,73 @@ TEST(ValueTests, ToBoostJson) {
EXPECT_EQ("ham", boost_arr.as_array().at(3).as_object().at("string"));
}

TEST(ValueTests, ArrayEquality) {
std::vector<Value::Array> arrays = {
{"foo", "bar", "baz"},
{1, 2, 3},
{1.1, 2.2, 3.3},
{true, false},
{true, 1, 3.14, "qux", Value::Array({"foo", "bar"})}};

for (auto const& a : arrays) {
ASSERT_TRUE(a == a);
ASSERT_FALSE(a != a);
}
}

TEST(ValueTests, ArrayInequality) {
std::vector<std::pair<Value::Array, Value::Array>> arrays = {
{{"foo"}, {"bar"}},
{{"foo"}, {"foo", "foo"}},
{{1}, {"foo"}},
{
{3.14},
{3},
},
{{true}, {false}},
{{"foo", "bar"}, {"bar", "foo"}}};

for (auto const& pair : arrays) {
ASSERT_NE(pair.first, pair.second);
}
}

TEST(ValueTests, ObjectEqualityOrderDoesNotMatter) {
std::vector<Value::Object> objects = {
{{"foo", 1}, {"bar", 2}, {"baz", 3}},
{{"foo", 1}, {"baz", 3}, {"bar", 2}},
{{"bar", 2}, {"foo", 1}, {"baz", 3}},
{{"bar", 2}, {"baz", 3}, {"foo", 1}},
{{"baz", 3}, {"bar", 2}, {"foo", 1}},
{{"baz", 3}, {"foo", 1}, {"bar", 2}},
};

for (auto const& a : objects) {
for (auto const& b : objects) {
ASSERT_TRUE(a == b);
ASSERT_FALSE(a != b);
}
}
}

TEST(ValueTests, ObjectInequality) {
std::vector<std::pair<Value::Object, Value::Object>> objects = {
// Different keys, same values
{Value::Object({{"foo", true}}), Value::Object({{"bar", true}})},
// Same keys, different values
{Value::Object({{"foo", true}}), Value::Object({{"foo", false}})},
// Different number of keys
{Value::Object({{"foo", true}, {"bar", true}}),
Value::Object({{"foo", true}})},
// Same key, but values are arrays with different orderings
{Value::Object({{"foo", Value({"foo", "bar"})}}),
Value::Object({{"foo", Value({"bar", "foo"})}})},

};

for (auto const& pair : objects) {
ASSERT_NE(pair.first, pair.second);
}
}

// NOLINTEND cppcoreguidelines-avoid-magic-numbers