mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-22 01:55:25 -04:00
2c2efa4a99
* Fix SerializerElement broken when using attributes with children * Fix usage of AddChild on arrays without named children
207 lines
8.3 KiB
C++
207 lines
8.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("(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\"}");
|
|
}
|
|
}
|