Pyrogenesis  trunk
ComponentTest.h
Go to the documentation of this file.
1 /* Copyright (C) 2022 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 {
55  bool m_isSystemEntityInit = false;
56 
57 public:
58  ComponentTestHelper(std::shared_ptr<ScriptContext> scriptContext) :
59  m_Context(), m_ComponentManager(m_Context, scriptContext), m_Cmp(NULL)
60  {
61  m_ComponentManager.LoadComponentTypes();
62  }
63 
65  {
66  return m_ComponentManager.GetScriptInterface();
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  {
85  if (!m_isSystemEntityInit)
86  {
87  m_ComponentManager.InitSystemEntity();
88  m_isSystemEntityInit = true;
89  }
90  handle = m_ComponentManager.GetSystemEntity();
91  m_Context.SetSystemEntity(handle);
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  {
109  if (!m_isSystemEntityInit)
110  {
111  m_ComponentManager.InitSystemEntity();
112  m_isSystemEntityInit = true;
113  }
114  handle = m_ComponentManager.GetSystemEntity();
115  m_Context.SetSystemEntity(handle);
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 
157  IComponent* cmp2 = test2.m_ComponentManager.ConstructComponent(ent, m_Cid);
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  */
191 class MockTerrain : public ICmpTerrain
192 {
193 public:
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  {
228  return GetTilesPerSide() * TERRAIN_TILE_SIZE;
229  }
230 
231  u16 GetVerticesPerSide() const override
232  {
233  return 17;
234  }
235 
236  CTerrain* GetCTerrain() override
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
An entity initialisation parameter node.
Definition: ParamNode.h:150
Definition: IComponent.h:32
A simple fixed-point number class.
Definition: Fixed.h:119
EComponentTypeId
Definition: Components.h:50
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
Definition: code_annotation.h:38
entity_pos_t GetGroundLevel(entity_pos_t x, entity_pos_t z) const override
Definition: ComponentTest.h:211
CParamNode m_Param
Definition: ComponentTest.h:52
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:776
void Roundtrip(bool verbose=false)
Checks that the object roundtrips through its serialize/deserialize functions correctly.
Definition: ComponentTest.h:133
u16 GetTilesPerSide() const override
Returns number of tiles per side on the terrain.
Definition: ComponentTest.h:221
const ssize_t TERRAIN_TILE_SIZE
metres [world space units] per tile in x and z
Definition: Terrain.h:40
u32 GetMapSize() const override
Returns the map size in metres (world space units).
Definition: ComponentTest.h:226
const PSRETURN PSRETURN_OK
Definition: Errors.h:103
uint16_t u16
Definition: types.h:38
virtual void Serialize(ISerializer &serialize)=0
Object wrapping an entity_id_t, with a SEntityComponentCache to support fast QueryInterface() / CmpPt...
Definition: Entity.h:79
CComponentManager m_ComponentManager
Definition: ComponentTest.h:51
float GetExactGroundLevel(float x, float z) const override
Definition: ComponentTest.h:216
ScriptInterface & GetScriptInterface()
Definition: ComponentManager.h:272
Definition: Vector3D.h:30
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
IComponent * QueryInterface(entity_id_t ent, InterfaceId iid) const
Definition: ComponentManager.cpp:941
Definition: Terrain.h:51
Serialize to a human-readable YAML-like format.
Definition: DebugSerializer.h:26
const ScriptInterface & GetScriptInterface()
Definition: ComponentTest.h:64
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
Contains pointers to various &#39;global&#39; objects that are needed by the simulation code, to allow easy access without using real (evil) global variables.
Definition: SimContext.h:32
void LoadComponentTypes()
Definition: ComponentManager.cpp:123
void ReloadTerrain(bool ReloadWater) override
Call when the underlying CTerrain has been modified behind our backs.
Definition: ComponentTest.h:245
Definition: HashSerializer.h:45
u16 GetVerticesPerSide() const override
Returns number of vertices per side on the terrain.
Definition: ComponentTest.h:231
CTerrain * GetCTerrain() override
Definition: ComponentTest.h:236
const entity_id_t SYSTEM_ENTITY
Entity ID for singleton &#39;system&#39; components.
Definition: Entity.h:43
CEntityHandle LookupEntityHandle(entity_id_t ent, bool allowCreate=false)
Returns a CEntityHandle with id ent.
Definition: ComponentManager.cpp:807
void AddMock(entity_id_t ent, EInterfaceId iid, IComponent &component)
Definition: ComponentTest.h:104
uint32_t u32
Definition: types.h:39
Simple terrain implementation with constant height of 50.
Definition: ComponentTest.h:191
#define DEFAULT_MOCK_COMPONENT()
Definition: Component.h:47
Definition: ComponentManager.h:39
static PSRETURN LoadXMLString(CParamNode &ret, const char *xml, const wchar_t *sourceIdentifier=NULL)
See LoadXML, but parses the XML string xml.
Definition: ParamNode.cpp:57
Definition: FixedVector3D.h:24
#define T(string_literal)
Definition: secure_crt.cpp:77
void InitSystemEntity()
Set up an empty SYSTEM_ENTITY.
Definition: ComponentManager.cpp:822
CVector3D CalcExactNormal(float x, float z) const override
Definition: ComponentTest.h:206
int32_t i32
Definition: types.h:34
CSimContext m_Context
Definition: ComponentTest.h:50
virtual void Deserialize(const CParamNode &paramNode, IDeserializer &deserialize)=0
ComponentTestHelper(std::shared_ptr< ScriptContext > scriptContext)
Definition: ComponentTest.h:58
bool AddComponent(CEntityHandle ent, ComponentTypeId cid, const CParamNode &paramNode)
Constructs a component of type &#39;cid&#39;, initialised with data &#39;paramNode&#39;, and attaches it to entity &#39;e...
Definition: ComponentManager.cpp:678
size_t GetHashLength()
Definition: HashSerializer.cpp:27
IComponent * ConstructComponent(CEntityHandle ent, ComponentTypeId cid)
Allocates a component object of type &#39;cid&#39;, and attaches it to entity &#39;ent&#39;.
Definition: ComponentManager.cpp:716
IComponent * m_Cmp
Definition: ComponentTest.h:53
void SetSystemEntity(CEntityHandle ent)
Definition: SimContext.h:48
bool m_isSystemEntityInit
Definition: ComponentTest.h:55
virtual void HandleMessage(const CMessage &msg, bool global)
Definition: IComponent.cpp:46
EComponentTypeId m_Cid
Definition: ComponentTest.h:54
CEntityHandle GetSystemEntity()
Returns a CEntityHandle with id SYSTEM_ENTITY.
Definition: ComponentManager.h:149
Abstraction around a SpiderMonkey JS::Realm.
Definition: ScriptInterface.h:71
void HandleMessage(IComponent *cmp, const CMessage &msg, bool global)
Definition: ComponentTest.h:123
CFixedVector3D CalcNormal(entity_pos_t x, entity_pos_t z) const override
Definition: ComponentTest.h:201
CSimContext & GetSimContext()
Definition: ComponentTest.h:69
static constexpr CFixed FromInt(int n)
Definition: Fixed.h:140
Class to test a single component.
Definition: ComponentTest.h:48
u32 entity_id_t
Entity ID type.
Definition: Entity.h:23
def xml
Definition: tests.py:121
Definition: StdDeserializer.h:26
const u8 * ComputeHash()
Definition: HashSerializer.cpp:32
Definition: StdSerializer.h:59
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:253
EInterfaceId
Definition: Components.h:39
Definition: ICmpTerrain.h:30
Definition: Message.h:23