/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2009 University of Washington * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ns3/test.h" #include "ns3/object.h" #include "ns3/boolean.h" #include "ns3/integer.h" #include "ns3/uinteger.h" #include "ns3/config.h" #include "ns3/enum.h" #include "ns3/string.h" #include "ns3/random-variable.h" #include "ns3/double.h" #include "ns3/object-vector.h" #include "ns3/traced-value.h" #include "ns3/callback.h" #include "ns3/trace-source-accessor.h" #include "ns3/pointer.h" namespace ns3 { class ValueClassTest { public: ValueClassTest () {} private: int m_v; }; bool operator != (const ValueClassTest &a, const ValueClassTest &b) { return true; } std::ostream & operator << (std::ostream &os, ValueClassTest v) { return os; } std::istream & operator >> (std::istream &is, ValueClassTest &v) { return is; } ATTRIBUTE_HELPER_HEADER (ValueClassTest); ATTRIBUTE_HELPER_CPP (ValueClassTest); class Derived : public Object { public: static TypeId GetTypeId (void) { static TypeId tid = TypeId ("ns3::Derived") .SetParent () ; return tid; } }; class AttributeObjectTest : public Object { public: enum Test_e { TEST_A, TEST_B, TEST_C }; static TypeId GetTypeId (void) { static TypeId tid = TypeId ("ns3::AttributeObjectTest") .SetParent () .HideFromDocumentation () .AddAttribute ("TestBoolName", "help text", BooleanValue (false), MakeBooleanAccessor (&AttributeObjectTest::m_boolTest), MakeBooleanChecker ()) .AddAttribute ("TestBoolA", "help text", BooleanValue (false), MakeBooleanAccessor (&AttributeObjectTest::DoSetTestB, &AttributeObjectTest::DoGetTestB), MakeBooleanChecker ()) .AddAttribute ("TestInt16", "help text", IntegerValue (-2), MakeIntegerAccessor (&AttributeObjectTest::m_int16), MakeIntegerChecker ()) .AddAttribute ("TestInt16WithBounds", "help text", IntegerValue (-2), MakeIntegerAccessor (&AttributeObjectTest::m_int16WithBounds), MakeIntegerChecker (-5, 10)) .AddAttribute ("TestInt16SetGet", "help text", IntegerValue (6), MakeIntegerAccessor (&AttributeObjectTest::DoSetInt16, &AttributeObjectTest::DoGetInt16), MakeIntegerChecker ()) .AddAttribute ("TestUint8", "help text", UintegerValue (1), MakeUintegerAccessor (&AttributeObjectTest::m_uint8), MakeUintegerChecker ()) .AddAttribute ("TestEnum", "help text", EnumValue (TEST_A), MakeEnumAccessor (&AttributeObjectTest::m_enum), MakeEnumChecker (TEST_A, "TestA", TEST_B, "TestB", TEST_C, "TestC")) .AddAttribute ("TestRandom", "help text", RandomVariableValue (ConstantVariable (1.0)), MakeRandomVariableAccessor (&AttributeObjectTest::m_random), MakeRandomVariableChecker ()) .AddAttribute ("TestFloat", "help text", DoubleValue (-1.1), MakeDoubleAccessor (&AttributeObjectTest::m_float), MakeDoubleChecker ()) .AddAttribute ("TestVector1", "help text", ObjectVectorValue (), MakeObjectVectorAccessor (&AttributeObjectTest::m_vector1), MakeObjectVectorChecker ()) .AddAttribute ("TestVector2", "help text", ObjectVectorValue (), MakeObjectVectorAccessor (&AttributeObjectTest::DoGetVectorN, &AttributeObjectTest::DoGetVector), MakeObjectVectorChecker ()) .AddAttribute ("IntegerTraceSource1", "help text", IntegerValue (-2), MakeIntegerAccessor (&AttributeObjectTest::m_intSrc1), MakeIntegerChecker ()) .AddAttribute ("IntegerTraceSource2", "help text", IntegerValue (-2), MakeIntegerAccessor (&AttributeObjectTest::DoSetIntSrc, &AttributeObjectTest::DoGetIntSrc), MakeIntegerChecker ()) .AddAttribute ("UIntegerTraceSource", "help text", UintegerValue (2), MakeUintegerAccessor (&AttributeObjectTest::m_uintSrc), MakeIntegerChecker ()) .AddAttribute ("DoubleTraceSource", "help text", DoubleValue (2), MakeDoubleAccessor (&AttributeObjectTest::m_doubleSrc), MakeDoubleChecker ()) .AddAttribute ("BoolTraceSource", "help text", BooleanValue (false), MakeBooleanAccessor (&AttributeObjectTest::m_boolSrc), MakeBooleanChecker ()) .AddAttribute ("EnumTraceSource", "help text", EnumValue (false), MakeEnumAccessor (&AttributeObjectTest::m_enumSrc), MakeEnumChecker (TEST_A, "TestA")) .AddAttribute ("ValueClassSource", "help text", ValueClassTestValue (ValueClassTest ()), MakeValueClassTestAccessor (&AttributeObjectTest::m_valueSrc), MakeValueClassTestChecker ()) .AddTraceSource ("Source1", "help test", MakeTraceSourceAccessor (&AttributeObjectTest::m_intSrc1)) .AddTraceSource ("Source2", "help text", MakeTraceSourceAccessor (&AttributeObjectTest::m_cb)) .AddTraceSource ("ValueSource", "help text", MakeTraceSourceAccessor (&AttributeObjectTest::m_valueSrc)) .AddAttribute ("Pointer", "help text", PointerValue (), MakePointerAccessor (&AttributeObjectTest::m_ptr), MakePointerChecker ()) .AddAttribute ("Callback", "help text", CallbackValue (), MakeCallbackAccessor (&AttributeObjectTest::m_cbValue), MakeCallbackChecker ()) ; return tid; } void AddToVector1 (void) { m_vector1.push_back (CreateObject ()); } void AddToVector2 (void) { m_vector2.push_back (CreateObject ()); } void InvokeCb (double a, int b, float c) { m_cb (a,b,c); } void InvokeCbValue (int8_t a) { if (!m_cbValue.IsNull ()) { m_cbValue (a); } } private: void DoSetTestB (bool v) { m_boolTestA = v; } bool DoGetTestB (void) const { return m_boolTestA; } int16_t DoGetInt16 (void) const { return m_int16SetGet; } void DoSetInt16 (int16_t v) { m_int16SetGet = v; } uint32_t DoGetVectorN (void) const { return m_vector2.size (); } Ptr DoGetVector (uint32_t i) const { return m_vector2[i]; } bool DoSetIntSrc (int8_t v) { m_intSrc2 = v; return true; } int8_t DoGetIntSrc (void) const { return m_intSrc2; } bool m_boolTestA; bool m_boolTest; int16_t m_int16; int16_t m_int16WithBounds; int16_t m_int16SetGet; uint8_t m_uint8; float m_float; enum Test_e m_enum; RandomVariable m_random; std::vector > m_vector1; std::vector > m_vector2; Callback m_cbValue; TracedValue m_intSrc1; TracedValue m_intSrc2; TracedCallback m_cb; TracedValue m_valueSrc; Ptr m_ptr; TracedValue m_uintSrc; TracedValue m_enumSrc; TracedValue m_doubleSrc; TracedValue m_boolSrc; }; NS_OBJECT_ENSURE_REGISTERED (AttributeObjectTest); // =========================================================================== // Test case template used for generic Attribute Value types -- used to make // sure that Attributes work as expected. // =========================================================================== template class AttributeTestCase : public TestCase { public: AttributeTestCase (std::string description); virtual ~AttributeTestCase (); private: virtual void DoRun (void); bool CheckGetCodePaths (Ptr p, std::string attributeName, std::string expectedString, T expectedValue); }; template AttributeTestCase::AttributeTestCase (std::string description) : TestCase (description) { } template AttributeTestCase::~AttributeTestCase () { } template bool AttributeTestCase::CheckGetCodePaths ( Ptr p, std::string attributeName, std::string expectedString, T expectedValue) { StringValue stringValue; T actualValue; // // Get an Attribute value through its StringValue representation. // bool ok1 = p->GetAttributeFailSafe (attributeName.c_str (), stringValue); bool ok2 = stringValue.Get () == expectedString; // // Get the existing boolean value through its particular type representation. // bool ok3 = p->GetAttributeFailSafe (attributeName.c_str (), actualValue); bool ok4 = expectedValue.Get () == actualValue.Get (); return ok1 && ok2 && ok3 && ok4; } // =========================================================================== // The actual Attribute type test cases are specialized for each Attribute type // =========================================================================== template <> void AttributeTestCase::DoRun (void) { Ptr p; bool ok; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // Set the default value of the BooleanValue and create an object. The new // default value should stick. // Config::SetDefault ("ns3::AttributeObjectTest::TestBoolName", StringValue ("true")); p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); ok = CheckGetCodePaths (p, "TestBoolName", "true", BooleanValue (true)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by default value"); // // Set the default value of the BooleanValue the other way and create an object. // The new default value should stick. // Config::SetDefaultFailSafe ("ns3::AttributeObjectTest::TestBoolName", StringValue ("false")); p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); ok = CheckGetCodePaths (p, "TestBoolName", "false", BooleanValue (false)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not et properly by default value"); // // Set the BooleanValue Attribute to true via SetAttributeFailSafe path. // ok = p->SetAttributeFailSafe ("TestBoolName", StringValue ("true")); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() \"TestBoolName\" to true"); ok = CheckGetCodePaths (p, "TestBoolName", "true", BooleanValue (true)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() via StringValue"); // // Set the BooleanValue to false via SetAttributeFailSafe path. // ok = p->SetAttributeFailSafe ("TestBoolName", StringValue ("false")); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() \"TestBoolName\" to false"); ok = CheckGetCodePaths (p, "TestBoolName", "false", BooleanValue (false)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() via StringValue"); // // Create an object using // p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // The previous object-based tests checked access directly. Now check through // setter and getter. The code here looks the same, but the underlying // attribute is declared differently in the object. First make sure we can set // to true. // ok = p->SetAttributeFailSafe ("TestBoolA", StringValue ("true")); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() a boolean value to true"); ok = CheckGetCodePaths (p, "TestBoolA", "true", BooleanValue (true)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() (getter/setter) via StringValue"); // // Now Set the BooleanValue to false via the setter. // ok = p->SetAttributeFailSafe ("TestBoolA", StringValue ("false")); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() a boolean value to false"); ok = CheckGetCodePaths (p, "TestBoolA", "false", BooleanValue (false)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() (getter/setter) via StringValue"); } template <> void AttributeTestCase::DoRun (void) { Ptr p; bool ok; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // When the object is first created, the Attribute should have the default // value. // ok = CheckGetCodePaths (p, "TestInt16", "-2", IntegerValue (-2)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by default value"); // // Set the Attribute to a negative value through a StringValue. // ok = p->SetAttributeFailSafe ("TestInt16", StringValue ("-5")); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via StringValue to -5"); ok = CheckGetCodePaths (p, "TestInt16", "-5", IntegerValue (-5)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() via StringValue"); // // Set the Attribute to a positive value through a StringValue. // ok = p->SetAttributeFailSafe ("TestInt16", StringValue ("+2")); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via StringValue to +2"); ok = CheckGetCodePaths (p, "TestInt16", "2", IntegerValue (2)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() via StringValue"); // // Set the Attribute to the most negative value of the signed 16-bit range. // ok = p->SetAttributeFailSafe ("TestInt16", StringValue ("-32768")); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via StringValue to -32768"); ok = CheckGetCodePaths (p, "TestInt16", "-32768", IntegerValue (-32768)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() (most negative) via StringValue"); // // Try to set the Attribute past the most negative value of the signed 16-bit // range and make sure the underlying attribute is unchanged. // ok = p->SetAttributeFailSafe ("TestInt16", StringValue ("-32769")); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via StringValue to -32769"); ok = CheckGetCodePaths (p, "TestInt16", "-32768", IntegerValue (-32768)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes"); // // Set the Attribute to the most positive value of the signed 16-bit range. // ok = p->SetAttributeFailSafe ("TestInt16", StringValue ("32767")); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via StringValue to 32767"); ok = CheckGetCodePaths (p, "TestInt16", "32767", IntegerValue (32767)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() (most positive) via StringValue"); // // Try to set the Attribute past the most positive value of the signed 16-bit // range and make sure the underlying attribute is unchanged. // ok = p->SetAttributeFailSafe ("TestInt16", StringValue ("32768")); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via StringValue to 32768"); ok = CheckGetCodePaths (p, "TestInt16", "32767", IntegerValue (32767)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes"); // // Attributes can have limits other than the intrinsic limits of the // underlying data types. These limits are specified in the Object. // ok = p->SetAttributeFailSafe ("TestInt16WithBounds", IntegerValue (10)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 10"); ok = CheckGetCodePaths (p, "TestInt16WithBounds", "10", IntegerValue (10)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() (positive limit) via StringValue"); // // Set the Attribute past the positive limit. // ok = p->SetAttributeFailSafe ("TestInt16WithBounds", IntegerValue (11)); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via IntegerValue to 11"); ok = CheckGetCodePaths (p, "TestInt16WithBounds", "10", IntegerValue (10)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes"); // // Set the Attribute at the negative limit. // ok = p->SetAttributeFailSafe ("TestInt16WithBounds", IntegerValue (-5)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via IntegerValue to -5"); ok = CheckGetCodePaths (p, "TestInt16WithBounds", "-5", IntegerValue (-5)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() (negative limit) via StringValue"); // // Set the Attribute past the negative limit. // ok = p->SetAttributeFailSafe ("TestInt16WithBounds", IntegerValue (-6)); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via IntegerValue to -6"); ok = CheckGetCodePaths (p, "TestInt16WithBounds", "-5", IntegerValue (-5)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes"); } template <> void AttributeTestCase::DoRun (void) { Ptr p; bool ok; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // When the object is first created, the Attribute should have the default // value. // ok = CheckGetCodePaths (p, "TestUint8", "1", UintegerValue (1)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by default value");; // // Set the Attribute to zero. // ok = p->SetAttributeFailSafe ("TestUint8", UintegerValue (0)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() to 0"); ok = CheckGetCodePaths (p, "TestUint8", "0", UintegerValue (0)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() via StringValue"); // // Set the Attribute to the most positive value of the unsigned 8-bit range. // ok = p->SetAttributeFailSafe ("TestUint8", UintegerValue (255)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() to 255"); ok = CheckGetCodePaths (p, "TestUint8", "255", UintegerValue (255)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() (positive limit) via UintegerValue"); // // Try and set the Attribute past the most positive value of the unsigned // 8-bit range. // ok = p->SetAttributeFailSafe ("TestUint8", UintegerValue (256)); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() to 256"); ok = CheckGetCodePaths (p, "TestUint8", "255", UintegerValue (255)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes"); // // Set the Attribute to the most positive value of the unsigned 8-bit range // through a StringValue. // ok = p->SetAttributeFailSafe ("TestUint8", StringValue ("255")); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via StringValue to 255"); ok = CheckGetCodePaths (p, "TestUint8", "255", UintegerValue (255)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() via StringValue"); // // Try and set the Attribute past the most positive value of the unsigned // 8-bit range through a StringValue. // ok = p->SetAttributeFailSafe ("TestUint8", StringValue ("256")); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via StringValue to 256"); ok = CheckGetCodePaths (p, "TestUint8", "255", UintegerValue (255)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes"); // // Try to set the Attribute to a negative StringValue. // ok = p->SetAttributeFailSafe ("TestUint8", StringValue ("-1")); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via StringValue to -1"); } template <> void AttributeTestCase::DoRun (void) { Ptr p; bool ok; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // When the object is first created, the Attribute should have the default // value. // ok = CheckGetCodePaths (p, "TestFloat", "-1.1", DoubleValue ((float)-1.1)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by default value"); // // Set the Attribute. // ok = p->SetAttributeFailSafe ("TestFloat", DoubleValue ((float)2.3)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() to 2.3"); ok = CheckGetCodePaths (p, "TestFloat", "2.3", DoubleValue ((float)2.3)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() via DoubleValue"); } template <> void AttributeTestCase::DoRun (void) { Ptr p; bool ok; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // When the object is first created, the Attribute should have the default // value. // ok = CheckGetCodePaths (p, "TestEnum", "TestA", EnumValue (AttributeObjectTest::TEST_A)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by default value"); // // Set the Attribute using the EnumValue type. // ok = p->SetAttributeFailSafe ("TestEnum", EnumValue (AttributeObjectTest::TEST_C)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() to TEST_C"); ok = CheckGetCodePaths (p, "TestEnum", "TestC", EnumValue (AttributeObjectTest::TEST_C)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() via EnumValue"); // // Set the Attribute using the StringValue type. // ok = p->SetAttributeFailSafe ("TestEnum", StringValue ("TestB")); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() to TEST_B"); ok = CheckGetCodePaths (p, "TestEnum", "TestB", EnumValue (AttributeObjectTest::TEST_B)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() via StringValue"); // // Try to set the Attribute to a bogus enum using the StringValue type and // make sure the underlying value doesn't change. // ok = p->SetAttributeFailSafe ("TestEnum", StringValue ("TestD")); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() to TEST_D"); // ok = CheckGetCodePaths (p, "TestEnum", "TestB", EnumValue (AttributeObjectTest::TEST_B)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes"); // // Try to set the Attribute to a bogus enum using an integer implicit conversion // and make sure the underlying value doesn't change. // ok = p->SetAttributeFailSafe ("TestEnum", EnumValue (5)); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() to 5"); ok = CheckGetCodePaths (p, "TestEnum", "TestB", EnumValue (AttributeObjectTest::TEST_B)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes"); } template <> void AttributeTestCase::DoRun (void) { Ptr p; bool ok; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // Try to set a UniformVariable // ok = p->SetAttributeFailSafe ("TestRandom", RandomVariableValue (UniformVariable (0., 1.))); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() a UniformVariable"); // // Try to set a ConstantVariable // ok = p->SetAttributeFailSafe ("TestRandom", RandomVariableValue (ConstantVariable (10.))); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() a UniformVariable"); } // =========================================================================== // Test case for Object Vector Attributes. Generic nature is pretty much lost // here, so we just break the class out. // =========================================================================== class ObjectVectorAttributeTestCase : public TestCase { public: ObjectVectorAttributeTestCase (std::string description); virtual ~ObjectVectorAttributeTestCase () {} private: virtual void DoRun (void); }; ObjectVectorAttributeTestCase::ObjectVectorAttributeTestCase (std::string description) : TestCase (description) { } void ObjectVectorAttributeTestCase::DoRun (void) { Ptr p; ObjectVectorValue vector; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // When the object is first created, the Attribute should have no items in // the vector. // p->GetAttribute ("TestVector1", vector); NS_TEST_ASSERT_MSG_EQ (vector.GetN (), 0, "Initial count of ObjectVectorValue \"TestVector1\" should be zero"); // // Adding to the attribute shouldn't affect the value we already have. // p->AddToVector1 (); NS_TEST_ASSERT_MSG_EQ (vector.GetN (), 0, "Initial count of ObjectVectorValue \"TestVector1\" should still be zero"); // // Getting the attribute again should update the value. // p->GetAttribute ("TestVector1", vector); NS_TEST_ASSERT_MSG_EQ (vector.GetN (), 1, "ObjectVectorValue \"TestVector1\" should be incremented"); // // Get the Object pointer from the value. // Ptr a = vector.Get (0); NS_TEST_ASSERT_MSG_NE (a, 0, "Ptr from VectorValue \"TestVector1\" is zero"); // // Adding to the attribute shouldn't affect the value we already have. // p->AddToVector1 (); NS_TEST_ASSERT_MSG_EQ (vector.GetN (), 1, "Count of ObjectVectorValue \"TestVector1\" should still be one"); // // Getting the attribute again should update the value. // p->GetAttribute ("TestVector1", vector); NS_TEST_ASSERT_MSG_EQ (vector.GetN (), 2, "ObjectVectorValue \"TestVector1\" should be incremented"); } // =========================================================================== // Trace sources with value semantics can be used like Attributes. Make sure // we can use them that way. // =========================================================================== class IntegerTraceSourceAttributeTestCase : public TestCase { public: IntegerTraceSourceAttributeTestCase (std::string description); virtual ~IntegerTraceSourceAttributeTestCase () {} private: virtual void DoRun (void); }; IntegerTraceSourceAttributeTestCase::IntegerTraceSourceAttributeTestCase (std::string description) : TestCase (description) { } void IntegerTraceSourceAttributeTestCase::DoRun (void) { Ptr p; IntegerValue iv; bool ok; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // When the object is first created, the Attribute should have the default // value. // p->GetAttribute ("IntegerTraceSource1", iv); NS_TEST_ASSERT_MSG_EQ (iv.Get (), -2, "Attribute not set properly by default value"); // // Set the Attribute to a positive value through an IntegerValue. // ok = p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (5)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 5"); p->GetAttribute ("IntegerTraceSource1", iv); NS_TEST_ASSERT_MSG_EQ (iv.Get (), 5, "Attribute not set properly by SetAttributeFailSafe() via IntegerValue"); // // Limits should work. // ok = p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (127)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 127"); ok = p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (128)); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via IntegerValue to 128"); ok = p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (-128)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via IntegerValue to -128"); ok = p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (-129)); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via IntegerValue to -129"); // // When the object is first created, the Attribute should have the default // value. // p->GetAttribute ("IntegerTraceSource2", iv); NS_TEST_ASSERT_MSG_EQ (iv.Get (), -2, "Attribute not set properly by default value"); // // Set the Attribute to a positive value through an IntegerValue. // ok = p->SetAttributeFailSafe ("IntegerTraceSource2", IntegerValue (5)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 5"); p->GetAttribute ("IntegerTraceSource2", iv); NS_TEST_ASSERT_MSG_EQ (iv.Get (), 5, "Attribute not set properly by SetAttributeFailSafe() via IntegerValue"); // // Limits should work. // ok = p->SetAttributeFailSafe ("IntegerTraceSource2", IntegerValue (127)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 127"); ok = p->SetAttributeFailSafe ("IntegerTraceSource2", IntegerValue (128)); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via IntegerValue to 128"); ok = p->SetAttributeFailSafe ("IntegerTraceSource2", IntegerValue (-128)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via IntegerValue to -128"); ok = p->SetAttributeFailSafe ("IntegerTraceSource2", IntegerValue (-129)); NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via IntegerValue to -129"); } // =========================================================================== // Trace sources used like Attributes must also work as trace sources. Make // sure we can use them that way. // =========================================================================== class IntegerTraceSourceTestCase : public TestCase { public: IntegerTraceSourceTestCase (std::string description); virtual ~IntegerTraceSourceTestCase () {} private: virtual void DoRun (void); void NotifySource1 (int8_t old, int8_t n) { m_got1 = n; } int64_t m_got1; }; IntegerTraceSourceTestCase::IntegerTraceSourceTestCase (std::string description) : TestCase (description) { } void IntegerTraceSourceTestCase::DoRun (void) { Ptr p; bool ok; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // Check to make sure changing an Attibute value triggers a trace callback // that sets a member variable. // m_got1 = 1234; ok = p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (-1)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via IntegerValue to -1"); // // Source1 is declared as a TraceSourceAccessor to m_intSrc1. This m_intSrc1 // is also declared as an Integer Attribute. We just checked to make sure we // could set it using an IntegerValue through its IntegerTraceSource1 "persona." // We should also be able to hook a trace source to the underlying variable. // ok = p->TraceConnectWithoutContext ("Source1", MakeCallback (&IntegerTraceSourceTestCase::NotifySource1, this)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not TraceConnectWithoutContext() \"Source1\" to NodifySource1()"); // // When we set the IntegerValue that now underlies both the Integer Attribute // and the trace source, the trace should fire and call NotifySource1 which // will set m_got1 to the new value. // ok = p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (0)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 0"); NS_TEST_ASSERT_MSG_EQ (m_got1, 0, "Hitting a TracedValue does not cause trace callback to be called"); // // Now disconnect from the trace source and ensure that the trace callback // is not called if the trace source is hit. // ok = p->TraceDisconnectWithoutContext ("Source1", MakeCallback (&IntegerTraceSourceTestCase::NotifySource1, this)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not TraceConnectWithoutContext() \"Source1\" to NodifySource1()"); ok = p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (1)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via IntegerValue to 1"); NS_TEST_ASSERT_MSG_EQ (m_got1, 0, "Hitting a TracedValue after disconnect still causes callback"); } // =========================================================================== // Trace sources used like Attributes must also work as trace sources. Make // sure we can use them that way. // =========================================================================== class TracedCallbackTestCase : public TestCase { public: TracedCallbackTestCase (std::string description); virtual ~TracedCallbackTestCase () {} private: virtual void DoRun (void); void NotifySource2 (double a, int b, float c) { m_got2 = a; } double m_got2; }; TracedCallbackTestCase::TracedCallbackTestCase (std::string description) : TestCase (description) { } void TracedCallbackTestCase::DoRun (void) { Ptr p; bool ok; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // Initialize the // m_got2 = 4.3; // // Invoke the callback that lies at the heart of this test. We have a // method InvokeCb() that just executes m_cb(). The variable m_cb is // declared as a TracedCallback. This kind of beast // is like a callback but can call a list of targets. This list should // be empty so nothing should happen now. Specifically, m_got2 shouldn't // have changed. // p->InvokeCb (1.0, -5, 0.0); NS_TEST_ASSERT_MSG_EQ (m_got2, 4.3, "Invoking a newly created TracedCallback results in an unexpected callback"); // // Now, wire the TracedCallback up to a trace sink. This sink will just set // m_got2 to the first argument. // ok = p->TraceConnectWithoutContext ("Source2", MakeCallback (&TracedCallbackTestCase::NotifySource2, this)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not TraceConnectWithoutContext() to NotifySource2"); // // Now if we invoke the callback, the trace source should fire and m_got2 // should be set in the trace sink. // p->InvokeCb (1.0, -5, 0.0); NS_TEST_ASSERT_MSG_EQ (m_got2, 1.0, "Invoking TracedCallback does not result in trace callback"); // // Now, disconnect the trace sink and see what happens when we invoke the // callback again. Of course, the trace should not happen and m_got2 // should remain unchanged. // ok = p->TraceDisconnectWithoutContext ("Source2", MakeCallback (&TracedCallbackTestCase::NotifySource2, this)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not TraceDisconnectWithoutContext() from NotifySource2"); p->InvokeCb (-1.0, -5, 0.0); NS_TEST_ASSERT_MSG_EQ (m_got2, 1.0, "Invoking disconnected TracedCallback unexpectedly results in trace callback"); } // =========================================================================== // Smart pointers (Ptr) are central to our architecture, so they must work as // attributes. // =========================================================================== class PointerAttributeTestCase : public TestCase { public: PointerAttributeTestCase (std::string description); virtual ~PointerAttributeTestCase () {} private: virtual void DoRun (void); void NotifySource2 (double a, int b, float c) { m_got2 = a; } double m_got2; }; PointerAttributeTestCase::PointerAttributeTestCase (std::string description) : TestCase (description) { } void PointerAttributeTestCase::DoRun (void) { Ptr p; bool ok; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // We have declared a PointerValue Attribute named "Pointer" with a pointer // checker of type Derived. This means that we should be able to pull out // a Ptr with the initial value (which is 0). // PointerValue ptr; p->GetAttribute ("Pointer", ptr); Ptr derived = ptr.Get (); NS_TEST_ASSERT_MSG_EQ (derived, 0, "Unexpectedly found non-null pointer in newly initialized PointerValue Attribute"); // // Now, lets create an Object of type Derived and set the local Ptr to point // to that object. We can then set the PointerValue Attribute to that Ptr. // derived = Create (); ok = p->SetAttributeFailSafe ("Pointer", PointerValue (derived)); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() a PointerValue of the correct type"); // // Pull the value back out of the Attribute and make sure it points to the // correct object. // p->GetAttribute ("Pointer", ptr); Ptr stored = ptr.Get (); NS_TEST_ASSERT_MSG_EQ (stored, derived, "Retreived Attribute does not match stored PointerValue"); // // We should be able to use the Attribute Get() just like GetObject, // So see if we can get a Ptr out of the Ptr we stored. // This should be a pointer to the same physical memory since its the // same object. // p->GetAttribute ("Pointer", ptr); Ptr storedBase = ptr.Get (); NS_TEST_ASSERT_MSG_EQ (storedBase, stored, "Retreived Ptr does not match stored Ptr"); // // If we try to Get() something that is unrelated to what we stored, we should // retrieve a 0. // p->GetAttribute ("Pointer", ptr); Ptr x = ptr.Get (); NS_TEST_ASSERT_MSG_EQ (x, 0, "Unexpectedly retreived unrelated Ptr from stored Ptr"); } // =========================================================================== // Test the Attributes of type CallbackVale. // =========================================================================== class CallbackValueTestCase : public TestCase { public: CallbackValueTestCase (std::string description); virtual ~CallbackValueTestCase () {} void InvokeCbValue (int8_t a) { if (!m_cbValue.IsNull ()) { m_cbValue (a); } } private: virtual void DoRun (void); Callback m_cbValue; void NotifyCallbackValue (int8_t a) { m_gotCbValue = a; } int16_t m_gotCbValue; }; CallbackValueTestCase::CallbackValueTestCase (std::string description) : TestCase (description) { } void CallbackValueTestCase::DoRun (void) { Ptr p; bool ok; p = CreateObject (); NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject"); // // The member variable m_cbValue is declared as a Callback. The // Attibute named "Callback" also points to m_cbValue and allows us to set the // callback using that Attribute. // // NotifyCallbackValue is going to be the target of the callback and will just set // m_gotCbValue to its single parameter. This will be the parameter from the // callback invocation. The method InvokeCbValue() just invokes the m_cbValue // callback if it is non-null. // m_gotCbValue = 1; // // If we invoke the callback (which has not been set) nothing should happen. // Further, nothing should happen when we initialize the callback (it shouldn't // accidentally fire). // p->InvokeCbValue (2); CallbackValue cbValue = MakeCallback (&CallbackValueTestCase::NotifyCallbackValue, this); NS_TEST_ASSERT_MSG_EQ (m_gotCbValue, 1, "Callback unexpectedly fired"); ok = p->SetAttributeFailSafe ("Callback", cbValue); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() a CallbackValue"); // // Now that the callback has been set, invoking it should set m_gotCbValue. // p->InvokeCbValue (2); NS_TEST_ASSERT_MSG_EQ (m_gotCbValue, 2, "Callback Attribute set by CallbackValue did not fire"); ok = p->SetAttributeFailSafe ("Callback", CallbackValue (MakeNullCallback ())); NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() a null CallbackValue"); // // If the callback has been set to a null callback, it should no longer fire. // p->InvokeCbValue (3); NS_TEST_ASSERT_MSG_EQ (m_gotCbValue, 2, "Callback Attribute set to null callback unexpectedly fired"); } // =========================================================================== // The Test Suite that glues all of the Test Cases together. // =========================================================================== class AttributesTestSuite : public TestSuite { public: AttributesTestSuite (); }; AttributesTestSuite::AttributesTestSuite () : TestSuite ("attributes", UNIT) { AddTestCase (new AttributeTestCase ("Check Attributes of type BooleanValue")); AddTestCase (new AttributeTestCase ("Check Attributes of type IntegerValue")); AddTestCase (new AttributeTestCase ("Check Attributes of type UintegerValue")); AddTestCase (new AttributeTestCase ("Check Attributes of type DoubleValue")); AddTestCase (new AttributeTestCase ("Check Attributes of type EnumValue")); AddTestCase (new AttributeTestCase ("Check Attributes of type RandomVariableValue")); AddTestCase (new ObjectVectorAttributeTestCase ("Check Attributes of type ObjectVectorValue")); AddTestCase (new IntegerTraceSourceAttributeTestCase ("Ensure TracedValue can be set like IntegerValue")); AddTestCase (new IntegerTraceSourceTestCase ("Ensure TracedValue also works as trace source")); AddTestCase (new TracedCallbackTestCase ("Ensure TracedCallback works as trace source")); AddTestCase (new PointerAttributeTestCase ("Check Attributes of type PointerValue")); AddTestCase (new CallbackValueTestCase ("Check Attributes of type CallbackValue")); } static AttributesTestSuite attributesTestSuite; } // namespace ns3