93 lines
3.6 KiB
C++
93 lines
3.6 KiB
C++
#include "zeroerr/assert.h"
|
|
#include "zeroerr/unittest.h"
|
|
|
|
#include "common/Json.h"
|
|
#include "common/Value.h"
|
|
|
|
#include <cmath>
|
|
#include <limits>
|
|
#include <type_traits>
|
|
|
|
using eve::Value;
|
|
|
|
TEST_CASE("value.json_round_trip_preserves_all_supported_kinds") {
|
|
Value::Array array;
|
|
array.emplace_back();
|
|
array.emplace_back(true);
|
|
array.emplace_back(std::int64_t{-7});
|
|
array.emplace_back(1.25);
|
|
array.emplace_back("line\n中🚀");
|
|
|
|
Value value(Value::Object{{"z", "last"}, {"a", Value(std::move(array))}});
|
|
auto encoded = value.toJson();
|
|
REQUIRE(encoded.ok());
|
|
CHECK_EQ(encoded.value(), R"({"a":[null,true,-7,1.25,"line\n中🚀"],"z":"last"})");
|
|
|
|
auto parsed = Value::fromJson(encoded.value());
|
|
REQUIRE(parsed.ok());
|
|
CHECK(parsed.value() == value);
|
|
}
|
|
|
|
TEST_CASE("value.object_order_and_numeric_kinds_are_deterministic") {
|
|
auto parsed = Value::fromJson(R"({"z":9223372036854775807,"a":1.0,"negativeZero":-0.0})");
|
|
REQUIRE(parsed.ok());
|
|
const Value::Object* object = parsed.value().getIf<Value::Object>();
|
|
REQUIRE(object != nullptr);
|
|
CHECK(object->find("z")->second.getIf<std::int64_t>() != nullptr);
|
|
CHECK(object->find("a")->second.getIf<double>() != nullptr);
|
|
const double* negativeZero = object->find("negativeZero")->second.getIf<double>();
|
|
REQUIRE(negativeZero != nullptr);
|
|
CHECK(std::signbit(*negativeZero));
|
|
|
|
auto encoded = parsed.value().toJson();
|
|
REQUIRE(encoded.ok());
|
|
CHECK_EQ(encoded.value(), R"({"a":1.0,"negativeZero":-0.0,"z":9223372036854775807})");
|
|
}
|
|
|
|
TEST_CASE("value_uses_the_common_json_parser_and_serializer") {
|
|
std::string error;
|
|
eve::json::Document document =
|
|
eve::json::Document::parse(R"({"large":9223372036854775807,"fraction":1.0})", &error);
|
|
REQUIRE(document.valid());
|
|
CHECK(document.root().get("large").isIntegerLiteral());
|
|
CHECK(document.root().get("large").isInt64());
|
|
CHECK_EQ(document.root().get("large").asInt64(), std::int64_t{9223372036854775807});
|
|
CHECK(!eve::json::Document::parse(R"({"x":1,"x":2})").valid());
|
|
CHECK(!eve::json::Document::parse("Infinity").valid());
|
|
|
|
Value value = Value::fromJson(R"({"z":2,"a":1})").expect("value parse");
|
|
auto commonJson = eve::json::stringify(value);
|
|
REQUIRE(commonJson.ok());
|
|
CHECK_EQ(commonJson.value(), R"({"a":1,"z":2})");
|
|
auto valueJson = value.toJson();
|
|
REQUIRE(valueJson.ok());
|
|
CHECK_EQ(valueJson.value(), commonJson.value());
|
|
}
|
|
|
|
TEST_CASE("value.rejects_duplicate_keys_invalid_json_and_non_finite_numbers") {
|
|
CHECK(!Value::fromJson(R"({"x":1,"x":2})").ok());
|
|
CHECK(!Value::fromJson(R"([1,])").ok());
|
|
CHECK(!Value::fromJson("1e9999").ok());
|
|
CHECK(!Value::fromJson("NaN").ok());
|
|
|
|
auto nan = Value(std::numeric_limits<double>::quiet_NaN()).toJson();
|
|
CHECK(!nan.ok());
|
|
CHECK_EQ(static_cast<int>(nan.code()), static_cast<int>(eve::StatusCode::Failed));
|
|
REQUIRE(nan.error() != nullptr);
|
|
CHECK_EQ(static_cast<int>(nan.error()->code()), static_cast<int>(eve::DiagnosticCode::SerializationError));
|
|
|
|
auto infinity = Value(std::numeric_limits<double>::infinity()).toJson();
|
|
CHECK(!infinity.ok());
|
|
CHECK_EQ(static_cast<int>(infinity.error()->code()), static_cast<int>(eve::DiagnosticCode::SerializationError));
|
|
}
|
|
|
|
TEST_CASE("presentation_value_is_the_common_value_without_a_second_storage") {
|
|
static_assert(std::is_same_v<eve::Value, eve::Value>);
|
|
eve::Value value(eve::Value::Object{{"count", 4}});
|
|
auto encoded = value.toJson();
|
|
REQUIRE(encoded.ok());
|
|
auto parsed = eve::Value::fromJson(encoded.value());
|
|
REQUIRE(parsed.ok());
|
|
CHECK(parsed.value() == value);
|
|
}
|