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 
40 namespace {
41 
46 class BaseA : public ns3::Object
47 {
48 public:
53  static ns3::TypeId GetTypeId (void)
54  {
55  static ns3::TypeId tid = ns3::TypeId ("ObjectTest:BaseA")
56  .SetParent<Object> ()
57  .SetGroupName ("Core")
59  .AddConstructor<BaseA> ();
60  return tid;
61  }
63  BaseA () {}
64 };
65 
70 class DerivedA : public BaseA
71 {
72 public:
77  static ns3::TypeId GetTypeId (void)
78  {
79  static ns3::TypeId tid = ns3::TypeId ("ObjectTest:DerivedA")
80  .SetParent<BaseA> ()
81  .SetGroupName ("Core")
82  .HideFromDocumentation ()
83  .AddConstructor<DerivedA> ();
84  return tid;
85  }
87  DerivedA () {}
88 protected:
89  virtual void DoDispose (void) {
90  BaseA::DoDispose ();
91  }
92 };
93 
98 class BaseB : public ns3::Object
99 {
100 public:
105  static ns3::TypeId GetTypeId (void)
106  {
107  static ns3::TypeId tid = ns3::TypeId ("ObjectTest:BaseB")
108  .SetParent<Object> ()
109  .SetGroupName ("Core")
111  .AddConstructor<BaseB> ();
112  return tid;
113  }
115  BaseB () {}
116 };
117 
122 class DerivedB : public BaseB
123 {
124 public:
129  static ns3::TypeId GetTypeId (void)
130  {
131  static ns3::TypeId tid = ns3::TypeId ("ObjectTest:DerivedB")
132  .SetParent<BaseB> ()
133  .SetGroupName ("Core")
134  .HideFromDocumentation ()
135  .AddConstructor<DerivedB> ();
136  return tid;
137  }
139  DerivedB () {}
140 protected:
141  virtual void DoDispose (void) {
142  BaseB::DoDispose ();
143  }
144 };
145 
147 NS_OBJECT_ENSURE_REGISTERED (DerivedA);
149 NS_OBJECT_ENSURE_REGISTERED (DerivedB);
150 
151 } // unnamed namespace
152 
153 namespace ns3 {
154 
155  namespace tests {
156 
157 
163 {
164 public:
168  virtual ~CreateObjectTestCase ();
169 
170 private:
171  virtual void DoRun (void);
172 };
173 
175  : TestCase ("Check CreateObject<Type> template function")
176 {
177 }
178 
180 {
181 }
182 
183 void
185 {
186  Ptr<BaseA> baseA = CreateObject<BaseA> ();
187  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to CreateObject<BaseA>");
188 
189  //
190  // Since baseA is a BaseA, we must be able to successfully ask for a BaseA.
191  //
192  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<BaseA> (), baseA, "GetObject() of same type returns different Ptr");
193 
194  //
195  // Since BaseA is a BaseA and not a DerivedA, we must not find a DerivedA if we look.
196  //
197  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<DerivedA> (), 0, "GetObject() of unrelated type returns nonzero pointer");
198 
199  //
200  // Since baseA is not a BaseA, we must not be able to ask for a DerivedA even if we
201  // try an implied cast back to a BaseA.
202  //
203  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<BaseA> (DerivedA::GetTypeId ()), 0, "GetObject() of unrelated returns nonzero Ptr");
204 
205  baseA = CreateObject<DerivedA> ();
206  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to CreateObject<DerivedA> with implicit cast to BaseA");
207 
208  //
209  // If we create a DerivedA and cast it to a BaseA, then if we do a GetObject for
210  // that BaseA we should get the same address (same Object).
211  //
212  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<BaseA> (), baseA, "Unable to GetObject<BaseA> on BaseA");
213 
214  //
215  // Since we created a DerivedA and cast it to a BaseA, we should be able to
216  // get back a DerivedA and it should be the original Ptr.
217  //
218  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<DerivedA> (), baseA, "GetObject() of the original type returns different Ptr");
219 
220  // If we created a DerivedA and cast it to a BaseA, then we GetObject for the
221  // same DerivedA and cast it back to the same BaseA, we should get the same
222  // object.
223  //
224  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<BaseA> (DerivedA::GetTypeId ()), baseA, "GetObject returns different Ptr");
225 }
226 
232 {
233 public:
237  virtual ~AggregateObjectTestCase ();
238 
239 private:
240  virtual void DoRun (void);
241 };
242 
244  : TestCase ("Check Object aggregation functionality")
245 {
246 }
247 
249 {
250 }
251 
252 void
254 {
255  Ptr<BaseA> baseA = CreateObject<BaseA> ();
256  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to CreateObject<BaseA>");
257 
258  Ptr<BaseB> baseB = CreateObject<BaseB> ();
259  NS_TEST_ASSERT_MSG_NE (baseB, 0, "Unable to CreateObject<BaseB>");
260 
261  Ptr<BaseB> baseBCopy = baseB;
262  NS_TEST_ASSERT_MSG_NE (baseBCopy, 0, "Unable to copy BaseB");
263 
264  //
265  // Make an aggregation of a BaseA object and a BaseB object.
266  //
267  baseA->AggregateObject (baseB);
268 
269  //
270  // We should be able to ask the aggregation (through baseA) for the BaseA part
271  // of the aggregation.
272  //
273  NS_TEST_ASSERT_MSG_NE (baseA->GetObject<BaseA> (), 0, "Cannot GetObject (through baseA) for BaseA Object");
274 
275  //
276  // There is no DerivedA in this picture, so we should not be able to GetObject
277  // for that type.
278  //
279  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<DerivedA> (), 0, "Unexpectedly found a DerivedA through baseA");
280 
281  //
282  // We should be able to ask the aggregation (through baseA) for the BaseB part
283  //
284  NS_TEST_ASSERT_MSG_NE (baseA->GetObject<BaseB> (), 0, "Cannot GetObject (through baseA) for BaseB Object");
285 
286  //
287  // There is no DerivedB in this picture, so we should not be able to GetObject
288  // for that type.
289  //
290  NS_TEST_ASSERT_MSG_EQ (baseA->GetObject<DerivedB> (), 0, "Unexpectedly found a DerivedB through baseA");
291 
292  //
293  // We should be able to ask the aggregation (through baseA) for the BaseB part
294  //
295  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<BaseB> (), 0, "Cannot GetObject (through baseB) for BaseB Object");
296 
297  //
298  // There is no DerivedB in this picture, so we should not be able to GetObject
299  // for that type.
300  //
301  NS_TEST_ASSERT_MSG_EQ (baseB->GetObject<DerivedB> (), 0, "Unexpectedly found a DerivedB through baseB");
302 
303  //
304  // We should be able to ask the aggregation (through baseB) for the BaseA part
305  // of the aggregation.
306  //
307  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<BaseA> (), 0, "Cannot GetObject (through baseB) for BaseA Object");
308 
309  //
310  // There is no DerivedA in this picture, so we should not be able to GetObject
311  // for that type.
312  //
313  NS_TEST_ASSERT_MSG_EQ (baseB->GetObject<DerivedA> (), 0, "Unexpectedly found a DerivedA through baseB");
314 
315  //
316  // baseBCopy is a copy of the original Ptr to the Object BaseB. Even though
317  // we didn't use baseBCopy directly in the aggregations, the object to which
318  // it points was used, therefore, we should be able to use baseBCopy as if
319  // it were baseB and get a BaseA out of the aggregation.
320  //
321  NS_TEST_ASSERT_MSG_NE (baseBCopy->GetObject<BaseA> (), 0, "Cannot GetObject (through baseBCopy) for a BaseA Object");
322 
323  //
324  // Now, change the underlying type of the objects to be the derived types.
325  //
326  baseA = CreateObject<DerivedA> ();
327  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to CreateObject<DerivedA> with implicit cast to BaseA");
328 
329  baseB = CreateObject<DerivedB> ();
330  NS_TEST_ASSERT_MSG_NE (baseB, 0, "Unable to CreateObject<DerivedB> with implicit cast to BaseB");
331 
332  //
333  // Create an aggregation of two objects, both of the derived types; and leave
334  // an unaggregated copy of one lying around.
335  //
336  baseBCopy = baseB;
337  baseA->AggregateObject (baseB);
338 
339  //
340  // We should be able to ask the aggregation (through baseA) for the DerivedB part
341  //
342  NS_TEST_ASSERT_MSG_NE (baseA->GetObject<DerivedB> (), 0, "Cannot GetObject (through baseA) for DerivedB Object");
343 
344  //
345  // Since the DerivedB is also a BaseB, we should be able to ask the aggregation
346  // (through baseA) for the BaseB part
347  //
348  NS_TEST_ASSERT_MSG_NE (baseA->GetObject<BaseB> (), 0, "Cannot GetObject (through baseA) for BaseB Object");
349 
350  //
351  // We should be able to ask the aggregation (through baseB) for the DerivedA part
352  //
353  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<DerivedA> (), 0, "Cannot GetObject (through baseB) for DerivedA Object");
354 
355  //
356  // Since the DerivedA is also a BaseA, we should be able to ask the aggregation
357  // (through baseB) for the BaseA part
358  //
359  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<BaseA> (), 0, "Cannot GetObject (through baseB) for BaseA Object");
360 
361  //
362  // baseBCopy is a copy of the original Ptr to the Object BaseB. Even though
363  // we didn't use baseBCopy directly in the aggregations, the object to which
364  // it points was used, therefore, we should be able to use baseBCopy as if
365  // it were baseB (same underlying Object) and get a BaseA and a DerivedA out
366  // of the aggregation through baseBCopy.
367  //
368  NS_TEST_ASSERT_MSG_NE (baseBCopy->GetObject<BaseA> (), 0, "Cannot GetObject (through baseBCopy) for a BaseA Object");
369  NS_TEST_ASSERT_MSG_NE (baseBCopy->GetObject<DerivedA> (), 0, "Cannot GetObject (through baseBCopy) for a BaseA Object");
370 
371  //
372  // Since the Ptr<BaseB> is actually a DerivedB, we should be able to ask the
373  // aggregation (through baseB) for the DerivedB part
374  //
375  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<DerivedB> (), 0, "Cannot GetObject (through baseB) for DerivedB Object");
376 
377  //
378  // Since the DerivedB was cast to a BaseB, we should be able to ask the
379  // aggregation (through baseB) for the BaseB part
380  //
381  NS_TEST_ASSERT_MSG_NE (baseB->GetObject<BaseB> (), 0, "Cannot GetObject (through baseB) for BaseB Object");
382 
383  //
384  // Make sure reference counting works in the aggregate. Create two Objects
385  // and aggregate them, then release one of them. The aggregation should
386  // keep a reference to both and the Object we released should still be there.
387  //
388  baseA = CreateObject<BaseA> ();
389  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to CreateObject<BaseA>");
390 
391  baseB = CreateObject<BaseB> ();
392  NS_TEST_ASSERT_MSG_NE (baseB, 0, "Unable to CreateObject<BaseA>");
393 
394  baseA->AggregateObject (baseB);
395  baseA = 0;
396 
397  baseA = baseB->GetObject<BaseA> ();
398  NS_TEST_ASSERT_MSG_NE (baseA, 0, "Unable to GetObject on released object");
399 }
400 
406 {
407 public:
411  virtual ~ObjectFactoryTestCase ();
412 
413 private:
414  virtual void DoRun (void);
415 };
416 
418  : TestCase ("Check ObjectFactory functionality")
419 {
420 }
421 
423 {
424 }
425 
426 void
428 {
429  ObjectFactory factory;
430 
431  //
432  // Create an Object of type BaseA through an object factory.
433  //
434  factory.SetTypeId (BaseA::GetTypeId ());
435  Ptr<Object> a = factory.Create ();
436  NS_TEST_ASSERT_MSG_NE (a, 0, "Unable to factory.Create() a BaseA");
437 
438  //
439  // What we made should be a BaseA, not have anything to do with a DerivedA
440  //
441  NS_TEST_ASSERT_MSG_EQ (a->GetObject<BaseA> (DerivedA::GetTypeId ()), 0, "BaseA is unexpectedly a DerivedA also");
442 
443  //
444  // The BaseA we got should not respond to a GetObject for DerivedA
445  //
446  NS_TEST_ASSERT_MSG_EQ (a->GetObject<DerivedA> (), 0, "BaseA unexpectedly responds to GetObject for DerivedA");
447 
448  //
449  // Now tell the factory to make DerivedA Objects and create one with an
450  // implied cast back to a BaseA
451  //
452  factory.SetTypeId (DerivedA::GetTypeId ());
453  a = factory.Create ();
454 
455  //
456  // Since the DerivedA has a BaseA part, we should be able to use GetObject to
457  // dynamically cast back to a BaseA.
458  //
459  NS_TEST_ASSERT_MSG_EQ (a->GetObject<BaseA> (), a, "Unable to use GetObject as dynamic_cast<BaseA>()");
460 
461  //
462  // Since a is already a BaseA and is really a DerivedA, we should be able to
463  // GetObject for the DerivedA and cast it back to a BaseA getting the same
464  // value that is there.
465  //
466  NS_TEST_ASSERT_MSG_EQ (a->GetObject<BaseA> (DerivedA::GetTypeId ()), a, "GetObject with implied cast returns different Ptr");
467 
468  //
469  // Since a declared a BaseA, even if it is really a DerivedA, we should not
470  // be able to GetOBject for a DerivedA since this would break the type
471  // declaration.
472  //
473  NS_TEST_ASSERT_MSG_NE (a->GetObject<DerivedA> (), 0, "Unexpectedly able to work around C++ type system");
474 }
475 
481 {
482 public:
484  ObjectTestSuite ();
485 };
486 
488  : TestSuite ("object")
489 {
493 }
494 
500 
501 
502  } // namespace tests
503 
504 } // namespace ns3
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
TypeId AddConstructor(void)
Record in this TypeId the fact that the default constructor is accessible.
Definition: type-id.h:652
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
static ns3::TypeId GetTypeId(void)
Register this type.
A suite of tests to run.
Definition: test.h:1342
virtual ~AggregateObjectTestCase()
Destructor.
virtual ~ObjectFactoryTestCase()
Destructor.
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
Test we can aggregate Objects.
encapsulates test code
Definition: test.h:1155
virtual void DoDispose(void)
Destructor implementation.
virtual void DoDispose(void)
Destructor implementation.
virtual void DoRun(void)
Implementation to actually run this TestCase.
Ptr< Object > Create(void) const
Create an Object instance of the configured TypeId.
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
#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:168
static ObjectTestSuite g_objectTestSuite
ObjectTestSuite instance variable.
static ns3::TypeId GetTypeId(void)
Register this type.
Test we can make Objects using CreateObject.
virtual void DoRun(void)
Implementation to actually run this TestCase.
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:459
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static ns3::TypeId GetTypeId(void)
Register this type.
The Test Suite that glues the Test Cases together.
Test an Object factory can create Objects.
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:624
virtual ~CreateObjectTestCase()
Destructor.
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:915
TypeId HideFromDocumentation(void)
Hide this TypeId from documentation.
Definition: type-id.cc:1128