Pyrogenesis  trunk
ComponentTest.h
Go to the documentation of this file.
1 /* Copyright (C) 2017 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 #include "lib/self_test.h"
19 
20 #include "maths/Matrix3D.h"
21 #include "maths/Vector3D.h"
22 #include "ps/XML/Xeromyces.h"
30 
31 #include <iostream>
32 
33 /**
34  * @file
35  * Various common features for component test cases.
36  */
37 
38 /**
39  * Class to test a single component.
40  * - Create an instance of this class
41  * - Use AddMock to add mock components that the tested component relies on
42  * - Use Add to add the test component itself, and it returns a component pointer
43  * - Call methods on the component pointer
44  * - Use Roundtrip to test the consistency of serialization
45  */
47 {
53 
54 public:
55  ComponentTestHelper(shared_ptr<ScriptRuntime> runtime) :
56  m_Context(), m_ComponentManager(m_Context, runtime), m_Cmp(NULL)
57  {
58  m_ComponentManager.LoadComponentTypes();
59  }
60 
62  {
63  return m_ComponentManager.GetScriptInterface();
64  }
65 
67  {
68  return m_Context;
69  }
70 
71  /**
72  * Call this once to initialise the test helper with a component.
73  */
74  template<typename T>
75  T* Add(EComponentTypeId cid, const std::string& xml, entity_id_t ent = 10)
76  {
77  TS_ASSERT(m_Cmp == NULL);
78 
80  if (ent == SYSTEM_ENTITY)
81  {
82  m_ComponentManager.InitSystemEntity();
83  handle = m_ComponentManager.GetSystemEntity();
84  m_Context.SetSystemEntity(handle);
85  }
86  else
87  handle = m_ComponentManager.LookupEntityHandle(ent, true);
88 
89  m_Cid = cid;
90  TS_ASSERT_EQUALS(CParamNode::LoadXMLString(m_Param, ("<test>" + xml + "</test>").c_str()), PSRETURN_OK);
91  TS_ASSERT(m_ComponentManager.AddComponent(handle, m_Cid, m_Param.GetChild("test")));
92  m_Cmp = m_ComponentManager.QueryInterface(ent, T::GetInterfaceId());
93  TS_ASSERT(m_Cmp != NULL);
94  return static_cast<T*> (m_Cmp);
95  }
96 
97  void AddMock(entity_id_t ent, EInterfaceId iid, IComponent& component)
98  {
100  if (ent == SYSTEM_ENTITY)
101  {
102  m_ComponentManager.InitSystemEntity();
103  handle = m_ComponentManager.GetSystemEntity();
104  m_Context.SetSystemEntity(handle);
105  }
106  else
107  handle = m_ComponentManager.LookupEntityHandle(ent, true);
108 
109  m_ComponentManager.AddMockComponent(handle, iid, component);
110  }
111 
112  void HandleMessage(IComponent* cmp, const CMessage& msg, bool global)
113  {
114  cmp->HandleMessage(msg, global);
115  }
116 
117  /**
118  * Checks that the object roundtrips through its serialize/deserialize functions correctly.
119  * Computes the debug output, hash, and binary serialization; then deserializes into a new
120  * system and checks the serialization outputs are unchanged.
121  */
122  void Roundtrip(bool verbose = false)
123  {
124  std::stringstream dbgstr1;
125  CDebugSerializer dbg1(GetScriptInterface(), dbgstr1);
126  m_Cmp->Serialize(dbg1);
127 
128  if (verbose)
129  std::cout << "--------\n" << dbgstr1.str() << "--------\n";
130 
132  m_Cmp->Serialize(hash1);
133 
134  std::stringstream stdstr1;
135  CStdSerializer std1(GetScriptInterface(), stdstr1);
136  m_Cmp->Serialize(std1);
137 
138  ComponentTestHelper test2(GetScriptInterface().GetRuntime());
139  // (We should never need to add any mock objects etc to test2, since deserialization
140  // mustn't depend on other components already existing)
141 
143 
144  CStdDeserializer stdde2(test2.GetScriptInterface(), stdstr1);
145 
146  IComponent* cmp2 = test2.m_ComponentManager.ConstructComponent(ent, m_Cid);
147  cmp2->Deserialize(m_Param.GetChild("test"), stdde2);
148 
149  TS_ASSERT(stdstr1.peek() == EOF); // Deserialize must read whole stream
150 
151  std::stringstream dbgstr2;
152  CDebugSerializer dbg2(test2.GetScriptInterface(), dbgstr2);
153  cmp2->Serialize(dbg2);
154 
155  if (verbose)
156  std::cout << "--------\n" << dbgstr2.str() << "--------\n";
157 
158  CHashSerializer hash2(test2.GetScriptInterface());
159  cmp2->Serialize(hash2);
160 
161  std::stringstream stdstr2;
162  CStdSerializer std2(test2.GetScriptInterface(), stdstr2);
163  cmp2->Serialize(std2);
164 
165  TS_ASSERT_EQUALS(dbgstr1.str(), dbgstr2.str());
166 
167  TS_ASSERT_EQUALS(hash1.GetHashLength(), hash2.GetHashLength());
168  TS_ASSERT_SAME_DATA(hash1.ComputeHash(), hash2.ComputeHash(), hash1.GetHashLength());
169 
170  TS_ASSERT_EQUALS(stdstr1.str(), stdstr2.str());
171 
172  // TODO: need to extend this so callers can run methods on the cloned component
173  // to check that all its data is still correct
174  }
175 };
176 
177 /**
178  * Simple terrain implementation with constant height of 50.
179  */
180 class MockTerrain : public ICmpTerrain
181 {
182 public:
184 
185  virtual bool IsLoaded() const
186  {
187  return true;
188  }
189 
191  {
193  }
194 
195  virtual CVector3D CalcExactNormal(float UNUSED(x), float UNUSED(z)) const
196  {
197  return CVector3D(0.f, 1.f, 0.f);
198  }
199 
201  {
202  return entity_pos_t::FromInt(50);
203  }
204 
205  virtual float GetExactGroundLevel(float UNUSED(x), float UNUSED(z)) const
206  {
207  return 50.f;
208  }
209 
210  virtual u16 GetTilesPerSide() const
211  {
212  return 16;
213  }
214 
215  virtual u16 GetVerticesPerSide() const
216  {
217  return 17;
218  }
219 
221  {
222  return NULL;
223  }
224 
225  virtual void MakeDirty(i32 UNUSED(i0), i32 UNUSED(j0), i32 UNUSED(i1), i32 UNUSED(j1))
226  {
227  }
228 
229  virtual void ReloadTerrain(bool UNUSED(ReloadWater))
230  {
231  }
232 };
An entity initialisation parameter node.
Definition: ParamNode.h:148
Definition: IComponent.h:33
A simple fixed-point number class.
Definition: Fixed.h:115
virtual CTerrain * GetCTerrain()
Definition: ComponentTest.h:220
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
CParamNode m_Param
Definition: ComponentTest.h:50
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:800
void Roundtrip(bool verbose=false)
Checks that the object roundtrips through its serialize/deserialize functions correctly.
Definition: ComponentTest.h:122
xml
Definition: tests.py:119
const PSRETURN PSRETURN_OK
Definition: Errors.h:103
uint16_t u16
Definition: types.h:38
virtual void Serialize(ISerializer &serialize)=0
IComponent * QueryInterface(entity_id_t ent, InterfaceId iid) const
Definition: ComponentManager.cpp:953
Object wrapping an entity_id_t, with a SEntityComponentCache to support fast QueryInterface() / CmpPt...
Definition: Entity.h:79
virtual void ReloadTerrain(bool ReloadWater)
Call when the underlying CTerrain has been modified behind our backs.
Definition: ComponentTest.h:229
CComponentManager m_ComponentManager
Definition: ComponentTest.h:49
ScriptInterface & GetScriptInterface()
Definition: ComponentManager.h:315
ComponentTestHelper(shared_ptr< ScriptRuntime > runtime)
Definition: ComponentTest.h:55
Definition: Vector3D.h:28
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:75
Definition: Terrain.h:51
Serialize to a human-readable YAML-like format.
Definition: DebugSerializer.h:26
virtual CFixedVector3D CalcNormal(entity_pos_t x, entity_pos_t z) const
Definition: ComponentTest.h:190
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:115
Definition: HashSerializer.h:45
const entity_id_t SYSTEM_ENTITY
Entity ID for singleton &#39;system&#39; components.
Definition: Entity.h:43
virtual float GetExactGroundLevel(float x, float z) const
Definition: ComponentTest.h:205
CEntityHandle LookupEntityHandle(entity_id_t ent, bool allowCreate=false)
Returns a CEntityHandle with id ent.
Definition: ComponentManager.cpp:830
void AddMock(entity_id_t ent, EInterfaceId iid, IComponent &component)
Definition: ComponentTest.h:97
virtual u16 GetVerticesPerSide() const
Returns number of vertices per side on the terrain.
Definition: ComponentTest.h:215
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:224
Simple terrain implementation with constant height of 50.
Definition: ComponentTest.h:180
#define DEFAULT_MOCK_COMPONENT()
Definition: Component.h:99
Definition: ComponentManager.h:40
static PSRETURN LoadXMLString(CParamNode &ret, const char *xml, const wchar_t *sourceIdentifier=NULL)
See LoadXML, but parses the XML string xml.
Definition: ParamNode.cpp:55
Definition: FixedVector3D.h:24
#define T(string_literal)
Definition: secure_crt.cpp:76
void InitSystemEntity()
Set up an empty SYSTEM_ENTITY.
Definition: ComponentManager.cpp:845
int32_t i32
Definition: types.h:34
CSimContext m_Context
Definition: ComponentTest.h:48
static CFixed FromInt(int n)
Definition: Fixed.h:136
virtual void Deserialize(const CParamNode &paramNode, IDeserializer &deserialize)=0
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:703
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:740
IComponent * m_Cmp
Definition: ComponentTest.h:51
void SetSystemEntity(CEntityHandle ent)
Definition: SimContext.h:48
virtual u16 GetTilesPerSide() const
Returns number of tiles per side on the terrain.
Definition: ComponentTest.h:210
virtual void HandleMessage(const CMessage &msg, bool global)
Definition: IComponent.cpp:32
EComponentTypeId m_Cid
Definition: ComponentTest.h:52
CEntityHandle GetSystemEntity()
Returns a CEntityHandle with id SYSTEM_ENTITY.
Definition: ComponentManager.h:197
static Handle handle(size_t idx, u64 tag)
Definition: h_mgr.cpp:121
ScriptInterface & GetScriptInterface()
Definition: ComponentTest.h:61
Abstraction around a SpiderMonkey JSContext.
Definition: ScriptInterface.h:71
void HandleMessage(IComponent *cmp, const CMessage &msg, bool global)
Definition: ComponentTest.h:112
virtual void MakeDirty(i32 i0, i32 j0, i32 i1, i32 j1)
Indicate that terrain tiles within the given region (inclusive lower bound, exclusive upper bound) ha...
Definition: ComponentTest.h:225
CSimContext & GetSimContext()
Definition: ComponentTest.h:66
virtual CVector3D CalcExactNormal(float x, float z) const
Definition: ComponentTest.h:195
Class to test a single component.
Definition: ComponentTest.h:46
virtual entity_pos_t GetGroundLevel(entity_pos_t x, entity_pos_t z) const
Definition: ComponentTest.h:200
u32 entity_id_t
Entity ID type.
Definition: Entity.h:23
Definition: StdDeserializer.h:27
const u8 * ComputeHash()
Definition: HashSerializer.cpp:32
Definition: StdSerializer.h:59
EInterfaceId
Definition: Components.h:39
Definition: ICmpTerrain.h:30
Definition: Message.h:24