A Discrete-Event Network Simulator
API
attribute-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009 University of Washington
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 
18 #include "ns3/boolean.h"
19 #include "ns3/callback.h"
20 #include "ns3/config.h"
21 #include "ns3/double.h"
22 #include "ns3/enum.h"
23 #include "ns3/integer.h"
24 #include "ns3/nstime.h"
25 #include "ns3/object-factory.h"
26 #include "ns3/object-map.h"
27 #include "ns3/object-vector.h"
28 #include "ns3/object.h"
29 #include "ns3/pointer.h"
30 #include "ns3/random-variable-stream.h"
31 #include "ns3/string.h"
32 #include "ns3/test.h"
33 #include "ns3/trace-source-accessor.h"
34 #include "ns3/traced-value.h"
35 #include "ns3/uinteger.h"
36 
37 using namespace ns3;
38 
39 namespace ns3
40 {
41 
60 {
61  public:
63  {
64  }
65 
72  typedef void (*TracedValueCallback)(const ValueClassTest oldValue,
73  const ValueClassTest newValue);
74 };
75 
82 bool
83 operator!=(const ValueClassTest& a [[maybe_unused]], const ValueClassTest& b [[maybe_unused]])
84 {
85  return true;
86 }
87 
95 std::ostream&
96 operator<<(std::ostream& os, ValueClassTest v [[maybe_unused]])
97 {
98  return os;
99 }
100 
108 std::istream&
109 operator>>(std::istream& is, ValueClassTest& v [[maybe_unused]])
110 {
111  return is;
112 }
113 
116 
117 } // namespace ns3
118 
124 class Derived : public Object
125 {
126  public:
131  static TypeId GetTypeId()
132  {
133  static TypeId tid = TypeId("ns3::Derived").AddConstructor<Derived>().SetParent<Object>();
134  return tid;
135  }
136 
138  {
139  }
140 };
141 
143 
150 {
151  public:
153  enum Test_e
154  {
157  TEST_C
158  };
159 
164  static TypeId GetTypeId()
165  {
166  static TypeId tid =
167  TypeId("ns3::AttributeObjectTest")
169  .SetParent<Object>()
170  .HideFromDocumentation()
171  .AddAttribute("TestBoolName",
172  "help text",
173  BooleanValue(false),
176  .AddAttribute("TestBoolA",
177  "help text",
178  BooleanValue(false),
182  .AddAttribute("TestInt16",
183  "help text",
184  IntegerValue(-2),
186  MakeIntegerChecker<int16_t>())
187  .AddAttribute("TestInt16WithBounds",
188  "help text",
189  IntegerValue(-2),
191  MakeIntegerChecker<int16_t>(-5, 10))
192  .AddAttribute("TestInt16SetGet",
193  "help text",
194  IntegerValue(6),
197  MakeIntegerChecker<int16_t>())
198  .AddAttribute("TestUint8",
199  "help text",
200  UintegerValue(1),
202  MakeUintegerChecker<uint8_t>())
203  .AddAttribute("TestEnum",
204  "help text",
205  EnumValue(TEST_A),
207  MakeEnumChecker(TEST_A, "TestA", TEST_B, "TestB", TEST_C, "TestC"))
208  .AddAttribute("TestEnumSetGet",
209  "help text",
210  EnumValue(TEST_B),
213  MakeEnumChecker(TEST_A, "TestA", TEST_B, "TestB", TEST_C, "TestC"))
214  .AddAttribute("TestRandom",
215  "help text",
216  StringValue("ns3::ConstantRandomVariable[Constant=1.0]"),
218  MakePointerChecker<RandomVariableStream>())
219  .AddAttribute("TestFloat",
220  "help text",
221  DoubleValue(-1.1),
223  MakeDoubleChecker<float>())
224  .AddAttribute("TestVector1",
225  "help text",
228  MakeObjectVectorChecker<Derived>())
229  .AddAttribute("TestVector2",
230  "help text",
234  MakeObjectVectorChecker<Derived>())
235  .AddAttribute("TestMap1",
236  "help text",
237  ObjectMapValue(),
239  MakeObjectMapChecker<Derived>())
240  .AddAttribute("IntegerTraceSource1",
241  "help text",
242  IntegerValue(-2),
244  MakeIntegerChecker<int8_t>())
245  .AddAttribute("IntegerTraceSource2",
246  "help text",
247  IntegerValue(-2),
250  MakeIntegerChecker<int8_t>())
251  .AddAttribute("UIntegerTraceSource",
252  "help text",
253  UintegerValue(2),
255  MakeIntegerChecker<uint8_t>())
256  .AddAttribute("DoubleTraceSource",
257  "help text",
258  DoubleValue(2),
260  MakeDoubleChecker<double>())
261  .AddAttribute("BoolTraceSource",
262  "help text",
263  BooleanValue(false),
266  .AddAttribute("EnumTraceSource",
267  "help text",
268  EnumValue(TEST_A),
270  MakeEnumChecker(TEST_A, "TestA"))
271  .AddAttribute("ValueClassSource",
272  "help text",
274  MakeValueClassTestAccessor(&AttributeObjectTest::m_valueSrc),
275  MakeValueClassTestChecker())
276  .AddTraceSource("Source1",
277  "help test",
279  "ns3::TracedValueCallback::Int8")
280  .AddTraceSource("Source2",
281  "help text",
283  "ns3::AttributeObjectTest::NumericTracedCallback")
284  .AddTraceSource("ValueSource",
285  "help text",
287  "ns3::ValueClassTest::TracedValueCallback")
288  .AddAttribute("Pointer",
289  "help text",
290  PointerValue(),
292  MakePointerChecker<Derived>())
293  .AddAttribute("PointerInitialized",
294  "help text",
295  StringValue("ns3::Derived"),
297  MakePointerChecker<Derived>())
298  .AddAttribute("PointerInitialized2",
299  "help text",
300  StringValue("ns3::Derived[]"),
302  MakePointerChecker<Derived>())
303  .AddAttribute("Callback",
304  "help text",
305  CallbackValue(),
308  .AddAttribute("TestTimeWithBounds",
309  "help text",
310  TimeValue(Seconds(-2)),
312  MakeTimeChecker(Seconds(-5), Seconds(10)))
313  .AddAttribute("TestDeprecated",
314  "help text",
315  BooleanValue(false),
319  "DEPRECATED test working.");
320 
321  return tid;
322  }
323 
325  {
326  }
327 
329  {
330  }
331 
334  {
335  m_vector1.push_back(CreateObject<Derived>());
336  }
337 
340  {
341  m_vector2.push_back(CreateObject<Derived>());
342  }
343 
348  void AddToMap1(uint32_t i)
349  {
350  m_map1.insert(std::pair<uint32_t, Ptr<Derived>>(i, CreateObject<Derived>()));
351  }
352 
359  void InvokeCb(double a, int b, float c)
360  {
361  m_cb(a, b, c);
362  }
363 
368  void InvokeCbValue(int8_t a)
369  {
370  if (!m_cbValue.IsNull())
371  {
372  m_cbValue(a);
373  }
374  }
375 
376  private:
381  void DoSetTestA(bool v)
382  {
383  m_boolTestA = v;
384  }
385 
390  bool DoGetTestA() const
391  {
392  return m_boolTestA;
393  }
394 
399  int16_t DoGetInt16() const
400  {
401  return m_int16SetGet;
402  }
403 
408  void DoSetInt16(int16_t v)
409  {
410  m_int16SetGet = v;
411  }
412 
417  std::size_t DoGetVectorN() const
418  {
419  return m_vector2.size();
420  }
421 
427  Ptr<Derived> DoGetVector(std::size_t i) const
428  {
429  return m_vector2[i];
430  }
431 
437  bool DoSetIntSrc(int8_t v)
438  {
439  m_intSrc2 = v;
440  return true;
441  }
442 
447  int8_t DoGetIntSrc() const
448  {
449  return m_intSrc2;
450  }
451 
458  {
459  m_enumSetGet = v;
460  return true;
461  }
462 
468  {
469  return m_enumSetGet;
470  }
471 
472  bool m_boolTestA;
473  bool m_boolTest;
475  int16_t m_int16;
477  int16_t m_int16SetGet;
478  uint8_t m_uint8;
479  float m_float;
480  enum Test_e m_enum;
481  enum Test_e m_enumSetGet;
483  std::vector<Ptr<Derived>> m_vector1;
484  std::vector<Ptr<Derived>> m_vector2;
485  std::map<uint32_t, Ptr<Derived>> m_map1;
489 
491  typedef void (*NumericTracedCallback)(double, int, float);
502 };
503 
505 
512 template <typename T>
514 {
515  public:
520  AttributeTestCase(std::string description);
521  ~AttributeTestCase() override;
522 
523  private:
524  void DoRun() override;
533  bool CheckGetCodePaths(Ptr<Object> p,
534  std::string attributeName,
535  std::string expectedString,
536  T expectedValue);
537 };
538 
539 template <typename T>
541  : TestCase(description)
542 {
543 }
544 
545 template <typename T>
547 {
548 }
549 
550 template <typename T>
551 bool
553  std::string attributeName,
554  std::string expectedString,
555  T expectedValue)
556 {
557  StringValue stringValue;
558  T actualValue;
559 
560  //
561  // Get an Attribute value through its StringValue representation.
562  //
563  bool ok1 = p->GetAttributeFailSafe(attributeName, stringValue);
564  bool ok2 = stringValue.Get() == expectedString;
565 
566  //
567  // Get the existing boolean value through its particular type representation.
568  //
569  bool ok3 = p->GetAttributeFailSafe(attributeName, actualValue);
570  bool ok4 = expectedValue.Get() == actualValue.Get();
571 
572  return ok1 && ok2 && ok3 && ok4;
573 }
574 
575 // ===========================================================================
576 // The actual Attribute type test cases are specialized for each Attribute type
577 // ===========================================================================
578 template <>
579 void
581 {
583  bool ok;
584 
585  p = CreateObject<AttributeObjectTest>();
586  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
587 
588  //
589  // Set the default value of the BooleanValue and create an object. The new
590  // default value should stick.
591  //
592  Config::SetDefault("ns3::AttributeObjectTest::TestBoolName", StringValue("true"));
593  p = CreateObject<AttributeObjectTest>();
594  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
595 
596  ok = CheckGetCodePaths(p, "TestBoolName", "true", BooleanValue(true));
597  NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value");
598 
599  std::string expected("Attribute 'TestDeprecated' is deprecated: DEPRECATED test working.\n");
600  // Temporarily redirect std::cerr to a stringstream
601  std::stringstream buffer;
602  std::streambuf* oldBuffer = std::cerr.rdbuf(buffer.rdbuf());
603  // Cause the deprecation warning to be sent to the stringstream
604  Config::SetDefault("ns3::AttributeObjectTest::TestDeprecated", BooleanValue(true));
605 
606  // Compare the obtained actual string with the expected string.
607  NS_TEST_ASSERT_MSG_EQ(buffer.str(), expected, "Deprecated attribute not working");
608  // Restore cerr to its original stream buffer
609  std::cerr.rdbuf(oldBuffer);
610 
611  //
612  // Set the default value of the BooleanValue the other way and create an object.
613  // The new default value should stick.
614  //
615  Config::SetDefaultFailSafe("ns3::AttributeObjectTest::TestBoolName", StringValue("false"));
616 
617  p = CreateObject<AttributeObjectTest>();
618  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
619 
620  ok = CheckGetCodePaths(p, "TestBoolName", "false", BooleanValue(false));
621  NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not et properly by default value");
622 
623  //
624  // Set the BooleanValue Attribute to true via SetAttributeFailSafe path.
625  //
626  ok = p->SetAttributeFailSafe("TestBoolName", StringValue("true"));
627  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() \"TestBoolName\" to true");
628 
629  ok = CheckGetCodePaths(p, "TestBoolName", "true", BooleanValue(true));
631  true,
632  "Attribute not set properly by SetAttributeFailSafe() via StringValue");
633 
634  //
635  // Set the BooleanValue to false via SetAttributeFailSafe path.
636  //
637  ok = p->SetAttributeFailSafe("TestBoolName", StringValue("false"));
638  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() \"TestBoolName\" to false");
639 
640  ok = CheckGetCodePaths(p, "TestBoolName", "false", BooleanValue(false));
642  true,
643  "Attribute not set properly by SetAttributeFailSafe() via StringValue");
644 
645  //
646  // Create an object using
647  //
648  p = CreateObject<AttributeObjectTest>();
649  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
650 
651  //
652  // The previous object-based tests checked access directly. Now check through
653  // setter and getter. The code here looks the same, but the underlying
654  // attribute is declared differently in the object. First make sure we can set
655  // to true.
656  //
657  ok = p->SetAttributeFailSafe("TestBoolA", StringValue("true"));
658  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() a boolean value to true");
659 
660  ok = CheckGetCodePaths(p, "TestBoolA", "true", BooleanValue(true));
662  ok,
663  true,
664  "Attribute not set properly by SetAttributeFailSafe() (getter/setter) via StringValue");
665 
666  //
667  // Now Set the BooleanValue to false via the setter.
668  //
669  ok = p->SetAttributeFailSafe("TestBoolA", StringValue("false"));
670  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() a boolean value to false");
671 
672  ok = CheckGetCodePaths(p, "TestBoolA", "false", BooleanValue(false));
674  ok,
675  true,
676  "Attribute not set properly by SetAttributeFailSafe() (getter/setter) via StringValue");
677 }
678 
679 template <>
680 void
682 {
684  bool ok;
685 
686  p = CreateObject<AttributeObjectTest>();
687  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
688 
689  //
690  // When the object is first created, the Attribute should have the default
691  // value.
692  //
693  ok = CheckGetCodePaths(p, "TestInt16", "-2", IntegerValue(-2));
694  NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value");
695 
696  //
697  // Set the Attribute to a negative value through a StringValue.
698  //
699  ok = p->SetAttributeFailSafe("TestInt16", StringValue("-5"));
700  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via StringValue to -5");
701 
702  ok = CheckGetCodePaths(p, "TestInt16", "-5", IntegerValue(-5));
704  true,
705  "Attribute not set properly by SetAttributeFailSafe() via StringValue");
706 
707  //
708  // Set the Attribute to a positive value through a StringValue.
709  //
710  ok = p->SetAttributeFailSafe("TestInt16", StringValue("+2"));
711  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via StringValue to +2");
712 
713  ok = CheckGetCodePaths(p, "TestInt16", "2", IntegerValue(2));
715  true,
716  "Attribute not set properly by SetAttributeFailSafe() via StringValue");
717 
718  //
719  // Set the Attribute to the most negative value of the signed 16-bit range.
720  //
721  ok = p->SetAttributeFailSafe("TestInt16", StringValue("-32768"));
722  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via StringValue to -32768");
723 
724  ok = CheckGetCodePaths(p, "TestInt16", "-32768", IntegerValue(-32768));
726  ok,
727  true,
728  "Attribute not set properly by SetAttributeFailSafe() (most negative) via StringValue");
729 
730  //
731  // Try to set the Attribute past the most negative value of the signed 16-bit
732  // range and make sure the underlying attribute is unchanged.
733  //
734  ok = p->SetAttributeFailSafe("TestInt16", StringValue("-32769"));
736  false,
737  "Unexpectedly could SetAttributeFailSafe() via StringValue to -32769");
738 
739  ok = CheckGetCodePaths(p, "TestInt16", "-32768", IntegerValue(-32768));
740  NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes");
741 
742  //
743  // Set the Attribute to the most positive value of the signed 16-bit range.
744  //
745  ok = p->SetAttributeFailSafe("TestInt16", StringValue("32767"));
746  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via StringValue to 32767");
747 
748  ok = CheckGetCodePaths(p, "TestInt16", "32767", IntegerValue(32767));
750  ok,
751  true,
752  "Attribute not set properly by SetAttributeFailSafe() (most positive) via StringValue");
753 
754  //
755  // Try to set the Attribute past the most positive value of the signed 16-bit
756  // range and make sure the underlying attribute is unchanged.
757  //
758  ok = p->SetAttributeFailSafe("TestInt16", StringValue("32768"));
760  false,
761  "Unexpectedly could SetAttributeFailSafe() via StringValue to 32768");
762 
763  ok = CheckGetCodePaths(p, "TestInt16", "32767", IntegerValue(32767));
764  NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes");
765 
766  //
767  // Attributes can have limits other than the intrinsic limits of the
768  // underlying data types. These limits are specified in the Object.
769  //
770  ok = p->SetAttributeFailSafe("TestInt16WithBounds", IntegerValue(10));
771  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 10");
772 
773  ok = CheckGetCodePaths(p, "TestInt16WithBounds", "10", IntegerValue(10));
775  ok,
776  true,
777  "Attribute not set properly by SetAttributeFailSafe() (positive limit) via StringValue");
778 
779  //
780  // Set the Attribute past the positive limit.
781  //
782  ok = p->SetAttributeFailSafe("TestInt16WithBounds", IntegerValue(11));
784  false,
785  "Unexpectedly could SetAttributeFailSafe() via IntegerValue to 11");
786 
787  ok = CheckGetCodePaths(p, "TestInt16WithBounds", "10", IntegerValue(10));
788  NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes");
789 
790  //
791  // Set the Attribute at the negative limit.
792  //
793  ok = p->SetAttributeFailSafe("TestInt16WithBounds", IntegerValue(-5));
794  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to -5");
795 
796  ok = CheckGetCodePaths(p, "TestInt16WithBounds", "-5", IntegerValue(-5));
798  ok,
799  true,
800  "Attribute not set properly by SetAttributeFailSafe() (negative limit) via StringValue");
801 
802  //
803  // Set the Attribute past the negative limit.
804  //
805  ok = p->SetAttributeFailSafe("TestInt16WithBounds", IntegerValue(-6));
807  false,
808  "Unexpectedly could SetAttributeFailSafe() via IntegerValue to -6");
809 
810  ok = CheckGetCodePaths(p, "TestInt16WithBounds", "-5", IntegerValue(-5));
811  NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes");
812 }
813 
814 template <>
815 void
817 {
819  bool ok;
820 
821  p = CreateObject<AttributeObjectTest>();
822  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
823 
824  //
825  // When the object is first created, the Attribute should have the default
826  // value.
827  //
828  ok = CheckGetCodePaths(p, "TestUint8", "1", UintegerValue(1));
829  NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value");
830 
831  //
832  // Set the Attribute to zero.
833  //
834  ok = p->SetAttributeFailSafe("TestUint8", UintegerValue(0));
835  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() to 0");
836 
837  ok = CheckGetCodePaths(p, "TestUint8", "0", UintegerValue(0));
839  true,
840  "Attribute not set properly by SetAttributeFailSafe() via StringValue");
841 
842  //
843  // Set the Attribute to the most positive value of the unsigned 8-bit range.
844  //
845  ok = p->SetAttributeFailSafe("TestUint8", UintegerValue(255));
846  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() to 255");
847 
848  ok = CheckGetCodePaths(p, "TestUint8", "255", UintegerValue(255));
850  ok,
851  true,
852  "Attribute not set properly by SetAttributeFailSafe() (positive limit) via UintegerValue");
853 
854  //
855  // Try and set the Attribute past the most positive value of the unsigned
856  // 8-bit range.
857  //
858  ok = p->SetAttributeFailSafe("TestUint8", UintegerValue(256));
859  NS_TEST_ASSERT_MSG_EQ(ok, false, "Unexpectedly could SetAttributeFailSafe() to 256");
860 
861  ok = CheckGetCodePaths(p, "TestUint8", "255", UintegerValue(255));
862  NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes");
863 
864  //
865  // Set the Attribute to the most positive value of the unsigned 8-bit range
866  // through a StringValue.
867  //
868  ok = p->SetAttributeFailSafe("TestUint8", StringValue("255"));
869  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via StringValue to 255");
870 
871  ok = CheckGetCodePaths(p, "TestUint8", "255", UintegerValue(255));
873  true,
874  "Attribute not set properly by SetAttributeFailSafe() via StringValue");
875 
876  //
877  // Try and set the Attribute past the most positive value of the unsigned
878  // 8-bit range through a StringValue.
879  //
880  ok = p->SetAttributeFailSafe("TestUint8", StringValue("256"));
882  false,
883  "Unexpectedly could SetAttributeFailSafe() via StringValue to 256");
884 
885  ok = CheckGetCodePaths(p, "TestUint8", "255", UintegerValue(255));
886  NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes");
887 
888  //
889  // Try to set the Attribute to a negative StringValue.
890  //
891  ok = p->SetAttributeFailSafe("TestUint8", StringValue("-1"));
893  false,
894  "Unexpectedly could SetAttributeFailSafe() via StringValue to -1");
895 }
896 
897 template <>
898 void
900 {
902  bool ok;
903 
904  p = CreateObject<AttributeObjectTest>();
905  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
906 
907  //
908  // When the object is first created, the Attribute should have the default
909  // value.
910  //
911  ok = CheckGetCodePaths(p, "TestFloat", "-1.1", DoubleValue(-1.1F));
912  NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value");
913 
914  //
915  // Set the Attribute.
916  //
917  ok = p->SetAttributeFailSafe("TestFloat", DoubleValue(2.3F));
918  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() to 2.3");
919 
920  ok = CheckGetCodePaths(p, "TestFloat", "2.3", DoubleValue(2.3F));
922  true,
923  "Attribute not set properly by SetAttributeFailSafe() via DoubleValue");
924 }
925 
926 template <>
927 void
929 {
931  bool ok;
932 
933  p = CreateObject<AttributeObjectTest>();
934  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
935 
936  //
937  // When the object is first created, the Attribute should have the default
938  // value.
939  //
940  ok = CheckGetCodePaths(p, "TestEnum", "TestA", EnumValue(AttributeObjectTest::TEST_A));
941  NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value");
942 
943  //
944  // Set the Attribute using the EnumValue type.
945  //
946  ok = p->SetAttributeFailSafe("TestEnum", EnumValue(AttributeObjectTest::TEST_C));
947  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() to TEST_C");
948 
949  ok = CheckGetCodePaths(p, "TestEnum", "TestC", EnumValue(AttributeObjectTest::TEST_C));
951  true,
952  "Attribute not set properly by SetAttributeFailSafe() via EnumValue");
953 
954  //
955  // When the object is first created, the Attribute should have the default
956  // value.
957  //
958  ok = CheckGetCodePaths(p, "TestEnumSetGet", "TestB", EnumValue(AttributeObjectTest::TEST_B));
959  NS_TEST_ASSERT_MSG_EQ(ok, true, "Attribute not set properly by default value");
960 
961  //
962  // Set the Attribute using the EnumValue type.
963  //
964  ok = p->SetAttributeFailSafe("TestEnumSetGet", EnumValue(AttributeObjectTest::TEST_C));
965  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() to TEST_C");
966 
967  ok = CheckGetCodePaths(p, "TestEnumSetGet", "TestC", EnumValue(AttributeObjectTest::TEST_C));
969  true,
970  "Attribute not set properly by SetAttributeFailSafe() via EnumValue");
971 
972  //
973  // Set the Attribute using the StringValue type.
974  //
975  ok = p->SetAttributeFailSafe("TestEnum", StringValue("TestB"));
976  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() to TEST_B");
977 
978  ok = CheckGetCodePaths(p, "TestEnum", "TestB", EnumValue(AttributeObjectTest::TEST_B));
980  true,
981  "Attribute not set properly by SetAttributeFailSafe() via StringValue");
982 
983  //
984  // Try to set the Attribute to a bogus enum using the StringValue type
985  // throws a fatal error.
986  //
987  // ok = p->SetAttributeFailSafe ("TestEnum", StringValue ("TestD"));
988  // NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() to TEST_D"); //
989 
990  ok = CheckGetCodePaths(p, "TestEnum", "TestB", EnumValue(AttributeObjectTest::TEST_B));
991  NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes");
992 
993  //
994  // Try to set the Attribute to a bogus enum using an integer implicit conversion
995  // and make sure the underlying value doesn't change.
996  //
997  ok = p->SetAttributeFailSafe("TestEnum", EnumValue(5));
998  NS_TEST_ASSERT_MSG_EQ(ok, false, "Unexpectedly could SetAttributeFailSafe() to 5");
999 
1000  ok = CheckGetCodePaths(p, "TestEnum", "TestB", EnumValue(AttributeObjectTest::TEST_B));
1001  NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes");
1002 }
1003 
1004 template <>
1005 void
1007 {
1009  bool ok;
1010 
1011  p = CreateObject<AttributeObjectTest>();
1012  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
1013 
1014  // The test vectors assume ns resolution
1015  Time::SetResolution(Time::NS);
1016 
1017  //
1018  // Set value
1019  //
1020  ok = p->SetAttributeFailSafe("TestTimeWithBounds", TimeValue(Seconds(5)));
1021  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via TimeValue to 5s");
1022 
1023  ok = CheckGetCodePaths(p, "TestTimeWithBounds", "+5e+09ns", TimeValue(Seconds(5)));
1025  true,
1026  "Attribute not set properly by SetAttributeFailSafe(5s) via TimeValue");
1027 
1028  ok = p->SetAttributeFailSafe("TestTimeWithBounds", StringValue("3s"));
1029  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via TimeValue to 3s");
1030 
1031  ok = CheckGetCodePaths(p, "TestTimeWithBounds", "+3e+09ns", TimeValue(Seconds(3)));
1033  true,
1034  "Attribute not set properly by SetAttributeFailSafe(3s) via StringValue");
1035 
1036  //
1037  // Attributes can have limits other than the intrinsic limits of the
1038  // underlying data types. These limits are specified in the Object.
1039  //
1040 
1041  //
1042  // Set the Attribute at the positive limit
1043  //
1044  ok = p->SetAttributeFailSafe("TestTimeWithBounds", TimeValue(Seconds(10)));
1045  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via TimeValue to 10s");
1046 
1047  ok = CheckGetCodePaths(p, "TestTimeWithBounds", "+1e+10ns", TimeValue(Seconds(10)));
1049  ok,
1050  true,
1051  "Attribute not set properly by SetAttributeFailSafe(10s [positive limit]) via StringValue");
1052 
1053  //
1054  // Set the Attribute past the positive limit.
1055  //
1056  ok = p->SetAttributeFailSafe("TestTimeWithBounds", TimeValue(Seconds(11)));
1058  false,
1059  "Unexpectedly could SetAttributeFailSafe() via TimeValue to 11s [greater "
1060  "than positive limit]");
1061 
1062  ok = CheckGetCodePaths(p, "TestTimeWithBounds", "+1e+10ns", TimeValue(Seconds(10)));
1063  NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes");
1064 
1065  //
1066  // Set the Attribute at the negative limit.
1067  //
1068  ok = p->SetAttributeFailSafe("TestTimeWithBounds", TimeValue(Seconds(-5)));
1069  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via TimeValue to -5s");
1070 
1071  ok = CheckGetCodePaths(p, "TestTimeWithBounds", "-5e+09ns", TimeValue(Seconds(-5)));
1073  ok,
1074  true,
1075  "Attribute not set properly by SetAttributeFailSafe(-5s [negative limit]) via StringValue");
1076 
1077  //
1078  // Set the Attribute past the negative limit.
1079  //
1080  ok = p->SetAttributeFailSafe("TestTimeWithBounds", TimeValue(Seconds(-6)));
1082  false,
1083  "Unexpectedly could SetAttributeFailSafe() via TimeValue to -6s");
1084 
1085  ok = CheckGetCodePaths(p, "TestTimeWithBounds", "-5e+09ns", TimeValue(Seconds(-5)));
1086  NS_TEST_ASSERT_MSG_EQ(ok, true, "Error in SetAttributeFailSafe() but value changes");
1087 }
1088 
1095 {
1096  public:
1101  RandomVariableStreamAttributeTestCase(std::string description);
1102 
1104  {
1105  }
1106 
1111  void InvokeCbValue(int8_t a)
1112  {
1113  if (!m_cbValue.IsNull())
1114  {
1115  m_cbValue(a);
1116  }
1117  }
1118 
1119  private:
1120  void DoRun() override;
1121 
1124 
1129  void NotifyCallbackValue(int8_t a)
1130  {
1131  m_gotCbValue = a;
1132  }
1133 
1134  int16_t m_gotCbValue;
1135 };
1136 
1138  std::string description)
1139  : TestCase(description)
1140 {
1141 }
1142 
1143 void
1145 {
1147  bool ok;
1148 
1149  p = CreateObject<AttributeObjectTest>();
1150  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
1151 
1152  //
1153  // Try to set a UniformRandomVariable
1154  //
1155  ok = p->SetAttributeFailSafe("TestRandom",
1156  StringValue("ns3::UniformRandomVariable[Min=0.|Max=1.]"));
1157  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() a UniformRandomVariable");
1158 
1159  //
1160  // Try to set a <snicker> ConstantRandomVariable
1161  //
1162  ok = p->SetAttributeFailSafe("TestRandom",
1163  StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
1164  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() a ConstantRandomVariable");
1165 }
1166 
1175 {
1176  public:
1181  ObjectVectorAttributeTestCase(std::string description);
1182 
1184  {
1185  }
1186 
1187  private:
1188  void DoRun() override;
1189 };
1190 
1192  : TestCase(description)
1193 {
1194 }
1195 
1196 void
1198 {
1200  ObjectVectorValue vector;
1201 
1202  p = CreateObject<AttributeObjectTest>();
1203  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
1204 
1205  //
1206  // When the object is first created, the Attribute should have no items in
1207  // the vector.
1208  //
1209  p->GetAttribute("TestVector1", vector);
1210  NS_TEST_ASSERT_MSG_EQ(vector.GetN(),
1211  0,
1212  "Initial count of ObjectVectorValue \"TestVector1\" should be zero");
1213 
1214  //
1215  // Adding to the attribute shouldn't affect the value we already have.
1216  //
1217  p->AddToVector1();
1219  vector.GetN(),
1220  0,
1221  "Initial count of ObjectVectorValue \"TestVector1\" should still be zero");
1222 
1223  //
1224  // Getting the attribute again should update the value.
1225  //
1226  p->GetAttribute("TestVector1", vector);
1227  NS_TEST_ASSERT_MSG_EQ(vector.GetN(),
1228  1,
1229  "ObjectVectorValue \"TestVector1\" should be incremented");
1230 
1231  //
1232  // Get the Object pointer from the value.
1233  //
1234  Ptr<Object> a = vector.Get(0);
1235  NS_TEST_ASSERT_MSG_NE(a, nullptr, "Ptr<Object> from VectorValue \"TestVector1\" is zero");
1236 
1237  //
1238  // Adding to the attribute shouldn't affect the value we already have.
1239  //
1240  p->AddToVector1();
1241  NS_TEST_ASSERT_MSG_EQ(vector.GetN(),
1242  1,
1243  "Count of ObjectVectorValue \"TestVector1\" should still be one");
1244 
1245  //
1246  // Getting the attribute again should update the value.
1247  //
1248  p->GetAttribute("TestVector1", vector);
1249  NS_TEST_ASSERT_MSG_EQ(vector.GetN(),
1250  2,
1251  "ObjectVectorValue \"TestVector1\" should be incremented");
1252 }
1253 
1260 {
1261  public:
1266  ObjectMapAttributeTestCase(std::string description);
1267 
1269  {
1270  }
1271 
1272  private:
1273  void DoRun() override;
1274 };
1275 
1277  : TestCase(description)
1278 {
1279 }
1280 
1281 void
1283 {
1285  ObjectMapValue map;
1286 
1287  p = CreateObject<AttributeObjectTest>();
1288  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
1289 
1290  //
1291  // When the object is first created, the Attribute should have no items in
1292  // the vector.
1293  //
1294  p->GetAttribute("TestMap1", map);
1296  0,
1297  "Initial count of ObjectVectorValue \"TestMap1\" should be zero");
1298 
1299  //
1300  // Adding to the attribute shouldn't affect the value we already have.
1301  //
1302  p->AddToMap1(1);
1304  0,
1305  "Initial count of ObjectVectorValue \"TestMap1\" should still be zero");
1306 
1307  //
1308  // Getting the attribute again should update the value.
1309  //
1310  p->GetAttribute("TestMap1", map);
1311  NS_TEST_ASSERT_MSG_EQ(map.GetN(), 1, "ObjectVectorValue \"TestMap1\" should be incremented");
1312 
1313  //
1314  // Get the Object pointer from the value.
1315  //
1316  Ptr<Object> a = map.Get(1);
1317  NS_TEST_ASSERT_MSG_NE(a, nullptr, "Ptr<Object> from VectorValue \"TestMap1\" is zero");
1318 
1319  //
1320  // Adding to the attribute shouldn't affect the value we already have.
1321  //
1322  p->AddToMap1(2);
1324  1,
1325  "Count of ObjectVectorValue \"TestMap1\" should still be one");
1326 
1327  //
1328  // Getting the attribute again should update the value.
1329  //
1330  p->GetAttribute("TestMap1", map);
1331  NS_TEST_ASSERT_MSG_EQ(map.GetN(), 2, "ObjectVectorValue \"TestMap1\" should be incremented");
1332 }
1333 
1341 {
1342  public:
1347  IntegerTraceSourceAttributeTestCase(std::string description);
1348 
1350  {
1351  }
1352 
1353  private:
1354  void DoRun() override;
1355 };
1356 
1358  : TestCase(description)
1359 {
1360 }
1361 
1362 void
1364 {
1366  IntegerValue iv;
1367  bool ok;
1368 
1369  p = CreateObject<AttributeObjectTest>();
1370  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
1371 
1372  //
1373  // When the object is first created, the Attribute should have the default
1374  // value.
1375  //
1376  p->GetAttribute("IntegerTraceSource1", iv);
1377  NS_TEST_ASSERT_MSG_EQ(iv.Get(), -2, "Attribute not set properly by default value");
1378 
1379  //
1380  // Set the Attribute to a positive value through an IntegerValue.
1381  //
1382  ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(5));
1383  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 5");
1384 
1385  p->GetAttribute("IntegerTraceSource1", iv);
1387  5,
1388  "Attribute not set properly by SetAttributeFailSafe() via IntegerValue");
1389 
1390  //
1391  // Limits should work.
1392  //
1393  ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(127));
1394  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 127");
1395 
1396  ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(128));
1398  false,
1399  "Unexpectedly could SetAttributeFailSafe() via IntegerValue to 128");
1400 
1401  ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(-128));
1402  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to -128");
1403 
1404  ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(-129));
1406  false,
1407  "Unexpectedly could SetAttributeFailSafe() via IntegerValue to -129");
1408 
1409  //
1410  // When the object is first created, the Attribute should have the default
1411  // value.
1412  //
1413  p->GetAttribute("IntegerTraceSource2", iv);
1414  NS_TEST_ASSERT_MSG_EQ(iv.Get(), -2, "Attribute not set properly by default value");
1415 
1416  //
1417  // Set the Attribute to a positive value through an IntegerValue.
1418  //
1419  ok = p->SetAttributeFailSafe("IntegerTraceSource2", IntegerValue(5));
1420  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 5");
1421 
1422  p->GetAttribute("IntegerTraceSource2", iv);
1424  5,
1425  "Attribute not set properly by SetAttributeFailSafe() via IntegerValue");
1426 
1427  //
1428  // Limits should work.
1429  //
1430  ok = p->SetAttributeFailSafe("IntegerTraceSource2", IntegerValue(127));
1431  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 127");
1432 
1433  ok = p->SetAttributeFailSafe("IntegerTraceSource2", IntegerValue(128));
1435  false,
1436  "Unexpectedly could SetAttributeFailSafe() via IntegerValue to 128");
1437 
1438  ok = p->SetAttributeFailSafe("IntegerTraceSource2", IntegerValue(-128));
1439  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to -128");
1440 
1441  ok = p->SetAttributeFailSafe("IntegerTraceSource2", IntegerValue(-129));
1443  false,
1444  "Unexpectedly could SetAttributeFailSafe() via IntegerValue to -129");
1445 }
1446 
1454 {
1455  public:
1460  IntegerTraceSourceTestCase(std::string description);
1461 
1463  {
1464  }
1465 
1466  private:
1467  void DoRun() override;
1468 
1474  void NotifySource1(int8_t old [[maybe_unused]], int8_t n)
1475  {
1476  m_got1 = n;
1477  }
1478 
1479  int64_t m_got1;
1480 };
1481 
1483  : TestCase(description)
1484 {
1485 }
1486 
1487 void
1489 {
1491  bool ok;
1492 
1493  p = CreateObject<AttributeObjectTest>();
1494  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
1495 
1496  //
1497  // Check to make sure changing an Attribute value triggers a trace callback
1498  // that sets a member variable.
1499  //
1500  m_got1 = 1234;
1501 
1502  ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(-1));
1503  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to -1");
1504 
1505  //
1506  // Source1 is declared as a TraceSourceAccessor to m_intSrc1. This m_intSrc1
1507  // is also declared as an Integer Attribute. We just checked to make sure we
1508  // could set it using an IntegerValue through its IntegerTraceSource1 "persona."
1509  // We should also be able to hook a trace source to the underlying variable.
1510  //
1511  ok = p->TraceConnectWithoutContext(
1512  "Source1",
1515  true,
1516  "Could not TraceConnectWithoutContext() \"Source1\" to NodifySource1()");
1517 
1518  //
1519  // When we set the IntegerValue that now underlies both the Integer Attribute
1520  // and the trace source, the trace should fire and call NotifySource1 which
1521  // will set m_got1 to the new value.
1522  //
1523  ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(0));
1524  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 0");
1525 
1527  0,
1528  "Hitting a TracedValue does not cause trace callback to be called");
1529 
1530  //
1531  // Now disconnect from the trace source and ensure that the trace callback
1532  // is not called if the trace source is hit.
1533  //
1534  ok = p->TraceDisconnectWithoutContext(
1535  "Source1",
1538  true,
1539  "Could not TraceConnectWithoutContext() \"Source1\" to NodifySource1()");
1540 
1541  ok = p->SetAttributeFailSafe("IntegerTraceSource1", IntegerValue(1));
1542  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 1");
1543 
1545  0,
1546  "Hitting a TracedValue after disconnect still causes callback");
1547 }
1548 
1556 {
1557  public:
1562  TracedCallbackTestCase(std::string description);
1563 
1565  {
1566  }
1567 
1568  private:
1569  void DoRun() override;
1570 
1577  void NotifySource2(double a, int b [[maybe_unused]], float c [[maybe_unused]])
1578  {
1579  m_got2 = a;
1580  }
1581 
1582  double m_got2;
1583 };
1584 
1586  : TestCase(description)
1587 {
1588 }
1589 
1590 void
1592 {
1594  bool ok;
1595 
1596  p = CreateObject<AttributeObjectTest>();
1597  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
1598 
1599  //
1600  // Initialize the
1601  //
1602  m_got2 = 4.3;
1603 
1604  //
1605  // Invoke the callback that lies at the heart of this test. We have a
1606  // method InvokeCb() that just executes m_cb(). The variable m_cb is
1607  // declared as a TracedCallback<double, int, float>. This kind of beast
1608  // is like a callback but can call a list of targets. This list should
1609  // be empty so nothing should happen now. Specifically, m_got2 shouldn't
1610  // have changed.
1611  //
1612  p->InvokeCb(1.0, -5, 0.0);
1614  m_got2,
1615  4.3,
1616  "Invoking a newly created TracedCallback results in an unexpected callback");
1617 
1618  //
1619  // Now, wire the TracedCallback up to a trace sink. This sink will just set
1620  // m_got2 to the first argument.
1621  //
1622  ok = p->TraceConnectWithoutContext("Source2",
1624  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not TraceConnectWithoutContext() to NotifySource2");
1625 
1626  //
1627  // Now if we invoke the callback, the trace source should fire and m_got2
1628  // should be set in the trace sink.
1629  //
1630  p->InvokeCb(1.0, -5, 0.0);
1631  NS_TEST_ASSERT_MSG_EQ(m_got2, 1.0, "Invoking TracedCallback does not result in trace callback");
1632 
1633  //
1634  // Now, disconnect the trace sink and see what happens when we invoke the
1635  // callback again. Of course, the trace should not happen and m_got2
1636  // should remain unchanged.
1637  //
1638  ok = p->TraceDisconnectWithoutContext(
1639  "Source2",
1641  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not TraceDisconnectWithoutContext() from NotifySource2");
1642 
1643  p->InvokeCb(-1.0, -5, 0.0);
1645  m_got2,
1646  1.0,
1647  "Invoking disconnected TracedCallback unexpectedly results in trace callback");
1648 }
1649 
1657 {
1658  public:
1663  PointerAttributeTestCase(std::string description);
1664 
1666  {
1667  }
1668 
1669  private:
1670  void DoRun() override;
1671 
1678  void NotifySource2(double a, int b [[maybe_unused]], float c [[maybe_unused]])
1679  {
1680  m_got2 = a;
1681  }
1682 
1683  double m_got2;
1684 };
1685 
1687  : TestCase(description)
1688 {
1689 }
1690 
1691 void
1693 {
1695  bool ok;
1696 
1697  p = CreateObject<AttributeObjectTest>();
1698  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
1699 
1700  //
1701  // We have declared a PointerValue Attribute named "Pointer" with a pointer
1702  // checker of type Derived. This means that we should be able to pull out
1703  // a Ptr<Derived> with the initial value (which is 0).
1704  //
1705  PointerValue ptr;
1706  p->GetAttribute("Pointer", ptr);
1707  Ptr<Derived> derived = ptr.Get<Derived>();
1709  (bool)derived,
1710  false,
1711  "Unexpectedly found non-null pointer in newly initialized PointerValue Attribute");
1712 
1713  //
1714  // Now, lets create an Object of type Derived and set the local Ptr to point
1715  // to that object. We can then set the PointerValue Attribute to that Ptr.
1716  //
1717  derived = Create<Derived>();
1718  ok = p->SetAttributeFailSafe("Pointer", PointerValue(derived));
1720  true,
1721  "Could not SetAttributeFailSafe() a PointerValue of the correct type");
1722 
1723  //
1724  // Pull the value back out of the Attribute and make sure it points to the
1725  // correct object.
1726  //
1727  p->GetAttribute("Pointer", ptr);
1728  Ptr<Derived> stored = ptr.Get<Derived>();
1729  NS_TEST_ASSERT_MSG_EQ(stored,
1730  derived,
1731  "Retrieved Attribute does not match stored PointerValue");
1732 
1733  //
1734  // We should be able to use the Attribute Get() just like GetObject<type>,
1735  // So see if we can get a Ptr<Object> out of the Ptr<Derived> we stored.
1736  // This should be a pointer to the same physical memory since its the
1737  // same object.
1738  //
1739  p->GetAttribute("Pointer", ptr);
1740  Ptr<Object> storedBase = ptr.Get<Object>();
1741  NS_TEST_ASSERT_MSG_EQ(storedBase,
1742  stored,
1743  "Retrieved Ptr<Object> does not match stored Ptr<Derived>");
1744 
1745  //
1746  // If we try to Get() something that is unrelated to what we stored, we should
1747  // retrieve a 0.
1748  //
1749  p->GetAttribute("Pointer", ptr);
1751  NS_TEST_ASSERT_MSG_EQ((bool)x,
1752  false,
1753  "Unexpectedly retrieved unrelated Ptr<type> from stored Ptr<Derived>");
1754 
1755  //
1756  // Test whether the initialized pointers from two different objects
1757  // point to different Derived objects
1758  //
1759  p->GetAttribute("PointerInitialized", ptr);
1760  Ptr<Derived> storedPtr = ptr.Get<Derived>();
1761  Ptr<AttributeObjectTest> p2 = CreateObject<AttributeObjectTest>();
1762  PointerValue ptr2;
1763  p2->GetAttribute("PointerInitialized", ptr2);
1764  Ptr<Derived> storedPtr2 = ptr2.Get<Derived>();
1765  NS_TEST_ASSERT_MSG_NE(storedPtr,
1766  storedPtr2,
1767  "ptr and ptr2 both have PointerInitialized pointing to the same object");
1768  PointerValue ptr3;
1769  p2->GetAttribute("PointerInitialized", ptr3);
1770  Ptr<Derived> storedPtr3 = ptr3.Get<Derived>();
1771  NS_TEST_ASSERT_MSG_NE(storedPtr,
1772  storedPtr3,
1773  "ptr and ptr3 both have PointerInitialized pointing to the same object");
1774 
1775  //
1776  // Test whether object factory creates the objects properly
1777  //
1778  ObjectFactory factory;
1779  factory.SetTypeId("ns3::AttributeObjectTest");
1780  factory.Set("PointerInitialized", StringValue("ns3::Derived"));
1782  NS_TEST_ASSERT_MSG_NE(aotPtr, nullptr, "Unable to factory.Create() a AttributeObjectTest");
1784  NS_TEST_ASSERT_MSG_NE(aotPtr2, nullptr, "Unable to factory.Create() a AttributeObjectTest");
1785  NS_TEST_ASSERT_MSG_NE(aotPtr, aotPtr2, "factory object not creating unique objects");
1786  PointerValue ptr4;
1787  aotPtr->GetAttribute("PointerInitialized", ptr4);
1788  Ptr<Derived> storedPtr4 = ptr4.Get<Derived>();
1789  PointerValue ptr5;
1790  aotPtr2->GetAttribute("PointerInitialized", ptr5);
1791  Ptr<Derived> storedPtr5 = ptr5.Get<Derived>();
1792  NS_TEST_ASSERT_MSG_NE(storedPtr4,
1793  storedPtr5,
1794  "aotPtr and aotPtr2 are unique, but their Derived member is not");
1795 }
1796 
1803 {
1804  public:
1809  CallbackValueTestCase(std::string description);
1810 
1812  {
1813  }
1814 
1819  void InvokeCbValue(int8_t a)
1820  {
1821  if (!m_cbValue.IsNull())
1822  {
1823  m_cbValue(a);
1824  }
1825  }
1826 
1827  private:
1828  void DoRun() override;
1829 
1831 
1836  void NotifyCallbackValue(int8_t a)
1837  {
1838  m_gotCbValue = a;
1839  }
1840 
1841  int16_t m_gotCbValue;
1842 };
1843 
1845  : TestCase(description)
1846 {
1847 }
1848 
1849 void
1851 {
1853  bool ok;
1854 
1855  p = CreateObject<AttributeObjectTest>();
1856  NS_TEST_ASSERT_MSG_NE(p, nullptr, "Unable to CreateObject");
1857 
1858  //
1859  // The member variable m_cbValue is declared as a Callback<void, int8_t>. The
1860  // Attribute named "Callback" also points to m_cbValue and allows us to set the
1861  // callback using that Attribute.
1862  //
1863  // NotifyCallbackValue is going to be the target of the callback and will just set
1864  // m_gotCbValue to its single parameter. This will be the parameter from the
1865  // callback invocation. The method InvokeCbValue() just invokes the m_cbValue
1866  // callback if it is non-null.
1867  //
1868  m_gotCbValue = 1;
1869 
1870  //
1871  // If we invoke the callback (which has not been set) nothing should happen.
1872  // Further, nothing should happen when we initialize the callback (it shouldn't
1873  // accidentally fire).
1874  //
1875  p->InvokeCbValue(2);
1877 
1878  NS_TEST_ASSERT_MSG_EQ(m_gotCbValue, 1, "Callback unexpectedly fired");
1879 
1880  ok = p->SetAttributeFailSafe("Callback", cbValue);
1881  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() a CallbackValue");
1882 
1883  //
1884  // Now that the callback has been set, invoking it should set m_gotCbValue.
1885  //
1886  p->InvokeCbValue(2);
1887  NS_TEST_ASSERT_MSG_EQ(m_gotCbValue, 2, "Callback Attribute set by CallbackValue did not fire");
1888 
1889  ok = p->SetAttributeFailSafe("Callback", CallbackValue(MakeNullCallback<void, int8_t>()));
1890  NS_TEST_ASSERT_MSG_EQ(ok, true, "Could not SetAttributeFailSafe() a null CallbackValue");
1891 
1892  //
1893  // If the callback has been set to a null callback, it should no longer fire.
1894  //
1895  p->InvokeCbValue(3);
1897  2,
1898  "Callback Attribute set to null callback unexpectedly fired");
1899 }
1900 
1907 {
1908  public:
1910 };
1911 
1913  : TestSuite("attributes", UNIT)
1914 {
1915  AddTestCase(new AttributeTestCase<BooleanValue>("Check Attributes of type BooleanValue"),
1916  TestCase::QUICK);
1917  AddTestCase(new AttributeTestCase<IntegerValue>("Check Attributes of type IntegerValue"),
1918  TestCase::QUICK);
1919  AddTestCase(new AttributeTestCase<UintegerValue>("Check Attributes of type UintegerValue"),
1920  TestCase::QUICK);
1921  AddTestCase(new AttributeTestCase<DoubleValue>("Check Attributes of type DoubleValue"),
1922  TestCase::QUICK);
1923  AddTestCase(new AttributeTestCase<EnumValue>("Check Attributes of type EnumValue"),
1924  TestCase::QUICK);
1925  AddTestCase(new AttributeTestCase<TimeValue>("Check Attributes of type TimeValue"),
1926  TestCase::QUICK);
1927  AddTestCase(
1928  new RandomVariableStreamAttributeTestCase("Check Attributes of type RandomVariableStream"),
1929  TestCase::QUICK);
1930  AddTestCase(new ObjectVectorAttributeTestCase("Check Attributes of type ObjectVectorValue"),
1931  TestCase::QUICK);
1932  AddTestCase(new ObjectMapAttributeTestCase("Check Attributes of type ObjectMapValue"),
1933  TestCase::QUICK);
1934  AddTestCase(new PointerAttributeTestCase("Check Attributes of type PointerValue"),
1935  TestCase::QUICK);
1936  AddTestCase(new CallbackValueTestCase("Check Attributes of type CallbackValue"),
1937  TestCase::QUICK);
1939  "Ensure TracedValue<uint8_t> can be set like IntegerValue"),
1940  TestCase::QUICK);
1941  AddTestCase(
1942  new IntegerTraceSourceTestCase("Ensure TracedValue<uint8_t> also works as trace source"),
1943  TestCase::QUICK);
1945  "Ensure TracedCallback<double, int, float> works as trace source"),
1946  TestCase::QUICK);
1947 }
1948 
static AttributesTestSuite g_attributesTestSuite
Static variable for test initialization.
Class used to check attributes.
std::size_t DoGetVectorN() const
Get the length of m_vector2.
bool DoSetIntSrc(int8_t v)
Set the m_intSrc2 value.
bool m_boolTest
Boolean test.
void AddToVector2()
Add an object to the second vector.
std::map< uint32_t, Ptr< Derived > > m_map1
Map of uint32_t, derived objects.
int16_t m_int16SetGet
16-bit integer set-get.
Test_e DoGetEnum() const
Get the m_enumSetGet value.
bool DoGetTestA() const
Get the m_boolTestA value.
void InvokeCb(double a, int b, float c)
Invoke the m_cb callback.
Ptr< Derived > DoGetVector(std::size_t i) const
Get the i-th item of m_vector2.
Ptr< RandomVariableStream > m_random
Random number generator.
bool m_boolTestA
Boolean test A.
int16_t m_int16
16-bit integer.
static TypeId GetTypeId()
Get the type ID.
std::vector< Ptr< Derived > > m_vector1
First vector of derived objects.
Callback< void, int8_t > m_cbValue
Callback accepting an integer.
void InvokeCbValue(int8_t a)
Invoke the m_cbValue callback.
TracedValue< double > m_doubleSrc
double Traced value.
bool m_boolTestDeprecated
Boolean test deprecated.
void AddToMap1(uint32_t i)
Adds an object to the first map.
TracedCallback< double, int, float > m_cb
TracedCallback (double, int, float).
Ptr< Derived > m_ptr
Pointer to Derived class.
int16_t m_int16WithBounds
16-bit integer with bounds.
TracedValue< int8_t > m_intSrc1
First int8_t Traced value.
TracedValue< Test_e > m_enumSrc
enum Traced value.
Ptr< Derived > m_ptrInitialized
Pointer to Derived class.
void AddToVector1()
Add an object to the first vector.
Ptr< Derived > m_ptrInitialized2
Pointer to Derived class.
int16_t DoGetInt16() const
Get the m_int16SetGet value.
TracedValue< ValueClassTest > m_valueSrc
ValueClassTest Traced value.
void DoSetTestA(bool v)
Set the m_boolTestA value.
TracedValue< uint8_t > m_uintSrc
uint8_t Traced value.
TracedValue< bool > m_boolSrc
bool Traced value.
TracedValue< int8_t > m_intSrc2
Second int8_t Traced value.
Time m_timeWithBounds
Time with bounds.
int8_t DoGetIntSrc() const
Get the m_intSrc2 value.
uint8_t m_uint8
8-bit integer.
std::vector< Ptr< Derived > > m_vector2
Second vector of derived objects.
bool DoSetEnum(Test_e v)
Set the m_enumSetGet value.
void DoSetInt16(int16_t v)
Set the m_int16SetGet value.
Test case template used for generic Attribute Value types – used to make sure that Attributes work as...
bool CheckGetCodePaths(Ptr< Object > p, std::string attributeName, std::string expectedString, T expectedValue)
Check the attribute path and value.
AttributeTestCase(std::string description)
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
The attributes Test Suite.
Test the Attributes of type CallbackValue.
CallbackValueTestCase(std::string description)
Constructor.
void NotifyCallbackValue(int8_t a)
Function invoked when the callback is fired.
void DoRun() override
Implementation to actually run this TestCase.
void InvokeCbValue(int8_t a)
Function to invoke the callback.
Callback< void, int8_t > m_cbValue
The callback.
int16_t m_gotCbValue
Value used to verify that source 2 was called.
Simple class derived from ns3::Object, used to check attribute constructors.
static TypeId GetTypeId()
Get the type ID.
Trace sources with value semantics can be used like Attributes, make sure we can use them that way.
IntegerTraceSourceAttributeTestCase(std::string description)
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
Trace sources used like Attributes must also work as trace sources, make sure we can use them that wa...
int64_t m_got1
Value used to verify that source 1 was called.
void NotifySource1(int8_t old[[maybe_unused]], int8_t n)
Notify the call of source 1.
IntegerTraceSourceTestCase(std::string description)
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
Test case for Object Map Attributes.
ObjectMapAttributeTestCase(std::string description)
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
Test case for Object Vector Attributes.
ObjectVectorAttributeTestCase(std::string description)
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
Smart pointers (Ptr) are central to our architecture, so they must work as attributes.
void DoRun() override
Implementation to actually run this TestCase.
void NotifySource2(double a, int b[[maybe_unused]], float c[[maybe_unused]])
Notify the call of source 2.
double m_got2
Value used to verify that source 2 was called.
PointerAttributeTestCase(std::string description)
Constructor.
Test the Attributes of type RandomVariableStream.
void InvokeCbValue(int8_t a)
Invoke the m_cbValue.
Callback< void, int8_t > m_cbValue
Callback used in the test.
void DoRun() override
Implementation to actually run this TestCase.
void NotifyCallbackValue(int8_t a)
Function called when the callback is used.
RandomVariableStreamAttributeTestCase(std::string description)
Constructor.
int16_t m_gotCbValue
Value used to verify that the callback has been invoked.
Trace sources used like Attributes must also work as trace sources, make sure we can use them that wa...
void NotifySource2(double a, int b[[maybe_unused]], float c[[maybe_unused]])
Notify the call of source 2.
TracedCallbackTestCase(std::string description)
Constructor.
double m_got2
Value used to verify that source 2 was called.
void DoRun() override
Implementation to actually run this TestCase.
AttributeValue implementation for Boolean.
Definition: boolean.h:37
bool IsNull() const
Check for null implementation.
Definition: callback.h:572
AttributeValue implementation for Callback.
Definition: callback.h:809
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
Hold variables of type enum.
Definition: enum.h:56
Hold a signed integer type.
Definition: integer.h:45
int64_t Get() const
Definition: integer.cc:37
bool GetAttributeFailSafe(std::string name, AttributeValue &value) const
Get the value of an attribute without raising errors.
Definition: object-base.cc:277
Instantiate subclasses of ns3::Object.
Ptr< Object > Create() const
Create an Object instance of the configured TypeId.
void Set(const std::string &name, const AttributeValue &value, Args &&... args)
Set an attribute to be set during construction.
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
Container for a set of ns3::Object pointers.
std::size_t GetN() const
Get the number of Objects.
Ptr< Object > Get(std::size_t i) const
Get a specific Object.
Hold objects of type Ptr<T>.
Definition: pointer.h:37
Ptr< T > Get() const
Definition: pointer.h:206
Hold variables of type string.
Definition: string.h:56
std::string Get() const
Definition: string.cc:31
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:305
A suite of tests to run.
Definition: test.h:1256
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
AttributeValue implementation for Time.
Definition: nstime.h:1423
a unique identifier for an interface.
Definition: type-id.h:60
TypeId AddConstructor()
Record in this TypeId the fact that the default constructor is accessible.
Definition: type-id.h:653
@ DEPRECATED
Attribute or trace source is deprecated; user is warned.
Definition: type-id.h:76
Hold an unsigned integer type.
Definition: uinteger.h:45
Test class for TracedValue callbacks attributes.
void(* TracedValueCallback)(const ValueClassTest oldValue, const ValueClassTest newValue)
TracedValue callback signature for ValueClassTest.
AttributeValue implementation for ValueClassTest.
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: boolean.h:86
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeCallbackAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: callback.h:847
Ptr< const AttributeChecker > MakeCallbackChecker()
Definition: callback.cc:82
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: double.h:43
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: enum.h:205
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: integer.h:46
ObjectPtrContainerValue ObjectMapValue
ObjectMapValue is an alias for ObjectPtrContainerValue.
Definition: object-map.h:40
Ptr< const AttributeAccessor > MakeObjectMapAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition: object-map.h:76
ObjectPtrContainerValue ObjectVectorValue
ObjectVectorValue is an alias for ObjectPtrContainerValue.
Definition: object-vector.h:40
Ptr< const AttributeAccessor > MakeObjectVectorAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition: object-vector.h:76
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: pointer.h:231
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: nstime.h:1424
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: uinteger.h:46
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:891
bool SetDefaultFailSafe(std::string fullName, const AttributeValue &value)
Definition: config.cc:901
#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
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
bool operator!=(Callback< R, Args... > a, Callback< R, Args... > b)
Inequality test.
Definition: callback.h:681
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:707
ATTRIBUTE_HELPER_HEADER(ValueClassTest)
ATTRIBUTE_HELPER_CPP(Length)
Ptr< const AttributeChecker > MakeEnumChecker(int v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:163
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:535
std::istream & operator>>(std::istream &is, Angles &a)
Definition: angles.cc:153
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:129