Pyrogenesis HEAD
Pyrogenesis, a RTS Engine
ComponentTest.h
Go to the documentation of this file.
1/* Copyright (C) 2023 Wildfire Games.
2 * This file is part of 0 A.D.
3 *
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef INCLUDED_COMPONENTTEST
19#define INCLUDED_COMPONENTTEST
20
21#include "lib/self_test.h"
22
23#include "maths/Vector3D.h"
24#include "ps/XML/Xeromyces.h"
32
33#include <iostream>
34
35/**
36 * @file
37 * Various common features for component test cases.
38 */
39
40/**
41 * Class to test a single component.
42 * - Create an instance of this class
43 * - Use AddMock to add mock components that the tested component relies on
44 * - Use Add to add the test component itself, and it returns a component pointer
45 * - Call methods on the component pointer
46 * - Use Roundtrip to test the consistency of serialization
47 */
49{
56
57public:
59 m_Context(), m_ComponentManager(m_Context, scriptContext), m_Cmp(NULL)
60 {
62 }
63
65 {
67 }
68
70 {
71 return m_Context;
72 }
73
74 /**
75 * Call this once to initialise the test helper with a component.
76 */
77 template<typename T>
78 T* Add(EComponentTypeId cid, const std::string& xml, entity_id_t ent = 10)
79 {
80 TS_ASSERT(m_Cmp == NULL);
81
82 CEntityHandle handle;
83 if (ent == SYSTEM_ENTITY)
84 {
86 {
89 }
92 }
93 else
94 handle = m_ComponentManager.LookupEntityHandle(ent, true);
95
96 m_Cid = cid;
97 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(m_Param, ("<test>" + xml + "</test>").c_str()), PSRETURN_OK);
98 TS_ASSERT(m_ComponentManager.AddComponent(handle, m_Cid, m_Param.GetChild("test")));
99 m_Cmp = m_ComponentManager.QueryInterface(ent, T::GetInterfaceId());
100 TS_ASSERT(m_Cmp != NULL);
101 return static_cast<T*> (m_Cmp);
102 }
103
104 void AddMock(entity_id_t ent, EInterfaceId iid, IComponent& component)
105 {
106 CEntityHandle handle;
107 if (ent == SYSTEM_ENTITY)
108 {
110 {
113 }
116 }
117 else
118 handle = m_ComponentManager.LookupEntityHandle(ent, true);
119
120 m_ComponentManager.AddMockComponent(handle, iid, component);
121 }
122
123 void HandleMessage(IComponent* cmp, const CMessage& msg, bool global)
124 {
125 cmp->HandleMessage(msg, global);
126 }
127
128 /**
129 * Checks that the object roundtrips through its serialize/deserialize functions correctly.
130 * Computes the debug output, hash, and binary serialization; then deserializes into a new
131 * system and checks the serialization outputs are unchanged.
132 */
133 void Roundtrip(bool verbose = false)
134 {
135 std::stringstream dbgstr1;
136 CDebugSerializer dbg1(GetScriptInterface(), dbgstr1);
137 m_Cmp->Serialize(dbg1);
138
139 if (verbose)
140 std::cout << "--------\n" << dbgstr1.str() << "--------\n";
141
143 m_Cmp->Serialize(hash1);
144
145 std::stringstream stdstr1;
146 CStdSerializer std1(GetScriptInterface(), stdstr1);
147 m_Cmp->Serialize(std1);
148
149 ComponentTestHelper test2(GetScriptInterface().GetContext());
150 // (We should never need to add any mock objects etc to test2, since deserialization
151 // mustn't depend on other components already existing)
152
154
155 CStdDeserializer stdde2(test2.GetScriptInterface(), stdstr1);
156
158 cmp2->Deserialize(m_Param.GetChild("test"), stdde2);
159
160 TS_ASSERT(stdstr1.peek() == EOF); // Deserialize must read whole stream
161
162 std::stringstream dbgstr2;
163 CDebugSerializer dbg2(test2.GetScriptInterface(), dbgstr2);
164 cmp2->Serialize(dbg2);
165
166 if (verbose)
167 std::cout << "--------\n" << dbgstr2.str() << "--------\n";
168
169 CHashSerializer hash2(test2.GetScriptInterface());
170 cmp2->Serialize(hash2);
171
172 std::stringstream stdstr2;
173 CStdSerializer std2(test2.GetScriptInterface(), stdstr2);
174 cmp2->Serialize(std2);
175
176 TS_ASSERT_EQUALS(dbgstr1.str(), dbgstr2.str());
177
178 TS_ASSERT_EQUALS(hash1.GetHashLength(), hash2.GetHashLength());
179 TS_ASSERT_SAME_DATA(hash1.ComputeHash(), hash2.ComputeHash(), hash1.GetHashLength());
180
181 TS_ASSERT_EQUALS(stdstr1.str(), stdstr2.str());
182
183 // TODO: need to extend this so callers can run methods on the cloned component
184 // to check that all its data is still correct
185 }
186};
187
188/**
189 * Simple terrain implementation with constant height of 50.
190 */
192{
193public:
195
196 bool IsLoaded() const override
197 {
198 return true;
199 }
200
202 {
204 }
205
206 CVector3D CalcExactNormal(float UNUSED(x), float UNUSED(z)) const override
207 {
208 return CVector3D(0.f, 1.f, 0.f);
209 }
210
212 {
213 return entity_pos_t::FromInt(50);
214 }
215
216 float GetExactGroundLevel(float UNUSED(x), float UNUSED(z)) const override
217 {
218 return 50.f;
219 }
220
221 u16 GetTilesPerSide() const override
222 {
223 return 16;
224 }
225
226 u32 GetMapSize() const override
227 {
229 }
230
231 u16 GetVerticesPerSide() const override
232 {
233 return 17;
234 }
235
237 {
238 return nullptr;
239 }
240
241 void MakeDirty(i32 UNUSED(i0), i32 UNUSED(j0), i32 UNUSED(i1), i32 UNUSED(j1)) override
242 {
243 }
244
245 void ReloadTerrain(bool UNUSED(ReloadWater)) override
246 {
247 }
248};
249
250#endif // INCLUDED_COMPONENTTEST
#define DEFAULT_MOCK_COMPONENT()
Definition: Component.h:47
EComponentTypeId
Definition: Components.h:51
EInterfaceId
Definition: Components.h:40
const PSRETURN PSRETURN_OK
Definition: Errors.h:103
const ssize_t TERRAIN_TILE_SIZE
metres [world space units] per tile in x and z
Definition: Terrain.h:40
Definition: ComponentManager.h:40
void InitSystemEntity()
Set up an empty SYSTEM_ENTITY.
Definition: ComponentManager.cpp:824
void AddMockComponent(CEntityHandle ent, InterfaceId iid, IComponent &component)
Adds an externally-created component, so that it is returned by QueryInterface but does not get destr...
Definition: ComponentManager.cpp:778
bool AddComponent(CEntityHandle ent, ComponentTypeId cid, const CParamNode &paramNode)
Constructs a component of type 'cid', initialised with data 'paramNode', and attaches it to entity 'e...
Definition: ComponentManager.cpp:680
CEntityHandle LookupEntityHandle(entity_id_t ent, bool allowCreate=false)
Returns a CEntityHandle with id ent.
Definition: ComponentManager.cpp:809
ScriptInterface & GetScriptInterface()
Definition: ComponentManager.h:272
IComponent * QueryInterface(entity_id_t ent, InterfaceId iid) const
Definition: ComponentManager.cpp:943
CEntityHandle GetSystemEntity()
Returns a CEntityHandle with id SYSTEM_ENTITY.
Definition: ComponentManager.h:149
void LoadComponentTypes()
Definition: ComponentManager.cpp:124
IComponent * ConstructComponent(CEntityHandle ent, ComponentTypeId cid)
Allocates a component object of type 'cid', and attaches it to entity 'ent'.
Definition: ComponentManager.cpp:718
Serialize to a human-readable YAML-like format.
Definition: DebugSerializer.h:27
Object wrapping an entity_id_t, with a SEntityComponentCache to support fast QueryInterface() / CmpPt...
Definition: Entity.h:80
Definition: FixedVector3D.h:25
A simple fixed-point number class.
Definition: Fixed.h:120
static constexpr CFixed FromInt(int n)
Definition: Fixed.h:140
Definition: HashSerializer.h:46
const u8 * ComputeHash()
Definition: HashSerializer.cpp:32
size_t GetHashLength()
Definition: HashSerializer.cpp:27
Definition: Message.h:26
An entity initialisation parameter node.
Definition: ParamNode.h:151
static PSRETURN LoadXMLString(CParamNode &ret, const char *xml, const wchar_t *sourceIdentifier=NULL)
See LoadXML, but parses the XML string xml.
Definition: ParamNode.cpp:58
const CParamNode & GetChild(const char *name) const
Returns the (unique) child node with the given name, or a node with IsOk() == false if there is none.
Definition: ParamNode.cpp:254
Contains pointers to various 'global' objects that are needed by the simulation code,...
Definition: SimContext.h:33
void SetSystemEntity(CEntityHandle ent)
Definition: SimContext.h:48
Definition: StdDeserializer.h:27
Definition: StdSerializer.h:60
Definition: Terrain.h:52
Definition: Vector3D.h:31
Class to test a single component.
Definition: ComponentTest.h:49
EComponentTypeId m_Cid
Definition: ComponentTest.h:54
void HandleMessage(IComponent *cmp, const CMessage &msg, bool global)
Definition: ComponentTest.h:123
CComponentManager m_ComponentManager
Definition: ComponentTest.h:51
CParamNode m_Param
Definition: ComponentTest.h:52
IComponent * m_Cmp
Definition: ComponentTest.h:53
CSimContext m_Context
Definition: ComponentTest.h:50
CSimContext & GetSimContext()
Definition: ComponentTest.h:69
bool m_isSystemEntityInit
Definition: ComponentTest.h:55
ComponentTestHelper(ScriptContext &scriptContext)
Definition: ComponentTest.h:58
void AddMock(entity_id_t ent, EInterfaceId iid, IComponent &component)
Definition: ComponentTest.h:104
void Roundtrip(bool verbose=false)
Checks that the object roundtrips through its serialize/deserialize functions correctly.
Definition: ComponentTest.h:133
const ScriptInterface & GetScriptInterface()
Definition: ComponentTest.h:64
T * Add(EComponentTypeId cid, const std::string &xml, entity_id_t ent=10)
Call this once to initialise the test helper with a component.
Definition: ComponentTest.h:78
Definition: ICmpTerrain.h:31
Definition: IComponent.h:33
virtual void Serialize(ISerializer &serialize)=0
virtual void Deserialize(const CParamNode &paramNode, IDeserializer &deserialize)=0
virtual void HandleMessage(const CMessage &msg, bool global)
Definition: IComponent.cpp:46
Simple terrain implementation with constant height of 50.
Definition: ComponentTest.h:192
CTerrain * GetCTerrain() override
Definition: ComponentTest.h:236
u16 GetVerticesPerSide() const override
Returns number of vertices per side on the terrain.
Definition: ComponentTest.h:231
void MakeDirty(i32 i0, i32 j0, i32 i1, i32 j1) override
Indicate that terrain tiles within the given region (inclusive lower bound, exclusive upper bound) ha...
Definition: ComponentTest.h:241
u16 GetTilesPerSide() const override
Returns number of tiles per side on the terrain.
Definition: ComponentTest.h:221
CVector3D CalcExactNormal(float x, float z) const override
Definition: ComponentTest.h:206
CFixedVector3D CalcNormal(entity_pos_t x, entity_pos_t z) const override
Definition: ComponentTest.h:201
float GetExactGroundLevel(float x, float z) const override
Definition: ComponentTest.h:216
void ReloadTerrain(bool ReloadWater) override
Call when the underlying CTerrain has been modified behind our backs.
Definition: ComponentTest.h:245
u32 GetMapSize() const override
Returns the map size in metres (world space units).
Definition: ComponentTest.h:226
entity_pos_t GetGroundLevel(entity_pos_t x, entity_pos_t z) const override
Definition: ComponentTest.h:211
bool IsLoaded() const override
Definition: ComponentTest.h:196
Abstraction around a SpiderMonkey JSContext.
Definition: ScriptContext.h:46
Abstraction around a SpiderMonkey JS::Realm.
Definition: ScriptInterface.h:72
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning.
Definition: code_annotation.h:40
def xml
Definition: tests.py:138
#define T(string_literal)
Definition: secure_crt.cpp:77
const entity_id_t SYSTEM_ENTITY
Entity ID for singleton 'system' components.
Definition: Entity.h:43
u32 entity_id_t
Entity ID type.
Definition: Entity.h:29
int32_t i32
Definition: types.h:34
uint16_t u16
Definition: types.h:38
uint32_t u32
Definition: types.h:39