A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
object-test-suite.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2007 INRIA, Gustavo Carneiro
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Gustavo Carneiro <gjcarneiro@gmail.com>,
7 * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
8 */
9#include "ns3/assert.h"
10#include "ns3/object-factory.h"
11#include "ns3/object.h"
12#include "ns3/test.h"
13
14/**
15 * \file
16 * \ingroup core-tests
17 * \ingroup object
18 * \ingroup object-tests
19 * Object test suite.
20 */
21
22/**
23 * \ingroup core-tests
24 * \defgroup object-tests Object test suite
25 */
26
27namespace
28{
29
30/**
31 * \ingroup object-tests
32 * Base class A.
33 */
34class BaseA : public ns3::Object
35{
36 public:
37 /**
38 * Register this type.
39 * \return The TypeId.
40 */
42 {
43 static ns3::TypeId tid = ns3::TypeId("ObjectTest:BaseA")
44 .SetParent<Object>()
45 .SetGroupName("Core")
48 return tid;
49 }
50
51 /** Constructor. */
53 {
54 }
55};
56
57/**
58 * \ingroup object-tests
59 * Derived class A.
60 */
61class DerivedA : public BaseA
62{
63 public:
64 /**
65 * Register this type.
66 * \return The TypeId.
67 */
69 {
70 static ns3::TypeId tid = ns3::TypeId("ObjectTest:DerivedA")
72 .SetGroupName("Core")
73 .HideFromDocumentation()
74 .AddConstructor<DerivedA>();
75 return tid;
76 }
77
78 /** Constructor. */
80 {
81 }
82
83 protected:
84 void DoDispose() override
85 {
87 }
88};
89
90/**
91 * \ingroup object-tests
92 * Base class B.
93 */
94class BaseB : public ns3::Object
95{
96 public:
97 /**
98 * Register this type.
99 * \return The TypeId.
100 */
102 {
103 static ns3::TypeId tid = ns3::TypeId("ObjectTest:BaseB")
104 .SetParent<Object>()
105 .SetGroupName("Core")
108 return tid;
109 }
110
111 /** Constructor. */
113 {
114 }
115};
116
117/**
118 * \ingroup object-tests
119 * Derived class B.
120 */
121class DerivedB : public BaseB
122{
123 public:
124 /**
125 * Register this type.
126 * \return The TypeId.
127 */
129 {
130 static ns3::TypeId tid = ns3::TypeId("ObjectTest:DerivedB")
131 .SetParent<BaseB>()
132 .SetGroupName("Core")
133 .HideFromDocumentation()
134 .AddConstructor<DerivedB>();
135 return tid;
136 }
137
138 /** Constructor. */
140 {
141 }
142
143 protected:
144 void DoDispose() override
145 {
147 }
148};
149
154
155} // unnamed namespace
156
157namespace ns3
158{
159
160namespace tests
161{
162
163/**
164 * \ingroup object-tests
165 * Test we can make Objects using CreateObject.
166 */
168{
169 public:
170 /** Constructor. */
172 /** Destructor. */
173 ~CreateObjectTestCase() override;
174
175 private:
176 void DoRun() override;
177};
178
180 : TestCase("Check CreateObject<Type> template function")
181{
182}
183
187
188void
190{
192 NS_TEST_ASSERT_MSG_NE(baseA, nullptr, "Unable to CreateObject<BaseA>");
193
194 //
195 // Since baseA is a BaseA, we must be able to successfully ask for a BaseA.
196 //
197 NS_TEST_ASSERT_MSG_EQ(baseA->GetObject<BaseA>(),
198 baseA,
199 "GetObject() of same type returns different Ptr");
200
201 //
202 // Since BaseA is a BaseA and not a DerivedA, we must not find a DerivedA if we look.
203 //
204 NS_TEST_ASSERT_MSG_NE(!baseA->GetObject<DerivedA>(),
205 0,
206 "GetObject() of unrelated type returns nonzero pointer");
207
208 //
209 // Since baseA is not a BaseA, we must not be able to ask for a DerivedA even if we
210 // try an implied cast back to a BaseA.
211 //
212 NS_TEST_ASSERT_MSG_NE(!baseA->GetObject<BaseA>(DerivedA::GetTypeId()),
213 0,
214 "GetObject() of unrelated returns nonzero Ptr");
215
216 baseA = CreateObject<DerivedA>();
218 nullptr,
219 "Unable to CreateObject<DerivedA> with implicit cast to BaseA");
220
221 //
222 // If we create a DerivedA and cast it to a BaseA, then if we do a GetObject for
223 // that BaseA we should get the same address (same Object).
224 //
225 NS_TEST_ASSERT_MSG_EQ(baseA->GetObject<BaseA>(), baseA, "Unable to GetObject<BaseA> on BaseA");
226
227 //
228 // Since we created a DerivedA and cast it to a BaseA, we should be able to
229 // get back a DerivedA and it should be the original Ptr.
230 //
231 NS_TEST_ASSERT_MSG_EQ(baseA->GetObject<DerivedA>(),
232 baseA,
233 "GetObject() of the original type returns different Ptr");
234
235 // If we created a DerivedA and cast it to a BaseA, then we GetObject for the
236 // same DerivedA and cast it back to the same BaseA, we should get the same
237 // object.
238 //
239 NS_TEST_ASSERT_MSG_EQ(baseA->GetObject<BaseA>(DerivedA::GetTypeId()),
240 baseA,
241 "GetObject returns different Ptr");
242}
243
244/**
245 * \ingroup object-tests
246 * Test we can aggregate Objects.
247 */
249{
250 public:
251 /** Constructor. */
253 /** Destructor. */
254 ~AggregateObjectTestCase() override;
255
256 private:
257 void DoRun() override;
258};
259
261 : TestCase("Check Object aggregation functionality")
262{
263}
264
268
269void
271{
273 NS_TEST_ASSERT_MSG_NE(baseA, nullptr, "Unable to CreateObject<BaseA>");
274
276 NS_TEST_ASSERT_MSG_NE(baseB, nullptr, "Unable to CreateObject<BaseB>");
277
278 Ptr<BaseB> baseBCopy = baseB;
279 NS_TEST_ASSERT_MSG_NE(baseBCopy, nullptr, "Unable to copy BaseB");
280
281 //
282 // Make an aggregation of a BaseA object and a BaseB object.
283 //
284 baseA->AggregateObject(baseB);
285
286 //
287 // We should be able to ask the aggregation (through baseA) for the BaseA part
288 // of the aggregation.
289 //
290 NS_TEST_ASSERT_MSG_NE(baseA->GetObject<BaseA>(),
291 nullptr,
292 "Cannot GetObject (through baseA) for BaseA Object");
293
294 //
295 // There is no DerivedA in this picture, so we should not be able to GetObject
296 // for that type.
297 //
298 NS_TEST_ASSERT_MSG_NE(!baseA->GetObject<DerivedA>(),
299 0,
300 "Unexpectedly found a DerivedA through baseA");
301
302 //
303 // We should be able to ask the aggregation (through baseA) for the BaseB part
304 //
305 NS_TEST_ASSERT_MSG_NE(baseA->GetObject<BaseB>(),
306 nullptr,
307 "Cannot GetObject (through baseA) for BaseB Object");
308
309 //
310 // There is no DerivedB in this picture, so we should not be able to GetObject
311 // for that type.
312 //
313 NS_TEST_ASSERT_MSG_NE(!baseA->GetObject<DerivedB>(),
314 0,
315 "Unexpectedly found a DerivedB through baseA");
316
317 //
318 // We should be able to ask the aggregation (through baseA) for the BaseB part
319 //
320 NS_TEST_ASSERT_MSG_NE(baseB->GetObject<BaseB>(),
321 nullptr,
322 "Cannot GetObject (through baseB) for BaseB Object");
323
324 //
325 // There is no DerivedB in this picture, so we should not be able to GetObject
326 // for that type.
327 //
328 NS_TEST_ASSERT_MSG_NE(!baseB->GetObject<DerivedB>(),
329 0,
330 "Unexpectedly found a DerivedB through baseB");
331
332 //
333 // We should be able to ask the aggregation (through baseB) for the BaseA part
334 // of the aggregation.
335 //
336 NS_TEST_ASSERT_MSG_NE(baseB->GetObject<BaseA>(),
337 nullptr,
338 "Cannot GetObject (through baseB) for BaseA Object");
339
340 //
341 // There is no DerivedA in this picture, so we should not be able to GetObject
342 // for that type.
343 //
344 NS_TEST_ASSERT_MSG_NE(!baseB->GetObject<DerivedA>(),
345 0,
346 "Unexpectedly found a DerivedA through baseB");
347
348 //
349 // baseBCopy is a copy of the original Ptr to the Object BaseB. Even though
350 // we didn't use baseBCopy directly in the aggregations, the object to which
351 // it points was used, therefore, we should be able to use baseBCopy as if
352 // it were baseB and get a BaseA out of the aggregation.
353 //
354 NS_TEST_ASSERT_MSG_NE(baseBCopy->GetObject<BaseA>(),
355 nullptr,
356 "Cannot GetObject (through baseBCopy) for a BaseA Object");
357
358 //
359 // Now, change the underlying type of the objects to be the derived types.
360 //
361 baseA = CreateObject<DerivedA>();
363 nullptr,
364 "Unable to CreateObject<DerivedA> with implicit cast to BaseA");
365
366 baseB = CreateObject<DerivedB>();
368 nullptr,
369 "Unable to CreateObject<DerivedB> with implicit cast to BaseB");
370
371 //
372 // Create an aggregation of two objects, both of the derived types; and leave
373 // an unaggregated copy of one lying around.
374 //
375 baseBCopy = baseB;
376 baseA->AggregateObject(baseB);
377
378 //
379 // We should be able to ask the aggregation (through baseA) for the DerivedB part
380 //
381 NS_TEST_ASSERT_MSG_NE(baseA->GetObject<DerivedB>(),
382 nullptr,
383 "Cannot GetObject (through baseA) for DerivedB Object");
384
385 //
386 // Since the DerivedB is also a BaseB, we should be able to ask the aggregation
387 // (through baseA) for the BaseB part
388 //
389 NS_TEST_ASSERT_MSG_NE(baseA->GetObject<BaseB>(),
390 nullptr,
391 "Cannot GetObject (through baseA) for BaseB Object");
392
393 //
394 // We should be able to ask the aggregation (through baseB) for the DerivedA part
395 //
396 NS_TEST_ASSERT_MSG_NE(baseB->GetObject<DerivedA>(),
397 nullptr,
398 "Cannot GetObject (through baseB) for DerivedA Object");
399
400 //
401 // Since the DerivedA is also a BaseA, we should be able to ask the aggregation
402 // (through baseB) for the BaseA part
403 //
404 NS_TEST_ASSERT_MSG_NE(baseB->GetObject<BaseA>(),
405 nullptr,
406 "Cannot GetObject (through baseB) for BaseA Object");
407
408 //
409 // baseBCopy is a copy of the original Ptr to the Object BaseB. Even though
410 // we didn't use baseBCopy directly in the aggregations, the object to which
411 // it points was used, therefore, we should be able to use baseBCopy as if
412 // it were baseB (same underlying Object) and get a BaseA and a DerivedA out
413 // of the aggregation through baseBCopy.
414 //
415 NS_TEST_ASSERT_MSG_NE(baseBCopy->GetObject<BaseA>(),
416 nullptr,
417 "Cannot GetObject (through baseBCopy) for a BaseA Object");
418 NS_TEST_ASSERT_MSG_NE(baseBCopy->GetObject<DerivedA>(),
419 nullptr,
420 "Cannot GetObject (through baseBCopy) for a BaseA Object");
421
422 //
423 // Since the Ptr<BaseB> is actually a DerivedB, we should be able to ask the
424 // aggregation (through baseB) for the DerivedB part
425 //
426 NS_TEST_ASSERT_MSG_NE(baseB->GetObject<DerivedB>(),
427 nullptr,
428 "Cannot GetObject (through baseB) for DerivedB Object");
429
430 //
431 // Since the DerivedB was cast to a BaseB, we should be able to ask the
432 // aggregation (through baseB) for the BaseB part
433 //
434 NS_TEST_ASSERT_MSG_NE(baseB->GetObject<BaseB>(),
435 nullptr,
436 "Cannot GetObject (through baseB) for BaseB Object");
437
438 //
439 // Make sure reference counting works in the aggregate. Create two Objects
440 // and aggregate them, then release one of them. The aggregation should
441 // keep a reference to both and the Object we released should still be there.
442 //
443 baseA = CreateObject<BaseA>();
444 NS_TEST_ASSERT_MSG_NE(baseA, nullptr, "Unable to CreateObject<BaseA>");
445
446 baseB = CreateObject<BaseB>();
447 NS_TEST_ASSERT_MSG_NE(baseB, nullptr, "Unable to CreateObject<BaseA>");
448
449 baseA->AggregateObject(baseB);
450 baseA = nullptr;
451
452 baseA = baseB->GetObject<BaseA>();
453 NS_TEST_ASSERT_MSG_NE(baseA, nullptr, "Unable to GetObject on released object");
454}
455
456/**
457 * \ingroup object-tests
458 * Test we can aggregate Objects.
459 */
461{
462 public:
463 /** Constructor. */
465 /** Destructor. */
467
468 private:
469 void DoRun() override;
470};
471
473 : TestCase("Check Object unidirectional aggregation functionality")
474{
475}
476
480
481void
483{
484 Ptr<BaseA> baseAOne = CreateObject<BaseA>();
485 NS_TEST_ASSERT_MSG_NE(baseAOne, nullptr, "Unable to CreateObject<BaseA>");
486 Ptr<BaseA> baseATwo = CreateObject<BaseA>();
487 NS_TEST_ASSERT_MSG_NE(baseATwo, nullptr, "Unable to CreateObject<BaseA>");
488
490 NS_TEST_ASSERT_MSG_NE(baseB, nullptr, "Unable to CreateObject<BaseB>");
491
492 //
493 // Make an unidirectional aggregation of a BaseA object and a BaseB object.
494 //
495 baseAOne->UnidirectionalAggregateObject(baseB);
496 baseATwo->UnidirectionalAggregateObject(baseB);
497
498 //
499 // We should be able to ask the aggregation (through baseA) for the BaseB part
500 // on either BaseA objects
501 //
502 NS_TEST_ASSERT_MSG_NE(baseAOne->GetObject<BaseB>(),
503 nullptr,
504 "Cannot GetObject (through baseAOne) for BaseB Object");
505
506 NS_TEST_ASSERT_MSG_NE(baseATwo->GetObject<BaseB>(),
507 nullptr,
508 "Cannot GetObject (through baseATwo) for BaseB Object");
509
511 baseAOne->GetObject<BaseB>(),
512 baseATwo->GetObject<BaseB>(),
513 "GetObject (through baseAOne and baseATwo) for BaseB Object are not equal");
514
515 //
516 // We should not be able to ask the aggregation (through baseB) for the BaseA part
517 // of the aggregation.
518 //
519 NS_TEST_ASSERT_MSG_NE(!baseB->GetObject<BaseA>(),
520 0,
521 "Can GetObject (through baseB) for BaseA Object");
522}
523
524/**
525 * \ingroup object-tests
526 * Test an Object factory can create Objects
527 */
529{
530 public:
531 /** Constructor. */
533 /** Destructor. */
534 ~ObjectFactoryTestCase() override;
535
536 private:
537 void DoRun() override;
538};
539
541 : TestCase("Check ObjectFactory functionality")
542{
543}
544
548
549void
551{
552 ObjectFactory factory;
553
554 //
555 // Create an Object of type BaseA through an object factory.
556 //
557 factory.SetTypeId(BaseA::GetTypeId());
558 Ptr<Object> a = factory.Create();
559 NS_TEST_ASSERT_MSG_EQ(!a, 0, "Unable to factory.Create() a BaseA");
560
561 //
562 // What we made should be a BaseA, not have anything to do with a DerivedA
563 //
564 NS_TEST_ASSERT_MSG_NE(!a->GetObject<BaseA>(DerivedA::GetTypeId()),
565 0,
566 "BaseA is unexpectedly a DerivedA also");
567
568 //
569 // The BaseA we got should not respond to a GetObject for DerivedA
570 //
571 NS_TEST_ASSERT_MSG_NE(!a->GetObject<DerivedA>(),
572 0,
573 "BaseA unexpectedly responds to GetObject for DerivedA");
574
575 //
576 // Now tell the factory to make DerivedA Objects and create one with an
577 // implied cast back to a BaseA
578 //
580 a = factory.Create();
581
582 //
583 // Since the DerivedA has a BaseA part, we should be able to use GetObject to
584 // dynamically cast back to a BaseA.
585 //
586 NS_TEST_ASSERT_MSG_EQ(a->GetObject<BaseA>(),
587 a,
588 "Unable to use GetObject as dynamic_cast<BaseA>()");
589
590 //
591 // Since a is already a BaseA and is really a DerivedA, we should be able to
592 // GetObject for the DerivedA and cast it back to a BaseA getting the same
593 // value that is there.
594 //
595 NS_TEST_ASSERT_MSG_EQ(a->GetObject<BaseA>(DerivedA::GetTypeId()),
596 a,
597 "GetObject with implied cast returns different Ptr");
598
599 //
600 // Since a declared a BaseA, even if it is really a DerivedA, we should not
601 // be able to GetObject for a DerivedA since this would break the type
602 // declaration.
603 //
604 NS_TEST_ASSERT_MSG_EQ(!a->GetObject<DerivedA>(),
605 0,
606 "Unexpectedly able to work around C++ type system");
607}
608
609/**
610 * \ingroup object-tests
611 * The Test Suite that glues the Test Cases together.
612 */
614{
615 public:
616 /** Constructor. */
618};
619
628
629/**
630 * \ingroup object-tests
631 * ObjectTestSuite instance variable.
632 */
634
635} // namespace tests
636
637} // 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:78
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
Smart pointer class similar to boost::intrusive_ptr.
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
a unique identifier for an interface.
Definition type-id.h:48
TypeId HideFromDocumentation()
Hide this TypeId from documentation.
Definition type-id.cc:1221
TypeId AddConstructor()
Record in this TypeId the fact that the default constructor is accessible.
Definition type-id.h:670
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
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.
void DoRun() override
Implementation to actually run this TestCase.
static ObjectTestSuite g_objectTestSuite
ObjectTestSuite instance variable.
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
#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:134
#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:554
Every class exported by the ns3 library is enclosed in the ns3 namespace.