Files
GDevelop/Core/tests/BehaviorSerialization.cpp

223 lines
8.4 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 "DummyPlatform.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/Extensions/Platform.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Variable.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Tools/SystemStats.h"
#include "GDCore/Tools/VersionWrapper.h"
#include "catch.hpp"
using namespace gd;
namespace {
void AddEventsBasedExtension(gd::Project &project) {
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedBehavior =
eventsExtension.GetEventsBasedBehaviors().InsertNew(
"MyEventsBasedBehavior", 0);
eventsBasedBehavior.SetFullName("My events based behavior");
eventsBasedBehavior.SetDescription("An events based behavior for test");
eventsBasedBehavior.SetObjectType("");
eventsBasedBehavior.GetPropertyDescriptors()
.InsertNew("MyProperty", 0)
.SetType("Number");
};
void AddAnotherEventsBasedExtensionWithDependency(gd::Project &project) {
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyOtherEventsExtension", 0);
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
eventsBasedObject.SetFullName("My events based object");
eventsBasedObject.SetDescription("An events based object for test");
gd::Object &object = eventsBasedObject.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
gd::Behavior *behavior =
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior",
"MyEventsBasedBehavior");
behavior->UpdateProperty("MyProperty", "481516");
};
void SetupProject(gd::Project &project, gd::Platform &platform) {
SetupProjectWithDummyPlatform(project, platform);
AddEventsBasedExtension(project);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.GetObjects().InsertNewObject(
project, "MyExtension::Sprite", "MyObject", 0);
gd::Behavior *behavior =
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior",
"MyEventsBasedBehavior");
behavior->UpdateProperty("MyProperty", "481516");
};
void CheckBehaviorPropertyInObjectContainerElement(
SerializerElement &objectContainerElement) {
REQUIRE(objectContainerElement.HasChild("objects"));
auto &objectsElement = objectContainerElement.GetChild("objects");
objectsElement.ConsiderAsArrayOf("object");
REQUIRE(objectsElement.GetChildrenCount() == 1);
auto &objectElement = objectsElement.GetChild(0);
REQUIRE(objectElement.GetStringAttribute("name") == "MyObject");
REQUIRE(objectElement.GetStringAttribute("type") == "MyExtension::Sprite");
REQUIRE(objectElement.HasChild("behaviors"));
auto &behaviorsElement = objectElement.GetChild("behaviors");
behaviorsElement.ConsiderAsArrayOf("behavior");
REQUIRE(behaviorsElement.GetChildrenCount() == 1);
auto &behaviorElement = behaviorsElement.GetChild(0);
REQUIRE(behaviorElement.GetStringAttribute("name") ==
"MyEventsBasedBehavior");
REQUIRE(behaviorElement.GetStringAttribute("type") ==
"MyEventsExtension::MyEventsBasedBehavior");
REQUIRE(behaviorElement.GetStringAttribute("MyProperty") == "481516");
};
void CheckBehaviorPropertyInElement(SerializerElement &projectElement) {
auto &layoutsElement = projectElement.GetChild("layouts");
layoutsElement.ConsiderAsArrayOf("layout");
REQUIRE(layoutsElement.GetChildrenCount() == 1);
auto &layoutElement = layoutsElement.GetChild(0);
REQUIRE(layoutElement.GetStringAttribute("name") == "Scene");
CheckBehaviorPropertyInObjectContainerElement(layoutElement);
};
void CheckBehaviorProperty(ObjectsContainer &container) {
auto &object = container.GetObject("MyObject");
REQUIRE(object.GetType() == "MyExtension::Sprite");
REQUIRE(object.HasBehaviorNamed("MyEventsBasedBehavior"));
auto &behavior = object.GetBehavior("MyEventsBasedBehavior");
REQUIRE(behavior.GetTypeName() == "MyEventsExtension::MyEventsBasedBehavior");
REQUIRE(behavior.GetProperties().size() == 1);
REQUIRE(behavior.GetProperties().at("MyProperty").GetValue() == "481516");
};
} // namespace
// TODO EBO Add similar test cases for events-based objects.
TEST_CASE("BehaviorSerialization", "[common]") {
SECTION("Save and load a project with a custom behavior property value") {
gd::Platform platform;
gd::Project writtenProject;
SetupProject(writtenProject, platform);
CheckBehaviorProperty(
writtenProject.GetLayout("Scene").GetObjects());
SerializerElement projectElement;
writtenProject.SerializeTo(projectElement);
CheckBehaviorPropertyInElement(projectElement);
gd::Project readProject;
readProject.AddPlatform(platform);
readProject.UnserializeFrom(projectElement);
CheckBehaviorProperty(readProject.GetLayout("Scene").GetObjects());
}
SECTION("Copy constructor of Behavior") {
gd::Platform platform;
gd::Project originalProject;
SetupProject(originalProject, platform);
CheckBehaviorProperty(originalProject.GetLayout("Scene").GetObjects());
auto clonedProject = originalProject;
CheckBehaviorProperty(clonedProject.GetLayout("Scene").GetObjects());
}
SECTION("Load a project with a property value on a custom behavior that no longer exists") {
gd::Platform platform;
gd::Project writtenProject;
SetupProject(writtenProject, platform);
// Remove the events-based behavior
writtenProject.RemoveEventsFunctionsExtension("MyEventsExtension");
SerializerElement projectElement;
writtenProject.SerializeTo(projectElement);
CheckBehaviorPropertyInElement(projectElement);
gd::Project readProject;
readProject.AddPlatform(platform);
readProject.UnserializeFrom(projectElement);
// Add the events-based behavior back
AddEventsBasedExtension(readProject);
CheckBehaviorProperty(readProject.GetLayout("Scene").GetObjects());
}
SECTION("Save and load a project with an event based extension dependency") {
gd::Platform platform;
gd::Project writtenProject;
SetupProject(writtenProject, platform);
AddAnotherEventsBasedExtensionWithDependency(writtenProject);
// It's important that the extension with the dependency is the first one.
REQUIRE(writtenProject.GetEventsFunctionsExtension(0).GetName() ==
"MyOtherEventsExtension");
REQUIRE(writtenProject.GetEventsFunctionsExtension(1).GetName() ==
"MyEventsExtension");
SerializerElement projectElement;
writtenProject.SerializeTo(projectElement);
auto &extensionsElement =
projectElement.GetChild("eventsFunctionsExtensions");
extensionsElement.ConsiderAsArrayOf("eventsFunctionsExtension");
REQUIRE(extensionsElement.GetChildrenCount() == 2);
auto &firstExtensionElement = extensionsElement.GetChild(0);
REQUIRE(firstExtensionElement.GetStringAttribute("name") ==
"MyOtherEventsExtension");
auto &eventsBasedObjectsElement =
firstExtensionElement.GetChild("eventsBasedObjects");
eventsBasedObjectsElement.ConsiderAsArrayOf("eventsBasedObject");
auto &eventsBasedObjectElement =
eventsBasedObjectsElement.GetChild(0);
CheckBehaviorPropertyInObjectContainerElement(eventsBasedObjectElement);
auto &secondExtensionElement = extensionsElement.GetChild(1);
REQUIRE(secondExtensionElement.GetStringAttribute("name") ==
"MyEventsExtension");
gd::Project readProject;
readProject.AddPlatform(platform);
readProject.UnserializeFrom(projectElement);
// The custom behavior is unserialized even though it depends on the other
// extension.
REQUIRE(readProject.HasEventsBasedObject(
"MyOtherEventsExtension::MyEventsBasedObject"));
CheckBehaviorProperty(
readProject
.GetEventsBasedObject("MyOtherEventsExtension::MyEventsBasedObject")
.GetObjects());
}
}