mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
231 lines
9.3 KiB
C++
231 lines
9.3 KiB
C++
/*
|
|
* GDevelop Core
|
|
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
|
* reserved. This project is released under the MIT License.
|
|
*/
|
|
/**
|
|
* @file Tests covering serialization to JSON.
|
|
*/
|
|
#include "GDCore/Serialization/Serializer.h"
|
|
#include "GDCore/CommonTools.h"
|
|
#include "GDCore/Events/Builtin/StandardEvent.h"
|
|
#include "GDCore/Events/Event.h"
|
|
#include "GDCore/Events/EventsList.h"
|
|
#include "GDCore/Events/Serialization.h"
|
|
#include "GDCore/Project/Layout.h"
|
|
#include "GDCore/Project/Project.h"
|
|
#include "GDCore/Project/Variable.h"
|
|
#include "GDCore/Tools/SystemStats.h"
|
|
#include "GDCore/Tools/VersionWrapper.h"
|
|
#include "catch.hpp"
|
|
|
|
using namespace gd;
|
|
|
|
TEST_CASE("SerializerElement", "[common]") {
|
|
SECTION("Basics and copying") {
|
|
SerializerElement element;
|
|
element.AddChild("child1").SetStringValue("value123");
|
|
element.AddChild("child2").SetDoubleValue(45.6);
|
|
element.SetStringAttribute("attr1", "attr123");
|
|
|
|
SerializerElement copiedElement = element;
|
|
REQUIRE(element.GetChild("child1").GetStringValue() == "value123");
|
|
REQUIRE(element.GetChild("child2").GetDoubleValue() == 45.6);
|
|
REQUIRE(element.GetStringAttribute("attr1") == "attr123");
|
|
REQUIRE(copiedElement.GetChild("child1").GetStringValue() == "value123");
|
|
REQUIRE(copiedElement.GetChild("child2").GetDoubleValue() == 45.6);
|
|
REQUIRE(copiedElement.GetStringAttribute("attr1") == "attr123");
|
|
|
|
element.GetChild("child1").SetStringValue("value123 modified");
|
|
copiedElement.GetChild("child2").SetDoubleValue(45.678);
|
|
copiedElement.SetStringAttribute("attr1", "attr123 modified");
|
|
REQUIRE(element.GetChild("child1").GetStringValue() == "value123 modified");
|
|
REQUIRE(element.GetChild("child2").GetDoubleValue() == 45.6);
|
|
REQUIRE(element.GetStringAttribute("attr1") == "attr123");
|
|
REQUIRE(copiedElement.GetChild("child1").GetStringValue() == "value123");
|
|
REQUIRE(copiedElement.GetChild("child2").GetDoubleValue() == 45.678);
|
|
REQUIRE(copiedElement.GetStringAttribute("attr1") == "attr123 modified");
|
|
}
|
|
|
|
SECTION("Accessing already existing children, in objects") {
|
|
SerializerElement element;
|
|
element.AddChild("child1").SetStringValue("value123");
|
|
element.AddChild("child1").SetStringValue("value456");
|
|
element.AddChild("child2").SetDoubleValue(45.6);
|
|
|
|
REQUIRE(element.GetChild("child1").GetStringValue() == "value456");
|
|
REQUIRE(element.GetChild("child2").GetDoubleValue() == 45.6);
|
|
}
|
|
|
|
SECTION("Adding multiple named children, in arrays") {
|
|
SerializerElement element;
|
|
element.ConsiderAsArrayOf("namedElement");
|
|
element.AddChild("namedElement").SetStringValue("value123");
|
|
element.AddChild("namedElement").SetStringValue("value456");
|
|
element.AddChild("namedElement").SetDoubleValue(45.6);
|
|
|
|
REQUIRE(element.GetChild(0).GetStringValue() == "value123");
|
|
REQUIRE(element.GetChild(1).GetStringValue() == "value456");
|
|
REQUIRE(element.GetChild(2).GetDoubleValue() == 45.6);
|
|
}
|
|
|
|
SECTION("Adding multiple unnamed children, in arrays") {
|
|
SerializerElement element;
|
|
element.ConsiderAsArray();
|
|
element.AddChild("").SetStringValue("value123");
|
|
element.AddChild("").SetStringValue("value456");
|
|
element.AddChild("").SetDoubleValue(45.6);
|
|
|
|
REQUIRE(element.GetChild(0).GetStringValue() == "value123");
|
|
REQUIRE(element.GetChild(1).GetStringValue() == "value456");
|
|
REQUIRE(element.GetChild(2).GetDoubleValue() == 45.6);
|
|
}
|
|
|
|
SECTION("Multiline strings") {
|
|
SerializerElement element;
|
|
|
|
// A single line is saved as a string.
|
|
element.SetMultilineStringValue("test");
|
|
REQUIRE(element.GetMultilineStringValue() == "test");
|
|
REQUIRE(element.GetStringValue() == "test");
|
|
|
|
// A string can be read.
|
|
element.SetStringValue("test of\nsomething\nsaved as a string");
|
|
REQUIRE(element.GetMultilineStringValue() == "test of\nsomething\nsaved as a string");
|
|
|
|
// A multi lines string is saved as an array.
|
|
element.SetMultilineStringValue("test\nwith\nmultiple lines.");
|
|
REQUIRE(element.ConsideredAsArray() == true);
|
|
REQUIRE(element.GetChildrenCount() == 3);
|
|
REQUIRE(element.GetMultilineStringValue() == "test\nwith\nmultiple lines.");
|
|
|
|
element.SetMultilineStringValue("test\n\nwith\n\nmultiple lines.\n");
|
|
REQUIRE(element.ConsideredAsArray() == true);
|
|
REQUIRE(element.GetChildrenCount() == 6);
|
|
REQUIRE(element.GetMultilineStringValue() == "test\n\nwith\n\nmultiple lines.\n");
|
|
}
|
|
|
|
SECTION("(Deprecated) attributes") {
|
|
SerializerElement element;
|
|
element.AddChild("child1").SetStringValue("value123");
|
|
element.AddChild("child2").SetDoubleValue(45.6);
|
|
element.SetStringAttribute("attr1", "attr123");
|
|
|
|
// Setting a string attribute with the same name as a child
|
|
// will remove this child. This is because, even though in the future
|
|
// only child should be used (and only children are loaded from JSON),
|
|
// we still support attributes, so that
|
|
// setting one should take precedence over any children that was loaded.
|
|
element.SetStringAttribute("child1", "value456");
|
|
|
|
REQUIRE(element.HasChild("child1") == false);
|
|
REQUIRE(element.HasChild("child2") == true);
|
|
REQUIRE(element.GetStringAttribute("attr1") == "attr123");
|
|
REQUIRE(element.GetStringAttribute("child1") == "value456");
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Serializer", "[common]") {
|
|
SECTION("JSON basics") {
|
|
gd::String originalJSON = "{\"ok\":true,\"hello\":\"world\"}";
|
|
SerializerElement element = Serializer::FromJSON(originalJSON);
|
|
REQUIRE(element.GetChild("ok").GetBoolValue() == true);
|
|
REQUIRE(element.GetChild("hello").GetStringValue() == "world");
|
|
|
|
gd::String json = Serializer::ToJSON(element);
|
|
REQUIRE(json == originalJSON);
|
|
}
|
|
|
|
SECTION("Quotes and special characters") {
|
|
gd::String originalJSON =
|
|
"{\"\\\"hello\\\"\":\" \\\"quote\\\" \",\"caret-prop\":"
|
|
"1,\"special-\\b\\f\\n\\r\\t\\\"\":\"\\b\\f\\n\\r\\t\"}";
|
|
SerializerElement element = Serializer::FromJSON(originalJSON);
|
|
REQUIRE(element.GetChild("caret-prop").GetBoolValue() == true);
|
|
REQUIRE(element.GetChild("\"hello\"").GetStringValue() ==
|
|
" \"quote\" ");
|
|
REQUIRE(element.GetChild("special-\b\f\n\r\t\"").GetStringValue() ==
|
|
"\b\f\n\r\t");
|
|
|
|
gd::String json = Serializer::ToJSON(element);
|
|
REQUIRE(json == originalJSON);
|
|
}
|
|
|
|
SECTION("UTF8 characters") {
|
|
gd::String originalJSON =
|
|
u8"{\"Ich heiße GDevelop\":\"Gut!\",\"Bonjour à tout le monde\":"
|
|
u8"1,\"Hello 官话 world\":\"官话\"}";
|
|
SerializerElement element = Serializer::FromJSON(originalJSON);
|
|
REQUIRE(
|
|
element.GetChild(u8"Bonjour à tout le monde").GetBoolValue() ==
|
|
true);
|
|
REQUIRE(element.GetChild(u8"Ich heiße GDevelop").GetStringValue() ==
|
|
"Gut!");
|
|
REQUIRE(element.GetChild(u8"Hello 官话 world").GetStringValue() ==
|
|
u8"官话");
|
|
|
|
gd::String json = Serializer::ToJSON(element);
|
|
REQUIRE(json == originalJSON);
|
|
}
|
|
|
|
SECTION("Idempotency of unserializing and serializing again") {
|
|
auto unserializeAndSerializeToJSON = [](const gd::String& originalJSON) {
|
|
SerializerElement element = Serializer::FromJSON(originalJSON);
|
|
return Serializer::ToJSON(element);
|
|
};
|
|
|
|
SECTION("Strings and numbers") {
|
|
gd::String test1 = "\"\"";
|
|
REQUIRE(unserializeAndSerializeToJSON(test1) == test1);
|
|
gd::String test2 = "123.455";
|
|
REQUIRE(unserializeAndSerializeToJSON(test2) == test2);
|
|
}
|
|
SECTION("Objects") {
|
|
gd::String test1 = "{}";
|
|
REQUIRE(unserializeAndSerializeToJSON(test1) == test1);
|
|
gd::String test2 = "{\"a\":1}";
|
|
REQUIRE(unserializeAndSerializeToJSON(test2) == test2);
|
|
gd::String test3 = "{\"a\":1,\"b\":{\"c\":2}}";
|
|
REQUIRE(unserializeAndSerializeToJSON(test3) == test3);
|
|
}
|
|
SECTION("Arrays") {
|
|
gd::String test1 = "[]";
|
|
REQUIRE(unserializeAndSerializeToJSON(test1) == test1);
|
|
gd::String test2 = "[1,2]";
|
|
REQUIRE(unserializeAndSerializeToJSON(test2) == test2);
|
|
}
|
|
SECTION("Mixed") {
|
|
gd::String test1 =
|
|
"{\"hello\":{\"world\":[{},[],3,\"4\"],\"world2\":[-1,\"-2\","
|
|
"{\"-3\":[-4]}]}}";
|
|
REQUIRE(unserializeAndSerializeToJSON(test1) == test1);
|
|
gd::String test2 =
|
|
"{\"hello\":{\"world\":[{},[],3,4],\"world2\":[-1,\"-2\","
|
|
"{\"-3\":[-4]}]}}";
|
|
REQUIRE(unserializeAndSerializeToJSON(test2) == test2);
|
|
}
|
|
}
|
|
|
|
SECTION("(Deprecated) attributes") {
|
|
gd::String originalJSON = "{\"ok\":true,\"hello\":\"world\"}";
|
|
SerializerElement element = Serializer::FromJSON(originalJSON);
|
|
REQUIRE(element.GetChild("ok").GetBoolValue() == true);
|
|
REQUIRE(element.GetChild("hello").GetStringValue() == "world");
|
|
|
|
// Attributes are deprecated, but can still be used to access
|
|
// children:
|
|
REQUIRE(element.GetBoolAttribute("ok") == true);
|
|
REQUIRE(element.GetStringAttribute("hello") == "world");
|
|
REQUIRE(element.GetStringAttribute("idontexists") == "");
|
|
|
|
// Add a new children and changes an attribute. Even though "hello"
|
|
// was loaded as a child, attributes are still supported so the child
|
|
// with this name should be removed.
|
|
element.AddChild("hello2").SetStringValue("world2");
|
|
element.SetStringAttribute("hello", "world1");
|
|
|
|
gd::String json = Serializer::ToJSON(element);
|
|
REQUIRE(json == "{\"hello\":\"world1\",\"ok\":true,\"hello2\":\"world2\"}");
|
|
}
|
|
}
|