A Discrete-Event Network Simulator
API
object-test-suite.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2007 INRIA, Gustavo Carneiro
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program 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 this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Authors: Gustavo Carneiro <gjcarneiro@gmail.com>,
19  * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
20  */
21 #include "ns3/test.h"
22 #include "ns3/object.h"
23 #include "ns3/object-factory.h"
24 #include "ns3/assert.h"
25 
26 namespace {
27 
28 class BaseA : public ns3::Object
29 {
30 public:
35  static ns3::TypeId GetTypeId (void)
36  {
37  static ns3::TypeId tid = ns3::TypeId ("ObjectTest:BaseA")
38  .SetParent<Object> ()
39  .SetGroupName ("Core")
40  .HideFromDocumentation ()
41  .AddConstructor<BaseA> ();
42  return tid;
43  }
44  BaseA ()
45  {}
46  virtual void Dispose (void) {}
47 };
48 
49 class DerivedA : public BaseA
50 {
51 public:
56  static ns3::TypeId GetTypeId (void)
57  {
58  static ns3::TypeId tid = ns3::TypeId ("ObjectTest:DerivedA")
59  .SetParent<BaseA> ()
60  .SetGroupName ("Core")
61  .HideFromDocumentation ()
62  .AddConstructor<DerivedA> ();
63  return tid;
64  }
66  {}
67  virtual void Dispose (void) {
68  BaseA::Dispose ();
69  }
70 };
71 
72 class BaseB : public ns3::Object
73 {
74 public:
79  static ns3::TypeId GetTypeId (void)
80  {
81  static ns3::TypeId tid = ns3::TypeId ("ObjectTest:BaseB")
82  .SetParent<Object> ()
83  .SetGroupName ("Core")
84  .HideFromDocumentation ()
85  .AddConstructor<BaseB> ();
86  return tid;
87  }
88  BaseB ()
89  {}
90  virtual void Dispose (void) {}
91 };
92 
93 class DerivedB : public BaseB
94 {
95 public:
100  static ns3::TypeId GetTypeId (void)
101  {
102  static ns3::TypeId tid = ns3::TypeId ("ObjectTest:DerivedB")
103  .SetParent<BaseB> ()
104  .SetGroupName ("Core")
105  .HideFromDocumentation ()
106  .AddConstructor<DerivedB> ();
107  return tid;
108  }
110  {}
111  virtual void Dispose (void) {
112  BaseB::Dispose ();
113  }
114 };
115 
117 NS_OBJECT_ENSURE_REGISTERED (DerivedA);
119 NS_OBJECT_ENSURE_REGISTERED (DerivedB);
120 
121 } // namespace anonymous
122 
123 using namespace ns3;
124 
125 // ===========================================================================
126 // Test case to make sure that we can make Objects using CreateObject.
127 // ===========================================================================
129 {
130 public:
132  virtual ~CreateObjectTestCase ();
133 
134 private:
135  virtual void DoRun (void);
136 };
137 
139  : TestCase ("Check CreateObject<Type> template function")
140 {
141 }
142 
144 {
145 }
146 
147 void
149 {
150  Ptr<BaseA> baseA = CreateObject<BaseA> ();
151  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to CreateObject<BaseA>");
152 
153  //
154  // Since baseA is a BaseA, we must be able to successfully ask for a BaseA.
155  //
156  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<BaseA> (), baseA, "GetObject() of same type returns different Ptr");
157 
158  //
159  // Since BaseA is a BaseA and not a DerivedA, we must not find a DerivedA if we look.
160  //
161  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<DerivedA> (), 0, "GetObject() of unrelated type returns nonzero pointer");
162 
163  //
164  // Since baseA is not a BaseA, we must not be able to ask for a DerivedA even if we
165  // try an implied cast back to a BaseA.
166  //
167  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<BaseA> (DerivedA::GetTypeId ()), 0, "GetObject() of unrelated returns nonzero Ptr");
168 
169  baseA = CreateObject<DerivedA> ();
170  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to CreateObject<DerivedA> with implicit cast to BaseA");
171 
172  //
173  // If we create a DerivedA and cast it to a BaseA, then if we do a GetObject for
174  // that BaseA we should get the same address (same Object).
175  //
176  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<BaseA> (), baseA, "Unable to GetObject<BaseA> on BaseA");
177 
178  //
179  // Since we created a DerivedA and cast it to a BaseA, we should be able to
180  // get back a DerivedA and it should be the original Ptr.
181  //
182  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<DerivedA> (), baseA, "GetObject() of the original type returns different Ptr");
183 
184  // If we created a DerivedA and cast it to a BaseA, then we GetObject for the
185  // same DerivedA and cast it back to the same BaseA, we should get the same
186  // object.
187  //
188  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<BaseA> (DerivedA::GetTypeId ()), baseA, "GetObject returns different Ptr");
189 }
190 
191 // ===========================================================================
192 // Test case to make sure that we can aggregate Objects.
193 // ===========================================================================
195 {
196 public:
198  virtual ~AggregateObjectTestCase ();
199 
200 private:
201  virtual void DoRun (void);
202 };
203 
205  : TestCase ("Check Object aggregation functionality")
206 {
207 }
208 
210 {
211 }
212 
213 void
215 {
216  Ptr<BaseA> baseA = CreateObject<BaseA> ();
217  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to CreateObject<BaseA>");
218 
219  Ptr<BaseB> baseB = CreateObject<BaseB> ();
220  NS_TEST_ASSERT_MSG_NE (baseB, 0, "Unable to CreateObject<BaseB>");
221 
222  Ptr<BaseB> baseBCopy = baseB;
223  NS_TEST_ASSERT_MSG_NE (baseBCopy, 0, "Unable to copy BaseB");
224 
225  //
226  // Make an aggregation of a BaseA object and a BaseB object.
227  //
228  baseA->AggregateObject (baseB);
229 
230  //
231  // We should be able to ask the aggregation (through baseA) for the BaseA part
232  // of the aggregation.
233  //
234  NS_TEST_ASSERT_MSG_NE (baseA->GetObject<BaseA> (), 0, "Cannot GetObject (through baseA) for BaseA Object");
235 
236  //
237  // There is no DerivedA in this picture, so we should not be able to GetObject
238  // for that type.
239  //
240  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<DerivedA> (), 0, "Unexpectedly found a DerivedA through baseA");
241 
242  //
243  // We should be able to ask the aggregation (through baseA) for the BaseB part
244  //
245  NS_TEST_ASSERT_MSG_NE (baseA->GetObject<BaseB> (), 0, "Cannot GetObject (through baseA) for BaseB Object");
246 
247  //
248  // There is no DerivedB in this picture, so we should not be able to GetObject
249  // for that type.
250  //
251  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<DerivedB> (), 0, "Unexpectedly found a DerivedB through baseA");
252 
253  //
254  // We should be able to ask the aggregation (through baseA) for the BaseB part
255  //
256  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<BaseB> (), 0, "Cannot GetObject (through baseB) for BaseB Object");
257 
258  //
259  // There is no DerivedB in this picture, so we should not be able to GetObject
260  // for that type.
261  //
262  NS_TEST_ASSERT_MSG_EQ (baseB->GetObject<DerivedB> (), 0, "Unexpectedly found a DerivedB through baseB");
263 
264  //
265  // We should be able to ask the aggregation (through baseB) for the BaseA part
266  // of the aggregation.
267  //
268  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<BaseA> (), 0, "Cannot GetObject (through baseB) for BaseA Object");
269 
270  //
271  // There is no DerivedA in this picture, so we should not be able to GetObject
272  // for that type.
273  //
274  NS_TEST_ASSERT_MSG_EQ (baseB->GetObject<DerivedA> (), 0, "Unexpectedly found a DerivedA through baseB");
275 
276  //
277  // baseBCopy is a copy of the original Ptr to the Object BaseB. Even though
278  // we didn't use baseBCopy directly in the aggregations, the object to which
279  // it points was used, therefore, we should be able to use baseBCopy as if
280  // it were baseB and get a BaseA out of the aggregation.
281  //
282  NS_TEST_ASSERT_MSG_NE (baseBCopy->GetObject<BaseA> (), 0, "Cannot GetObject (through baseBCopy) for a BaseA Object");
283 
284  //
285  // Now, change the underlying type of the objects to be the derived types.
286  //
287  baseA = CreateObject<DerivedA> ();
288  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to CreateObject<DerivedA> with implicit cast to BaseA");
289 
290  baseB = CreateObject<DerivedB> ();
291  NS_TEST_ASSERT_MSG_NE (baseB, 0, "Unable to CreateObject<DerivedB> with implicit cast to BaseB");
292 
293  //
294  // Create an aggregation of two objects, both of the derived types; and leave
295  // an unaggregated copy of one lying around.
296  //
297  baseBCopy = baseB;
298  baseA->AggregateObject (baseB);
299 
300  //
301  // We should be able to ask the aggregation (through baseA) for the DerivedB part
302  //
303  NS_TEST_ASSERT_MSG_NE (baseA->GetObject<DerivedB> (), 0, "Cannot GetObject (through baseA) for DerivedB Object");
304 
305  //
306  // Since the DerivedB is also a BaseB, we should be able to ask the aggregation
307  // (through baseA) for the BaseB part
308  //
309  NS_TEST_ASSERT_MSG_NE (baseA->GetObject<BaseB> (), 0, "Cannot GetObject (through baseA) for BaseB Object");
310 
311  //
312  // We should be able to ask the aggregation (through baseB) for the DerivedA part
313  //
314  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<DerivedA> (), 0, "Cannot GetObject (through baseB) for DerivedA Object");
315 
316  //
317  // Since the DerivedA is also a BaseA, we should be able to ask the aggregation
318  // (through baseB) for the BaseA part
319  //
320  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<BaseA> (), 0, "Cannot GetObject (through baseB) for BaseA Object");
321 
322  //
323  // baseBCopy is a copy of the original Ptr to the Object BaseB. Even though
324  // we didn't use baseBCopy directly in the aggregations, the object to which
325  // it points was used, therefore, we should be able to use baseBCopy as if
326  // it were baseB (same underlying Object) and get a BaseA and a DerivedA out
327  // of the aggregation through baseBCopy.
328  //
329  NS_TEST_ASSERT_MSG_NE (baseBCopy->GetObject<BaseA> (), 0, "Cannot GetObject (through baseBCopy) for a BaseA Object");
330  NS_TEST_ASSERT_MSG_NE (baseBCopy->GetObject<DerivedA> (), 0, "Cannot GetObject (through baseBCopy) for a BaseA Object");
331 
332  //
333  // Since the Ptr<BaseB> is actually a DerivedB, we should be able to ask the
334  // aggregation (through baseB) for the DerivedB part
335  //
336  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<DerivedB> (), 0, "Cannot GetObject (through baseB) for DerivedB Object");
337 
338  //
339  // Since the DerivedB was cast to a BaseB, we should be able to ask the
340  // aggregation (through baseB) for the BaseB part
341  //
342  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<BaseB> (), 0, "Cannot GetObject (through baseB) for BaseB Object");
343 
344  //
345  // Make sure reference counting works in the aggregate. Create two Objects
346  // and aggregate them, then release one of them. The aggregation should
347  // keep a reference to both and the Object we released should still be there.
348  //
349  baseA = CreateObject<BaseA> ();
350  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to CreateObject<BaseA>");
351 
352  baseB = CreateObject<BaseB> ();
353  NS_TEST_ASSERT_MSG_NE (baseB, 0, "Unable to CreateObject<BaseA>");
354 
355  baseA->AggregateObject (baseB);
356  baseA = 0;
357 
358  baseA = baseB->GetObject<BaseA> ();
359  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to GetObject on released object");
360 }
361 
362 // ===========================================================================
363 // Test case to make sure that an Object factory can create Objects
364 // ===========================================================================
366 {
367 public:
369  virtual ~ObjectFactoryTestCase ();
370 
371 private:
372  virtual void DoRun (void);
373 };
374 
376  : TestCase ("Check ObjectFactory functionality")
377 {
378 }
379 
381 {
382 }
383 
384 void
386 {
387  ObjectFactory factory;
388 
389  //
390  // Create an Object of type BaseA through an object factory.
391  //
392  factory.SetTypeId (BaseA::GetTypeId ());
393  Ptr<Object> a = factory.Create ();
394  NS_TEST_ASSERT_MSG_NE (a, 0, "Unable to factory.Create() a BaseA");
395 
396  //
397  // What we made should be a BaseA, not have anything to do with a DerivedA
398  //
399  NS_TEST_ASSERT_MSG_EQ (a->GetObject<BaseA> (DerivedA::GetTypeId ()), 0, "BaseA is unexpectedly a DerivedA also");
400 
401  //
402  // The BaseA we got should not respond to a GetObject for DerivedA
403  //
404  NS_TEST_ASSERT_MSG_EQ (a->GetObject<DerivedA> (), 0, "BaseA unexpectedly responds to GetObject for DerivedA");
405 
406  //
407  // Now tell the factory to make DerivedA Objects and create one with an
408  // implied cast back to a BaseA
409  //
410  factory.SetTypeId (DerivedA::GetTypeId ());
411  a = factory.Create ();
412 
413  //
414  // Since the DerivedA has a BaseA part, we should be able to use GetObject to
415  // dynamically cast back to a BaseA.
416  //
417  NS_TEST_ASSERT_MSG_EQ (a->GetObject<BaseA> (), a, "Unable to use GetObject as dynamic_cast<BaseA>()");
418 
419  //
420  // Since a is already a BaseA and is really a DerivedA, we should be able to
421  // GetObject for the DerivedA and cast it back to a BaseA getting the same
422  // value that is there.
423  //
424  NS_TEST_ASSERT_MSG_EQ (a->GetObject<BaseA> (DerivedA::GetTypeId ()), a, "GetObject with implied cast returns different Ptr");
425 
426  //
427  // Since a declared a BaseA, even if it is really a DerivedA, we should not
428  // be able to GetOBject for a DerivedA since this would break the type
429  // declaration.
430  //
431  NS_TEST_ASSERT_MSG_NE (a->GetObject<DerivedA> (), 0, "Unexpectedly able to work around C++ type system");
432 }
433 
434 // ===========================================================================
435 // The Test Suite that glues the Test Cases together.
436 // ===========================================================================
438 {
439 public:
440  ObjectTestSuite ();
441 };
442 
444  : TestSuite ("object", UNIT)
445 {
446  AddTestCase (new CreateObjectTestCase, TestCase::QUICK);
447  AddTestCase (new AggregateObjectTestCase, TestCase::QUICK);
448  AddTestCase (new ObjectFactoryTestCase, TestCase::QUICK);
449 }
450 
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
static ObjectTestSuite objectTestSuite
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:462
static ns3::TypeId GetTypeId(void)
Register this type.
A suite of tests to run.
Definition: test.h:1333
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
encapsulates test code
Definition: test.h:1147
virtual void DoRun(void)
Implementation to actually run this TestCase.
void AddTestCase(TestCase *testCase, enum TestDuration duration)
Add an individual child TestCase to this test suite.
Definition: test.cc:298
Ptr< Object > Create(void) const
Create an Object instance of the configured TypeId.
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:161
static ns3::TypeId GetTypeId(void)
Register this type.
virtual void DoRun(void)
Implementation to actually run this TestCase.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static ns3::TypeId GetTypeId(void)
Register this type.
virtual void DoRun(void)
Implementation to actually run this TestCase.
Instantiate subclasses of ns3::Object.
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not...
Definition: test.h:617
A base class which provides memory management and object aggregation.
Definition: object.h:87
static ns3::TypeId GetTypeId(void)
Register this type.
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:904