A Discrete-Event Network Simulator
API
object-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007 INRIA, Gustavo Carneiro
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Authors: Gustavo Carneiro <gjcarneiro@gmail.com>,
18  * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 #include "ns3/assert.h"
21 #include "ns3/object-factory.h"
22 #include "ns3/object.h"
23 #include "ns3/test.h"
24 
38 namespace
39 {
40 
45 class BaseA : public ns3::Object
46 {
47  public:
53  {
54  static ns3::TypeId tid = ns3::TypeId("ObjectTest:BaseA")
55  .SetParent<Object>()
56  .SetGroupName("Core")
59  return tid;
60  }
61 
64  {
65  }
66 };
67 
72 class DerivedA : public BaseA
73 {
74  public:
80  {
81  static ns3::TypeId tid = ns3::TypeId("ObjectTest:DerivedA")
82  .SetParent<BaseA>()
83  .SetGroupName("Core")
84  .HideFromDocumentation()
85  .AddConstructor<DerivedA>();
86  return tid;
87  }
88 
91  {
92  }
93 
94  protected:
95  void DoDispose() override
96  {
97  BaseA::DoDispose();
98  }
99 };
100 
105 class BaseB : public ns3::Object
106 {
107  public:
113  {
114  static ns3::TypeId tid = ns3::TypeId("ObjectTest:BaseB")
115  .SetParent<Object>()
116  .SetGroupName("Core")
118  .AddConstructor<BaseB>();
119  return tid;
120  }
121 
124  {
125  }
126 };
127 
132 class DerivedB : public BaseB
133 {
134  public:
140  {
141  static ns3::TypeId tid = ns3::TypeId("ObjectTest:DerivedB")
142  .SetParent<BaseB>()
143  .SetGroupName("Core")
144  .HideFromDocumentation()
145  .AddConstructor<DerivedB>();
146  return tid;
147  }
148 
151  {
152  }
153 
154  protected:
155  void DoDispose() override
156  {
157  BaseB::DoDispose();
158  }
159 };
160 
165 
166 } // unnamed namespace
167 
168 namespace ns3
169 {
170 
171 namespace tests
172 {
173 
179 {
180  public:
184  ~CreateObjectTestCase() override;
185 
186  private:
187  void DoRun() override;
188 };
189 
191  : TestCase("Check CreateObject<Type> template function")
192 {
193 }
194 
196 {
197 }
198 
199 void
201 {
202  Ptr<BaseA> baseA = CreateObject<BaseA>();
203  NS_TEST_ASSERT_MSG_NE(baseA, nullptr, "Unable to CreateObject<BaseA>");
204 
205  //
206  // Since baseA is a BaseA, we must be able to successfully ask for a BaseA.
207  //
208  NS_TEST_ASSERT_MSG_EQ(baseA->GetObject<BaseA>(),
209  baseA,
210  "GetObject() of same type returns different Ptr");
211 
212  //
213  // Since BaseA is a BaseA and not a DerivedA, we must not find a DerivedA if we look.
214  //
215  NS_TEST_ASSERT_MSG_NE(!baseA->GetObject<DerivedA>(),
216  0,
217  "GetObject() of unrelated type returns nonzero pointer");
218 
219  //
220  // Since baseA is not a BaseA, we must not be able to ask for a DerivedA even if we
221  // try an implied cast back to a BaseA.
222  //
223  NS_TEST_ASSERT_MSG_NE(!baseA->GetObject<BaseA>(DerivedA::GetTypeId()),
224  0,
225  "GetObject() of unrelated returns nonzero Ptr");
226 
227  baseA = CreateObject<DerivedA>();
228  NS_TEST_ASSERT_MSG_NE(baseA,
229  nullptr,
230  "Unable to CreateObject<DerivedA> with implicit cast to BaseA");
231 
232  //
233  // If we create a DerivedA and cast it to a BaseA, then if we do a GetObject for
234  // that BaseA we should get the same address (same Object).
235  //
236  NS_TEST_ASSERT_MSG_EQ(baseA->GetObject<BaseA>(), baseA, "Unable to GetObject<BaseA> on BaseA");
237 
238  //
239  // Since we created a DerivedA and cast it to a BaseA, we should be able to
240  // get back a DerivedA and it should be the original Ptr.
241  //
242  NS_TEST_ASSERT_MSG_EQ(baseA->GetObject<DerivedA>(),
243  baseA,
244  "GetObject() of the original type returns different Ptr");
245 
246  // If we created a DerivedA and cast it to a BaseA, then we GetObject for the
247  // same DerivedA and cast it back to the same BaseA, we should get the same
248  // object.
249  //
250  NS_TEST_ASSERT_MSG_EQ(baseA->GetObject<BaseA>(DerivedA::GetTypeId()),
251  baseA,
252  "GetObject returns different Ptr");
253 }
254 
260 {
261  public:
265  ~AggregateObjectTestCase() override;
266 
267  private:
268  void DoRun() override;
269 };
270 
272  : TestCase("Check Object aggregation functionality")
273 {
274 }
275 
277 {
278 }
279 
280 void
282 {
283  Ptr<BaseA> baseA = CreateObject<BaseA>();
284  NS_TEST_ASSERT_MSG_NE(baseA, nullptr, "Unable to CreateObject<BaseA>");
285 
286  Ptr<BaseB> baseB = CreateObject<BaseB>();
287  NS_TEST_ASSERT_MSG_NE(baseB, nullptr, "Unable to CreateObject<BaseB>");
288 
289  Ptr<BaseB> baseBCopy = baseB;
290  NS_TEST_ASSERT_MSG_NE(baseBCopy, nullptr, "Unable to copy BaseB");
291 
292  //
293  // Make an aggregation of a BaseA object and a BaseB object.
294  //
295  baseA->AggregateObject(baseB);
296 
297  //
298  // We should be able to ask the aggregation (through baseA) for the BaseA part
299  // of the aggregation.
300  //
301  NS_TEST_ASSERT_MSG_NE(baseA->GetObject<BaseA>(),
302  nullptr,
303  "Cannot GetObject (through baseA) for BaseA Object");
304 
305  //
306  // There is no DerivedA in this picture, so we should not be able to GetObject
307  // for that type.
308  //
309  NS_TEST_ASSERT_MSG_NE(!baseA->GetObject<DerivedA>(),
310  0,
311  "Unexpectedly found a DerivedA through baseA");
312 
313  //
314  // We should be able to ask the aggregation (through baseA) for the BaseB part
315  //
316  NS_TEST_ASSERT_MSG_NE(baseA->GetObject<BaseB>(),
317  nullptr,
318  "Cannot GetObject (through baseA) for BaseB Object");
319 
320  //
321  // There is no DerivedB in this picture, so we should not be able to GetObject
322  // for that type.
323  //
324  NS_TEST_ASSERT_MSG_NE(!baseA->GetObject<DerivedB>(),
325  0,
326  "Unexpectedly found a DerivedB through baseA");
327 
328  //
329  // We should be able to ask the aggregation (through baseA) for the BaseB part
330  //
331  NS_TEST_ASSERT_MSG_NE(baseB->GetObject<BaseB>(),
332  nullptr,
333  "Cannot GetObject (through baseB) for BaseB Object");
334 
335  //
336  // There is no DerivedB in this picture, so we should not be able to GetObject
337  // for that type.
338  //
339  NS_TEST_ASSERT_MSG_NE(!baseB->GetObject<DerivedB>(),
340  0,
341  "Unexpectedly found a DerivedB through baseB");
342 
343  //
344  // We should be able to ask the aggregation (through baseB) for the BaseA part
345  // of the aggregation.
346  //
347  NS_TEST_ASSERT_MSG_NE(baseB->GetObject<BaseA>(),
348  nullptr,
349  "Cannot GetObject (through baseB) for BaseA Object");
350 
351  //
352  // There is no DerivedA in this picture, so we should not be able to GetObject
353  // for that type.
354  //
355  NS_TEST_ASSERT_MSG_NE(!baseB->GetObject<DerivedA>(),
356  0,
357  "Unexpectedly found a DerivedA through baseB");
358 
359  //
360  // baseBCopy is a copy of the original Ptr to the Object BaseB. Even though
361  // we didn't use baseBCopy directly in the aggregations, the object to which
362  // it points was used, therefore, we should be able to use baseBCopy as if
363  // it were baseB and get a BaseA out of the aggregation.
364  //
365  NS_TEST_ASSERT_MSG_NE(baseBCopy->GetObject<BaseA>(),
366  nullptr,
367  "Cannot GetObject (through baseBCopy) for a BaseA Object");
368 
369  //
370  // Now, change the underlying type of the objects to be the derived types.
371  //
372  baseA = CreateObject<DerivedA>();
373  NS_TEST_ASSERT_MSG_NE(baseA,
374  nullptr,
375  "Unable to CreateObject<DerivedA> with implicit cast to BaseA");
376 
377  baseB = CreateObject<DerivedB>();
378  NS_TEST_ASSERT_MSG_NE(baseB,
379  nullptr,
380  "Unable to CreateObject<DerivedB> with implicit cast to BaseB");
381 
382  //
383  // Create an aggregation of two objects, both of the derived types; and leave
384  // an unaggregated copy of one lying around.
385  //
386  baseBCopy = baseB;
387  baseA->AggregateObject(baseB);
388 
389  //
390  // We should be able to ask the aggregation (through baseA) for the DerivedB part
391  //
392  NS_TEST_ASSERT_MSG_NE(baseA->GetObject<DerivedB>(),
393  nullptr,
394  "Cannot GetObject (through baseA) for DerivedB Object");
395 
396  //
397  // Since the DerivedB is also a BaseB, we should be able to ask the aggregation
398  // (through baseA) for the BaseB part
399  //
400  NS_TEST_ASSERT_MSG_NE(baseA->GetObject<BaseB>(),
401  nullptr,
402  "Cannot GetObject (through baseA) for BaseB Object");
403 
404  //
405  // We should be able to ask the aggregation (through baseB) for the DerivedA part
406  //
407  NS_TEST_ASSERT_MSG_NE(baseB->GetObject<DerivedA>(),
408  nullptr,
409  "Cannot GetObject (through baseB) for DerivedA Object");
410 
411  //
412  // Since the DerivedA is also a BaseA, we should be able to ask the aggregation
413  // (through baseB) for the BaseA part
414  //
415  NS_TEST_ASSERT_MSG_NE(baseB->GetObject<BaseA>(),
416  nullptr,
417  "Cannot GetObject (through baseB) for BaseA Object");
418 
419  //
420  // baseBCopy is a copy of the original Ptr to the Object BaseB. Even though
421  // we didn't use baseBCopy directly in the aggregations, the object to which
422  // it points was used, therefore, we should be able to use baseBCopy as if
423  // it were baseB (same underlying Object) and get a BaseA and a DerivedA out
424  // of the aggregation through baseBCopy.
425  //
426  NS_TEST_ASSERT_MSG_NE(baseBCopy->GetObject<BaseA>(),
427  nullptr,
428  "Cannot GetObject (through baseBCopy) for a BaseA Object");
429  NS_TEST_ASSERT_MSG_NE(baseBCopy->GetObject<DerivedA>(),
430  nullptr,
431  "Cannot GetObject (through baseBCopy) for a BaseA Object");
432 
433  //
434  // Since the Ptr<BaseB> is actually a DerivedB, we should be able to ask the
435  // aggregation (through baseB) for the DerivedB part
436  //
437  NS_TEST_ASSERT_MSG_NE(baseB->GetObject<DerivedB>(),
438  nullptr,
439  "Cannot GetObject (through baseB) for DerivedB Object");
440 
441  //
442  // Since the DerivedB was cast to a BaseB, we should be able to ask the
443  // aggregation (through baseB) for the BaseB part
444  //
445  NS_TEST_ASSERT_MSG_NE(baseB->GetObject<BaseB>(),
446  nullptr,
447  "Cannot GetObject (through baseB) for BaseB Object");
448 
449  //
450  // Make sure reference counting works in the aggregate. Create two Objects
451  // and aggregate them, then release one of them. The aggregation should
452  // keep a reference to both and the Object we released should still be there.
453  //
454  baseA = CreateObject<BaseA>();
455  NS_TEST_ASSERT_MSG_NE(baseA, nullptr, "Unable to CreateObject<BaseA>");
456 
457  baseB = CreateObject<BaseB>();
458  NS_TEST_ASSERT_MSG_NE(baseB, nullptr, "Unable to CreateObject<BaseA>");
459 
460  baseA->AggregateObject(baseB);
461  baseA = nullptr;
462 
463  baseA = baseB->GetObject<BaseA>();
464  NS_TEST_ASSERT_MSG_NE(baseA, nullptr, "Unable to GetObject on released object");
465 }
466 
472 {
473  public:
477  ~ObjectFactoryTestCase() override;
478 
479  private:
480  void DoRun() override;
481 };
482 
484  : TestCase("Check ObjectFactory functionality")
485 {
486 }
487 
489 {
490 }
491 
492 void
494 {
495  ObjectFactory factory;
496 
497  //
498  // Create an Object of type BaseA through an object factory.
499  //
500  factory.SetTypeId(BaseA::GetTypeId());
501  Ptr<Object> a = factory.Create();
502  NS_TEST_ASSERT_MSG_EQ(!a, 0, "Unable to factory.Create() a BaseA");
503 
504  //
505  // What we made should be a BaseA, not have anything to do with a DerivedA
506  //
507  NS_TEST_ASSERT_MSG_NE(!a->GetObject<BaseA>(DerivedA::GetTypeId()),
508  0,
509  "BaseA is unexpectedly a DerivedA also");
510 
511  //
512  // The BaseA we got should not respond to a GetObject for DerivedA
513  //
514  NS_TEST_ASSERT_MSG_NE(!a->GetObject<DerivedA>(),
515  0,
516  "BaseA unexpectedly responds to GetObject for DerivedA");
517 
518  //
519  // Now tell the factory to make DerivedA Objects and create one with an
520  // implied cast back to a BaseA
521  //
522  factory.SetTypeId(DerivedA::GetTypeId());
523  a = factory.Create();
524 
525  //
526  // Since the DerivedA has a BaseA part, we should be able to use GetObject to
527  // dynamically cast back to a BaseA.
528  //
529  NS_TEST_ASSERT_MSG_EQ(a->GetObject<BaseA>(),
530  a,
531  "Unable to use GetObject as dynamic_cast<BaseA>()");
532 
533  //
534  // Since a is already a BaseA and is really a DerivedA, we should be able to
535  // GetObject for the DerivedA and cast it back to a BaseA getting the same
536  // value that is there.
537  //
538  NS_TEST_ASSERT_MSG_EQ(a->GetObject<BaseA>(DerivedA::GetTypeId()),
539  a,
540  "GetObject with implied cast returns different Ptr");
541 
542  //
543  // Since a declared a BaseA, even if it is really a DerivedA, we should not
544  // be able to GetObject for a DerivedA since this would break the type
545  // declaration.
546  //
547  NS_TEST_ASSERT_MSG_EQ(!a->GetObject<DerivedA>(),
548  0,
549  "Unexpectedly able to work around C++ type system");
550 }
551 
557 {
558  public:
560  ObjectTestSuite();
561 };
562 
564  : TestSuite("object")
565 {
569 }
570 
576 
577 } // namespace tests
578 
579 } // namespace ns3
static ns3::TypeId GetTypeId()
Register this type.
static ns3::TypeId GetTypeId()
Register this type.
static ns3::TypeId GetTypeId()
Register this type.
void DoDispose() override
Destructor implementation.
void DoDispose() override
Destructor implementation.
static ns3::TypeId GetTypeId()
Register this type.
Instantiate subclasses of ns3::Object.
Ptr< Object > Create() const
Create an Object instance of the configured TypeId.
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
A base class which provides memory management and object aggregation.
Definition: object.h:89
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
a unique identifier for an interface.
Definition: type-id.h:59
TypeId HideFromDocumentation()
Hide this TypeId from documentation.
Definition: type-id.cc:1151
TypeId AddConstructor()
Record in this TypeId the fact that the default constructor is accessible.
Definition: type-id.h:651
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
Test we can aggregate Objects.
~AggregateObjectTestCase() override
Destructor.
void DoRun() override
Implementation to actually run this TestCase.
Test we can make Objects using CreateObject.
~CreateObjectTestCase() override
Destructor.
void DoRun() override
Implementation to actually run this TestCase.
Test an Object factory can create Objects.
void DoRun() override
Implementation to actually run this TestCase.
~ObjectFactoryTestCase() override
Destructor.
The Test Suite that glues the Test Cases together.
static ObjectTestSuite g_objectTestSuite
ObjectTestSuite instance variable.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
#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:144
#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:564
Every class exported by the ns3 library is enclosed in the ns3 namespace.