Refactor
This commit is contained in:
119
tests/RuntimeJsonTests.cpp
Normal file
119
tests/RuntimeJsonTests.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "RuntimeJson.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
int gFailures = 0;
|
||||
|
||||
void Expect(bool condition, const char* message)
|
||||
{
|
||||
if (condition)
|
||||
return;
|
||||
|
||||
std::cerr << "FAIL: " << message << "\n";
|
||||
++gFailures;
|
||||
}
|
||||
|
||||
JsonValue ParseOrFail(const std::string& text, const char* message)
|
||||
{
|
||||
JsonValue value;
|
||||
std::string error;
|
||||
if (!ParseJson(text, value, error))
|
||||
{
|
||||
std::cerr << "FAIL: " << message << ": " << error << "\n";
|
||||
++gFailures;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void ExpectParseFails(const std::string& text, const char* message)
|
||||
{
|
||||
JsonValue value;
|
||||
std::string error;
|
||||
Expect(!ParseJson(text, value, error), message);
|
||||
Expect(!error.empty(), "failed parse should include an error message");
|
||||
}
|
||||
|
||||
void TestStringsAndEscaping()
|
||||
{
|
||||
const JsonValue value = ParseOrFail(R"({"text":"line\nquote:\" slash:\\ tab:\t"})", "escaped string parses");
|
||||
const JsonValue* text = value.find("text");
|
||||
Expect(text && text->isString(), "escaped string field is present");
|
||||
Expect(text && text->asString().find("line\nquote:\" slash:\\ tab:\t") != std::string::npos, "escaped string unescapes expected characters");
|
||||
|
||||
JsonValue controlString(std::string("a\001b", 3));
|
||||
Expect(SerializeJson(controlString, false) == R"("a\u0001b")", "serializer escapes raw control characters");
|
||||
ExpectParseFails(std::string("{\"bad\":\"a") + static_cast<char>(1) + "b\"}", "raw control characters are rejected");
|
||||
}
|
||||
|
||||
void TestUnicodeEscapes()
|
||||
{
|
||||
const JsonValue copyright = ParseOrFail(R"({"s":"\u00A9"})", "basic unicode escape parses");
|
||||
Expect(copyright.find("s") && copyright.find("s")->asString() == "\xC2\xA9", "basic unicode escape becomes UTF-8");
|
||||
|
||||
const JsonValue music = ParseOrFail(R"({"s":"\uD834\uDD1E"})", "surrogate pair parses");
|
||||
Expect(music.find("s") && music.find("s")->asString() == "\xF0\x9D\x84\x9E", "surrogate pair becomes UTF-8");
|
||||
|
||||
ExpectParseFails(R"({"s":"\uD834x"})", "unpaired high surrogate is rejected");
|
||||
ExpectParseFails(R"({"s":"\uDD1E"})", "unpaired low surrogate is rejected");
|
||||
ExpectParseFails(R"({"s":"\u00XZ"})", "invalid unicode hex is rejected");
|
||||
}
|
||||
|
||||
void TestNumbers()
|
||||
{
|
||||
const JsonValue value = ParseOrFail(R"({"a":0,"b":-12.5e+2,"c":3.25})", "valid numbers parse");
|
||||
Expect(value.find("a") && value.find("a")->asNumber(-1.0) == 0.0, "zero parses");
|
||||
Expect(value.find("b") && std::fabs(value.find("b")->asNumber() + 1250.0) < 0.0001, "exponent parses");
|
||||
Expect(value.find("c") && std::fabs(value.find("c")->asNumber() - 3.25) < 0.0001, "fraction parses");
|
||||
|
||||
ExpectParseFails("01", "leading zero is rejected");
|
||||
ExpectParseFails("1.", "fraction without digits is rejected");
|
||||
ExpectParseFails("1e", "exponent without digits is rejected");
|
||||
ExpectParseFails("1e9999", "non-finite number is rejected");
|
||||
}
|
||||
|
||||
void TestRoundtripAndMutation()
|
||||
{
|
||||
JsonValue root = JsonValue::MakeObject();
|
||||
root.set("version", JsonValue(1.0));
|
||||
root.set("name", JsonValue("Preset One"));
|
||||
|
||||
JsonValue layers = JsonValue::MakeArray();
|
||||
JsonValue layer = JsonValue::MakeObject();
|
||||
layer.set("id", JsonValue("layer-a"));
|
||||
layer.set("bypass", JsonValue(false));
|
||||
layers.pushBack(layer);
|
||||
root.set("layers", layers);
|
||||
|
||||
const std::string serialized = SerializeJson(root, true);
|
||||
const JsonValue parsed = ParseOrFail(serialized, "serialized preset-style object parses");
|
||||
Expect(parsed.find("layers") && parsed.find("layers")->isArray(), "roundtripped layers array exists");
|
||||
|
||||
JsonValue mutableValue = JsonValue::MakeObject();
|
||||
mutableValue.set("stale", JsonValue("value"));
|
||||
mutableValue.pushBack(JsonValue(7.0));
|
||||
Expect(mutableValue.isArray(), "pushBack changes object into array");
|
||||
Expect(mutableValue.asObject().empty(), "object storage is cleared when changing to array");
|
||||
Expect(mutableValue.asArray().size() == 1, "new array receives pushed value");
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
TestStringsAndEscaping();
|
||||
TestUnicodeEscapes();
|
||||
TestNumbers();
|
||||
TestRoundtripAndMutation();
|
||||
|
||||
if (gFailures != 0)
|
||||
{
|
||||
std::cerr << gFailures << " RuntimeJson test failure(s).\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "RuntimeJson tests passed.\n";
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user