Remove and replace attribute unit tests (bug 675)
authorCraig Dowell <craigdo@ee.washington.edu>
Wed, 23 Sep 2009 15:20:23 -0700
changeset 5239 2e753de86174
parent 5234 5c75d40fedcd
child 5240 8cc3fd3830d8
Remove and replace attribute unit tests (bug 675)
src/core/attribute-test-suite.cc
src/core/attribute-test.cc
src/core/test.cc
src/core/test.h
src/core/wscript
test.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/attribute-test-suite.cc	Wed Sep 23 15:20:23 2009 -0700
@@ -0,0 +1,1175 @@
+/* -*- 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 "test.h"
+#include "object.h"
+#include "boolean.h"
+#include "integer.h"
+#include "uinteger.h"
+#include "enum.h"
+#include "string.h"
+#include "random-variable.h"
+#include "double.h"
+#include "object-vector.h"
+#include "traced-value.h"
+#include "callback.h"
+#include "trace-source-accessor.h"
+#include "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 ("Derived")
+      .SetParent<Object> ()
+      ;
+    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<Object> ()
+      .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<int16_t> ())
+      .AddAttribute ("TestInt16WithBounds", "help text",
+		     IntegerValue (-2),
+		     MakeIntegerAccessor (&AttributeObjectTest::m_int16WithBounds),
+		     MakeIntegerChecker<int16_t> (-5, 10))
+      .AddAttribute ("TestInt16SetGet", "help text",
+		     IntegerValue (6),
+		     MakeIntegerAccessor (&AttributeObjectTest::DoSetInt16,
+				       &AttributeObjectTest::DoGetInt16),
+		     MakeIntegerChecker<int16_t> ())
+      .AddAttribute ("TestUint8", "help text",
+		     UintegerValue (1),
+		     MakeUintegerAccessor (&AttributeObjectTest::m_uint8),
+		     MakeUintegerChecker<uint8_t> ())
+      .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<float> ())
+      .AddAttribute ("TestVector1", "help text",
+		     ObjectVectorValue (),
+		     MakeObjectVectorAccessor (&AttributeObjectTest::m_vector1),
+		     MakeObjectVectorChecker<Derived> ())
+      .AddAttribute ("TestVector2", "help text",
+		     ObjectVectorValue (),
+		     MakeObjectVectorAccessor (&AttributeObjectTest::DoGetVectorN,
+						&AttributeObjectTest::DoGetVector),
+		     MakeObjectVectorChecker<Derived> ())
+      .AddAttribute ("IntegerTraceSource1", "help text",
+		     IntegerValue (-2),
+		     MakeIntegerAccessor (&AttributeObjectTest::m_intSrc1),
+		     MakeIntegerChecker<int8_t> ())
+      .AddAttribute ("IntegerTraceSource2", "help text",
+		     IntegerValue (-2),
+		     MakeIntegerAccessor (&AttributeObjectTest::DoSetIntSrc,
+					  &AttributeObjectTest::DoGetIntSrc),
+		     MakeIntegerChecker<int8_t> ())
+      .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<Derived> ())
+      .AddAttribute ("Callback", "help text",
+                     CallbackValue (),
+                     MakeCallbackAccessor (&AttributeObjectTest::m_cbValue),
+                     MakeCallbackChecker ())
+      ;
+        
+    return tid;
+  }
+
+  void AddToVector1 (void) {m_vector1.push_back (CreateObject<Derived> ());}
+  void AddToVector2 (void) {m_vector2.push_back (CreateObject<Derived> ());}
+  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<Derived> 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<Ptr<Derived> > m_vector1;
+  std::vector<Ptr<Derived> > m_vector2;
+  Callback<void,int8_t> m_cbValue;
+  TracedValue<int8_t> m_intSrc1;
+  TracedValue<int8_t> m_intSrc2;
+  TracedCallback<double, int, float> m_cb;
+  TracedValue<ValueClassTest> m_valueSrc;
+  Ptr<Derived> m_ptr;
+};
+
+NS_OBJECT_ENSURE_REGISTERED (AttributeObjectTest);
+
+// ===========================================================================
+// Test case template used for generic Attribute Value types -- used to make 
+// sure that Attributes work as expected.
+// ===========================================================================
+template <typename T>
+class AttributeTestCase : public TestCase
+{
+public:
+  AttributeTestCase (std::string description);
+  virtual ~AttributeTestCase ();
+
+private:
+  virtual bool DoRun (void);
+
+  bool CheckGetCodePaths (Ptr<Object> p, std::string attributeName, std::string expectedString, T expectedValue);
+};
+
+template <typename T>
+AttributeTestCase<T>::AttributeTestCase (std::string description)
+  : TestCase (description)
+{
+}
+
+template <typename T>
+AttributeTestCase<T>::~AttributeTestCase ()
+{
+}
+
+template <typename T> bool
+AttributeTestCase<T>::CheckGetCodePaths (
+  Ptr<Object> p, 
+  std::string attributeName,
+  std::string expectedString,
+  T expectedValue)
+{
+  StringValue stringValue;
+  T actualValue;
+
+  //
+  // Get an Attribute value through its StringValue representation.
+  //
+  bool ok = p->GetAttributeFailSafe (attributeName.c_str (), stringValue);
+  NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not GetAttributeFailSafe() " << attributeName << " from Object");
+  NS_TEST_ASSERT_MSG_EQ (stringValue.Get (), expectedString, "Got unexpected StringValue representation");
+
+  //
+  // Get the existing boolean value through its particular type representation.
+  //
+  ok = p->GetAttributeFailSafe (attributeName.c_str (), actualValue);
+  NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not GetAttributeFailSafe() " << attributeName << " from Object");
+  NS_TEST_ASSERT_MSG_EQ (actualValue.Get (), expectedValue.Get (), "Got unexpected Value from Object");
+
+  return GetErrorStatus ();
+}
+
+// ===========================================================================
+// The actual Attribute type test cases are specialized for each Attribute type
+// ===========================================================================
+template <> bool
+AttributeTestCase<BooleanValue>::DoRun (void)
+{
+  AttributeList attrs;
+  Ptr<AttributeObjectTest> p;
+  bool ok;
+
+  //
+  // Test setting a boolean via string representation using AttributeList.
+  //
+  ok = attrs.SetFailSafe ("ns3::AttributeObjectTest::TestBoolName", StringValue ("false"));
+  NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetFailSafe() \"ns3::AttributeObjectTest::TestBoolName\" into AttributeList");
+
+  //
+  // Create an object using that attribute list (which should therefore have the
+  // boolean from above set to false.
+  //
+  p = CreateObjectWithAttributes<AttributeObjectTest> (attrs);
+  NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObjectWithAttributes");
+
+  ok = CheckGetCodePaths (p, "TestBoolName", "false", BooleanValue (false));
+  NS_TEST_ASSERT_MSG_EQ (ok, false, "Attribute not set properly from CreateObjectWithAttributes");
+
+  //
+  // Set the default value of the BooleanValue and create an object.  The new
+  // default value should stick.
+  //
+  AttributeList::GetGlobal ()->SetFailSafe ("ns3::AttributeObjectTest::TestBoolName", StringValue ("true"));
+  p = CreateObject<AttributeObjectTest> ();
+  NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject");
+
+  ok = CheckGetCodePaths (p, "TestBoolName", "true", BooleanValue (true));
+  NS_TEST_ASSERT_MSG_EQ (ok, false, "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.
+  //
+  AttributeList::GetGlobal ()->SetFailSafe ("ns3::AttributeObjectTest::TestBoolName", StringValue ("false"));
+
+  p = CreateObject<AttributeObjectTest> ();
+  NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject");
+
+  ok = CheckGetCodePaths (p, "TestBoolName", "false", BooleanValue (false));
+  NS_TEST_ASSERT_MSG_EQ (ok, false, "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, false, "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, false, "Attribute not set properly by SetAttributeFailSafe() via StringValue");
+
+  //
+  // Create an object using individually provided StringValue Attribute.
+  //
+  p = CreateObjectWithAttributes<AttributeObjectTest> ("TestBoolName", StringValue ("true"));
+  NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObjectWithAttributes");
+
+  ok = CheckGetCodePaths (p, "TestBoolName", "true", BooleanValue (true));
+  NS_TEST_ASSERT_MSG_EQ (ok, false, "Attribute not set properly by CreateObjectWithAttributes() with StringValue");
+
+  //
+  // Create an object using individually provided BooleanValue Attribute.
+  //
+  p = CreateObjectWithAttributes<AttributeObjectTest> ("TestBoolName", BooleanValue (false));
+  NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObjectWithAttributes");
+
+  ok = CheckGetCodePaths (p, "TestBoolName", "false", BooleanValue (false));
+  NS_TEST_ASSERT_MSG_EQ (ok, false, "Attribute not set properly by CreateObjectWithAttributes() with BooleanValue");
+
+  //
+  // 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, false, "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, false, "Attribute not set properly by SetAttributeFailSafe() (getter/setter) via StringValue");
+
+  return GetErrorStatus ();
+}
+
+template <> bool
+AttributeTestCase<IntegerValue>::DoRun (void)
+{
+  Ptr<AttributeObjectTest> p;
+  bool ok;
+
+  p = CreateObject<AttributeObjectTest> ();
+  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, false, "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, false, "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, false, "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, false, "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, false, "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, false, "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, false, "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, false, "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, false, "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, false, "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, false, "Error in SetAttributeFailSafe() but value changes");
+
+  return GetErrorStatus ();
+}
+
+template <> bool
+AttributeTestCase<UintegerValue>::DoRun (void)
+{
+  Ptr<AttributeObjectTest> p;
+  bool ok;
+
+  p = CreateObject<AttributeObjectTest> ();
+  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, false, "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, false, "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, false, "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, false, "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, false, "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, false, "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");
+
+  return GetErrorStatus ();
+}
+
+template <> bool
+AttributeTestCase<DoubleValue>::DoRun (void)
+{
+  Ptr<AttributeObjectTest> p;
+  bool ok;
+
+  p = CreateObject<AttributeObjectTest> ();
+  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, false, "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, false, "Attribute not set properly by SetAttributeFailSafe() via DoubleValue");
+
+  return GetErrorStatus ();
+}
+
+template <> bool
+AttributeTestCase<EnumValue>::DoRun (void)
+{
+  Ptr<AttributeObjectTest> p;
+  bool ok;
+
+  p = CreateObject<AttributeObjectTest> ();
+  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, false, "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, false, "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, false, "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, false, "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, false, "Error in SetAttributeFailSafe() but value changes");
+
+  return GetErrorStatus ();
+}
+
+template <> bool
+AttributeTestCase<RandomVariableValue>::DoRun (void)
+{
+  Ptr<AttributeObjectTest> p;
+  bool ok;
+
+  p = CreateObject<AttributeObjectTest> ();
+  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 <snicker> ConstantVariable
+  //
+  ok = p->SetAttributeFailSafe("TestRandom", RandomVariableValue (ConstantVariable (10.)));
+  NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() a UniformVariable");
+
+  return GetErrorStatus ();
+}
+
+// ===========================================================================
+// 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 bool DoRun (void);
+};
+
+ObjectVectorAttributeTestCase::ObjectVectorAttributeTestCase (std::string description)
+  : TestCase (description)
+{
+}
+
+bool
+ObjectVectorAttributeTestCase::DoRun (void)
+{
+  Ptr<AttributeObjectTest> p;
+  ObjectVectorValue vector;
+
+  p = CreateObject<AttributeObjectTest> ();
+  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<Object> a = vector.Get (0);
+  NS_TEST_ASSERT_MSG_NE (a, 0, "Ptr<Object> 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");
+
+  return GetErrorStatus ();
+}
+
+// ===========================================================================
+// 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 bool DoRun (void);
+};
+
+IntegerTraceSourceAttributeTestCase::IntegerTraceSourceAttributeTestCase (std::string description)
+  : TestCase (description)
+{
+}
+
+bool
+IntegerTraceSourceAttributeTestCase::DoRun (void)
+{
+  Ptr<AttributeObjectTest> p;
+  IntegerValue iv;
+  bool ok;
+
+  p = CreateObject<AttributeObjectTest> ();
+  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");
+
+  return GetErrorStatus ();
+}
+
+// ===========================================================================
+// 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 bool DoRun (void);
+
+  void NotifySource1 (int8_t old, int8_t n) {m_got1 = n;}
+  int64_t m_got1;
+};
+
+IntegerTraceSourceTestCase::IntegerTraceSourceTestCase (std::string description)
+  : TestCase (description)
+{
+}
+
+bool
+IntegerTraceSourceTestCase::DoRun (void)
+{
+  Ptr<AttributeObjectTest> p;
+  bool ok;
+
+  p = CreateObject<AttributeObjectTest> ();
+  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");
+
+  return GetErrorStatus ();
+}
+
+// ===========================================================================
+// 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 bool DoRun (void);
+
+  void NotifySource2 (double a, int b, float c) {m_got2 = a;}
+
+  double m_got2;
+};
+
+TracedCallbackTestCase::TracedCallbackTestCase (std::string description)
+  : TestCase (description)
+{
+}
+
+bool
+TracedCallbackTestCase::DoRun (void)
+{
+  Ptr<AttributeObjectTest> p;
+  bool ok;
+
+  p = CreateObject<AttributeObjectTest> ();
+  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<double, int, float>.  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");
+
+  return GetErrorStatus ();
+}
+
+// ===========================================================================
+// 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 bool DoRun (void);
+
+  void NotifySource2 (double a, int b, float c) {m_got2 = a;}
+
+  double m_got2;
+};
+
+PointerAttributeTestCase::PointerAttributeTestCase (std::string description)
+  : TestCase (description)
+{
+}
+
+bool
+PointerAttributeTestCase::DoRun (void)
+{
+  Ptr<AttributeObjectTest> p;
+  bool ok;
+
+  p = CreateObject<AttributeObjectTest> ();
+  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<Derived> with the initial value (which is 0).
+  //
+  PointerValue ptr;
+  p->GetAttribute ("Pointer", ptr);
+  Ptr<Derived> derived = ptr.Get<Derived> ();
+  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<Derived> ();
+  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<Derived> stored = ptr.Get<Derived> ();
+  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<type>,
+  // So see if we can get a Ptr<Object> out of the Ptr<Derived> we stored.
+  // This should be a pointer to the same physical memory since its the 
+  // same object.
+  //
+  p->GetAttribute ("Pointer", ptr);
+  Ptr<Object> storedBase = ptr.Get<Object> ();
+  NS_TEST_ASSERT_MSG_EQ (storedBase, stored, "Retreived Ptr<Object> does not match stored Ptr<Derived>");
+
+  //
+  // If we try to Get() something that is unrelated to what we stored, we should
+  // retrieve a 0.
+  //
+  p->GetAttribute ("Pointer", ptr);
+  Ptr<AttributeObjectTest> x = ptr.Get<AttributeObjectTest> ();
+  NS_TEST_ASSERT_MSG_EQ (x, 0, "Unexpectedly retreived unrelated Ptr<type> from stored Ptr<Derived>");
+
+  //
+  // We should be able to create the object From a list of attributes.
+  //
+  p = CreateObjectWithAttributes<AttributeObjectTest> ("Pointer", PointerValue (Create<Derived> ()));
+  NS_TEST_ASSERT_MSG_NE (p, 0, "Could not create Object with PointerValue Attribute in Attribute List");
+
+  derived = 0;
+  p->GetAttribute ("Pointer", ptr);
+  derived = ptr.Get<Derived> ();
+  NS_TEST_ASSERT_MSG_NE (p, 0, "Retrieved zero PointerValue Attribute after initializing to non-zero Ptr");
+
+  return GetErrorStatus ();
+}
+
+// ===========================================================================
+// ===========================================================================
+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 bool DoRun (void);
+
+  Callback<void,int8_t> m_cbValue;
+
+  void NotifyCallbackValue (int8_t a) {m_gotCbValue = a;}
+
+  int16_t m_gotCbValue;
+};
+
+CallbackValueTestCase::CallbackValueTestCase (std::string description)
+  : TestCase (description)
+{
+}
+
+bool
+CallbackValueTestCase::DoRun (void)
+{
+  Ptr<AttributeObjectTest> p;
+  bool ok;
+
+  p = CreateObject<AttributeObjectTest> ();
+  NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject");
+
+  //
+  // The member variable m_cbValue is declared as a Callback<void, int8_t>.  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<void,int8_t> ()));
+  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");
+  
+  return GetErrorStatus ();
+}
+
+// ===========================================================================
+// 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<BooleanValue> ("Check Attributes of type BooleanValue"));
+  AddTestCase (new AttributeTestCase<IntegerValue> ("Check Attributes of type IntegerValue"));
+  AddTestCase (new AttributeTestCase<UintegerValue> ("Check Attributes of type UintegerValue"));
+  AddTestCase (new AttributeTestCase<DoubleValue> ("Check Attributes of type DoubleValue"));
+  AddTestCase (new AttributeTestCase<EnumValue> ("Check Attributes of type EnumValue"));
+  AddTestCase (new AttributeTestCase<RandomVariableValue> ("Check Attributes of type RandomVariableValue"));
+  AddTestCase (new ObjectVectorAttributeTestCase ("Check Attributes of type ObjectVectorValue"));
+  AddTestCase (new IntegerTraceSourceAttributeTestCase ("Ensure TracedValue<uint8_t> can be set like IntegerValue"));
+  AddTestCase (new IntegerTraceSourceTestCase ("Ensure TracedValue<uint8_t> also works as trace source"));
+  AddTestCase (new TracedCallbackTestCase ("Ensure TracedCallback<double, int, float> works as trace source"));
+  AddTestCase (new PointerAttributeTestCase ("Check Attributes of type PointerValue"));
+  AddTestCase (new CallbackValueTestCase ("Check Attributes of type CallbackValue"));
+}
+
+AttributesTestSuite attributesTestSuite;
+
+} // namespace ns3
--- a/src/core/attribute-test.cc	Mon Sep 21 11:21:05 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,537 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2008 INRIA
- *
- * 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
- *
- * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifdef RUN_SELF_TESTS
-#include "test.h"
-#include "object.h"
-#include "boolean.h"
-#include "integer.h"
-#include "uinteger.h"
-#include "enum.h"
-#include "string.h"
-#include "random-variable.h"
-#include "double.h"
-#include "object-vector.h"
-#include "traced-value.h"
-#include "callback.h"
-#include "trace-source-accessor.h"
-#include "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 AttributeTest : public Test
-{
-public:
-  AttributeTest ();
-  virtual bool RunTests (void);
-private:
-  void NotifySource1 (int8_t old, int8_t n) {
-    m_got1 = n;
-  }
-  void NotifySource2 (double a, int b, float c) {
-    m_got2 = a;
-  }
-  void NotifySourceValue (ValueClassTest old, ValueClassTest n) {
-    m_gotValue = n;
-  }
-  void NotifyCallbackValue (int8_t a) {
-    m_gotCbValue = a;
-  }
-  int64_t m_got1;
-  double m_got2;
-  ValueClassTest m_gotValue;
-  int16_t m_gotCbValue;
-};
-
-class Derived : public Object
-{
-public:
-  static TypeId GetTypeId (void) {
-    static TypeId tid = TypeId ("Derived")
-      .SetParent<Object> ()
-      ;
-    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<Object> ()
-      .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<int16_t> ())
-      .AddAttribute ("TestInt16WithBounds", "help text",
-		     IntegerValue (-2),
-		     MakeIntegerAccessor (&AttributeObjectTest::m_int16WithBounds),
-		     MakeIntegerChecker<int16_t> (-5, 10))
-      .AddAttribute ("TestInt16SetGet", "help text",
-		     IntegerValue (6),
-		     MakeIntegerAccessor (&AttributeObjectTest::DoSetInt16,
-				       &AttributeObjectTest::DoGetInt16),
-		     MakeIntegerChecker<int16_t> ())
-      .AddAttribute ("TestUint8", "help text",
-		     UintegerValue (1),
-		     MakeUintegerAccessor (&AttributeObjectTest::m_uint8),
-		     MakeUintegerChecker<uint8_t> ())
-      .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<float> ())
-      .AddAttribute ("TestVector1", "help text",
-		     ObjectVectorValue (),
-		     MakeObjectVectorAccessor (&AttributeObjectTest::m_vector1),
-		     MakeObjectVectorChecker<Derived> ())
-      .AddAttribute ("TestVector2", "help text",
-		     ObjectVectorValue (),
-		     MakeObjectVectorAccessor (&AttributeObjectTest::DoGetVectorN,
-						&AttributeObjectTest::DoGetVector),
-		     MakeObjectVectorChecker<Derived> ())
-      .AddAttribute ("IntegerTraceSource1", "help text",
-		     IntegerValue (-2),
-		     MakeIntegerAccessor (&AttributeObjectTest::m_intSrc1),
-		     MakeIntegerChecker<int8_t> ())
-      .AddAttribute ("IntegerTraceSource2", "help text",
-		     IntegerValue (-2),
-		     MakeIntegerAccessor (&AttributeObjectTest::DoSetIntSrc,
-					  &AttributeObjectTest::DoGetIntSrc),
-		     MakeIntegerChecker<int8_t> ())
-      .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<Derived> ())
-      .AddAttribute ("Callback", "help text",
-                     CallbackValue (),
-                     MakeCallbackAccessor (&AttributeObjectTest::m_cbValue),
-                     MakeCallbackChecker ())
-      ;
-        
-    return tid;
-  }
-
-  void AddToVector1 (void) {
-    m_vector1.push_back (CreateObject<Derived> ());
-  }
-  void AddToVector2 (void) {
-    m_vector2.push_back (CreateObject<Derived> ());
-  }
-
-  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<Derived> 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<Ptr<Derived> > m_vector1;
-  std::vector<Ptr<Derived> > m_vector2;
-  Callback<void,int8_t> m_cbValue;
-  TracedValue<int8_t> m_intSrc1;
-  TracedValue<int8_t> m_intSrc2;
-  TracedCallback<double, int, float> m_cb;
-  TracedValue<ValueClassTest> m_valueSrc;
-  Ptr<Derived> m_ptr;
-};
-
-
-#define CHECK_GET_STR(p,name,value)                               \
-  {                                                               \
-    std::string expected = value;                                 \
-    StringValue got;                                              \
-    bool ok = p->GetAttributeFailSafe (name, got);                \
-    NS_TEST_ASSERT (ok);                                          \
-    NS_TEST_ASSERT_EQUAL (got.Get (), expected);                  \
-  }
-#define CHECK_GET_PARAM(p,name,type,value)		\
-  {							\
-    const type expected = value;			\
-    type got;                                           \
-    bool ok = p->GetAttributeFailSafe (name, got);      \
-    NS_TEST_ASSERT (ok);                                \
-    NS_TEST_ASSERT_EQUAL (got.Get (), expected.Get ());	\
-  }
-
-NS_OBJECT_ENSURE_REGISTERED (AttributeObjectTest);
-
-AttributeTest::AttributeTest ()
-  : Test ("Attribute")
-{}
-bool 
-AttributeTest::RunTests (void)
-{
-  bool result = true;
-
-  AttributeList params;
-  Ptr<AttributeObjectTest> p;
-  NS_TEST_ASSERT (params.SetFailSafe ("ns3::AttributeObjectTest::TestBoolName", StringValue ("false")));
-  p = CreateObjectWithAttributes<AttributeObjectTest> (params);
-  CHECK_GET_STR (p, "TestBoolName", "false");
-  CHECK_GET_PARAM (p, "TestBoolName", BooleanValue, false);
-
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestBoolName", StringValue ("true")));
-  CHECK_GET_STR (p, "TestBoolName", "true");
-  CHECK_GET_PARAM (p, "TestBoolName", BooleanValue, true);
-
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestBoolName", BooleanValue (false)));
-  CHECK_GET_STR (p, "TestBoolName", "false");
-  CHECK_GET_PARAM (p, "TestBoolName", BooleanValue, false);
-
-  p = CreateObjectWithAttributes<AttributeObjectTest> ("TestBoolName", StringValue ("true"));
-  CHECK_GET_STR (p, "TestBoolName", "true");
-  CHECK_GET_PARAM (p, "TestBoolName", BooleanValue, true);
-
-  p = CreateObjectWithAttributes<AttributeObjectTest> ("TestBoolName", BooleanValue (true));
-  CHECK_GET_STR (p, "TestBoolName", "true");
-  CHECK_GET_PARAM (p, "TestBoolName", BooleanValue, true);
-
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestBoolA", StringValue ("false")));
-  CHECK_GET_STR (p, "TestBoolA", "false");
-  CHECK_GET_PARAM (p, "TestBoolA", BooleanValue, false);
-
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestBoolA", StringValue ("true")));
-  CHECK_GET_STR (p, "TestBoolA", "true");
-  CHECK_GET_PARAM (p, "TestBoolA", BooleanValue, true);
-
-
-  CHECK_GET_STR (p, "TestInt16", "-2");
-  CHECK_GET_PARAM (p, "TestInt16", IntegerValue, -2);
-
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestInt16", StringValue ("-5")));
-  CHECK_GET_STR (p, "TestInt16", "-5");
-  CHECK_GET_PARAM (p, "TestInt16", IntegerValue, -5);
-
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestInt16", IntegerValue (+2)));
-  CHECK_GET_STR (p, "TestInt16", "2");
-  CHECK_GET_PARAM (p, "TestInt16", IntegerValue, +2);
-
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestInt16", IntegerValue (-32768)));
-  CHECK_GET_STR (p, "TestInt16", "-32768");
-  CHECK_GET_PARAM (p, "TestInt16", IntegerValue, -32768);
-
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe("TestInt16", IntegerValue (-32769)));
-  CHECK_GET_STR (p, "TestInt16", "-32768");
-  CHECK_GET_PARAM (p, "TestInt16", IntegerValue, -32768);
-
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestInt16", IntegerValue (32767)));
-  CHECK_GET_STR (p, "TestInt16", "32767");
-  CHECK_GET_PARAM (p, "TestInt16", IntegerValue, 32767);
-
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe("TestInt16", IntegerValue (32768)));
-  CHECK_GET_STR (p, "TestInt16", "32767");
-  CHECK_GET_PARAM (p, "TestInt16", IntegerValue, 32767);
-
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestInt16WithBounds", IntegerValue (10)));
-  CHECK_GET_STR (p, "TestInt16WithBounds", "10");
-  CHECK_GET_PARAM (p, "TestInt16WithBounds", IntegerValue, 10);
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe("TestInt16WithBounds", IntegerValue (11)));
-  CHECK_GET_STR (p, "TestInt16WithBounds", "10");
-  CHECK_GET_PARAM (p, "TestInt16WithBounds", IntegerValue, 10);
-
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestInt16WithBounds", IntegerValue (-5)));
-  CHECK_GET_STR (p, "TestInt16WithBounds", "-5");
-  CHECK_GET_PARAM (p, "TestInt16WithBounds", IntegerValue, -5);
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe("TestInt16WithBounds", IntegerValue (-6)));
-  CHECK_GET_STR (p, "TestInt16WithBounds", "-5");
-  CHECK_GET_PARAM (p, "TestInt16WithBounds", IntegerValue, -5);
-
-  CHECK_GET_STR (p, "TestInt16SetGet", "6");
-  CHECK_GET_PARAM (p, "TestInt16SetGet", IntegerValue, 6);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestInt16SetGet", IntegerValue (0)));
-  CHECK_GET_STR (p, "TestInt16SetGet", "0");
-  CHECK_GET_PARAM (p, "TestInt16SetGet", IntegerValue, 0);
-
-  CHECK_GET_STR (p, "TestUint8", "1");
-  CHECK_GET_PARAM (p, "TestUint8", UintegerValue, 1);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestUint8", UintegerValue (0)));
-  CHECK_GET_STR (p, "TestUint8", "0");
-  CHECK_GET_PARAM (p, "TestUint8", UintegerValue, 0);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestUint8", UintegerValue (255)));
-  CHECK_GET_STR (p, "TestUint8", "255");
-  CHECK_GET_PARAM (p, "TestUint8", UintegerValue, 255);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestUint8", StringValue ("255")));
-  CHECK_GET_STR (p, "TestUint8", "255");
-  CHECK_GET_PARAM (p, "TestUint8", UintegerValue, 255);
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe("TestUint8", StringValue ("256")));
-  CHECK_GET_STR (p, "TestUint8", "255");
-  CHECK_GET_PARAM (p, "TestUint8", UintegerValue, 255);
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe("TestUint8", StringValue ("-1")));
-  CHECK_GET_STR (p, "TestUint8", "255");
-  CHECK_GET_PARAM (p, "TestUint8", UintegerValue, 255);
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe("TestUint8", UintegerValue ((uint64_t)-1)));
-  CHECK_GET_STR (p, "TestUint8", "255");
-  CHECK_GET_PARAM (p, "TestUint8", UintegerValue, 255);
-
-  CHECK_GET_STR (p, "TestFloat", "-1.1");
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestFloat", DoubleValue ((float)+2.3)));
-  CHECK_GET_PARAM (p, "TestFloat", DoubleValue, (float)+2.3);
-
-  CHECK_GET_STR (p, "TestEnum", "TestA");
-  CHECK_GET_PARAM (p, "TestEnum", EnumValue, AttributeObjectTest::TEST_A);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestEnum", EnumValue (AttributeObjectTest::TEST_C)));
-  CHECK_GET_STR (p, "TestEnum", "TestC");
-  CHECK_GET_PARAM (p, "TestEnum", EnumValue, AttributeObjectTest::TEST_C);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestEnum", StringValue ("TestB")));
-  CHECK_GET_STR (p, "TestEnum", "TestB");
-  CHECK_GET_PARAM (p, "TestEnum", EnumValue, AttributeObjectTest::TEST_B);
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe("TestEnum", StringValue ("TestD")));
-  CHECK_GET_STR (p, "TestEnum", "TestB");
-  CHECK_GET_PARAM (p, "TestEnum", EnumValue, AttributeObjectTest::TEST_B);
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe("TestEnum", EnumValue (5)));
-  CHECK_GET_STR (p, "TestEnum", "TestB");
-  CHECK_GET_PARAM (p, "TestEnum", EnumValue, AttributeObjectTest::TEST_B);
-
-  RandomVariableValue ran;
-  p->GetAttribute ("TestRandom", ran);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestRandom", RandomVariableValue (UniformVariable (0.0, 1.0))));
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("TestRandom", RandomVariableValue (ConstantVariable (10.0))));
-
-  {
-    ObjectVectorValue vector;
-    p->GetAttribute ("TestVector1", vector);
-    NS_TEST_ASSERT_EQUAL (vector.GetN (), 0);
-    p->AddToVector1 ();
-    NS_TEST_ASSERT_EQUAL (vector.GetN (), 0);
-    p->GetAttribute ("TestVector1", vector);
-    NS_TEST_ASSERT_EQUAL (vector.GetN (), 1);
-    Ptr<Object> a = vector.Get (0);
-    NS_TEST_ASSERT_UNEQUAL (a, 0);
-    p->AddToVector1 ();
-    NS_TEST_ASSERT_EQUAL (vector.GetN (), 1);
-    p->GetAttribute ("TestVector1", vector);
-    NS_TEST_ASSERT_EQUAL (vector.GetN (), 2);
-  }
-
-  {
-    ObjectVectorValue vector;
-    p->GetAttribute ("TestVector2", vector);
-    NS_TEST_ASSERT_EQUAL (vector.GetN (), 0);
-    p->AddToVector2 ();
-    NS_TEST_ASSERT_EQUAL (vector.GetN (), 0);
-    p->GetAttribute ("TestVector2", vector);
-    NS_TEST_ASSERT_EQUAL (vector.GetN (), 1);
-    Ptr<Object> a = vector.Get (0);
-    NS_TEST_ASSERT_UNEQUAL (a, 0);
-    p->AddToVector2 ();
-    NS_TEST_ASSERT_EQUAL (vector.GetN (), 1);
-    p->GetAttribute ("TestVector2", vector);
-    NS_TEST_ASSERT_EQUAL (vector.GetN (), 2);
-  }
-
-  NS_TEST_ASSERT (AttributeList::GetGlobal ()->SetFailSafe ("ns3::AttributeObjectTest::TestBoolName", StringValue ("true")));
-  p = CreateObject<AttributeObjectTest> ();
-  BooleanValue boolV;
-  p->GetAttribute ("TestBoolName", boolV);
-  NS_TEST_ASSERT_EQUAL (boolV.Get (), true);
-
-  NS_TEST_ASSERT (AttributeList::GetGlobal ()->SetFailSafe ("ns3::AttributeObjectTest::TestBoolName", StringValue ("false")));
-  p = CreateObject<AttributeObjectTest> ();
-  p->GetAttribute ("TestBoolName", boolV);
-  NS_TEST_ASSERT_EQUAL (boolV.Get (), false);
-
-  IntegerValue i;
-  p->GetAttribute ("IntegerTraceSource1", i);
-  NS_TEST_ASSERT_EQUAL (i.Get (), -2);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (+5)));
-  p->GetAttribute ("IntegerTraceSource1", i);
-  NS_TEST_ASSERT_EQUAL (i.Get (), +5);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (127)));
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (128)));
-  NS_TEST_ASSERT (p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (-128)));
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (-129)));
-
-  p->GetAttribute ("IntegerTraceSource2", i);
-  NS_TEST_ASSERT_EQUAL (i.Get (), -2);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe ("IntegerTraceSource2", IntegerValue (+5)));
-  p->GetAttribute ("IntegerTraceSource2", i);
-  NS_TEST_ASSERT_EQUAL (i.Get (), +5);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe ("IntegerTraceSource2", IntegerValue (127)));
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe ("IntegerTraceSource2", IntegerValue (128)));
-  NS_TEST_ASSERT (p->SetAttributeFailSafe ("IntegerTraceSource2", IntegerValue (-128)));
-  NS_TEST_ASSERT (!p->SetAttributeFailSafe ("IntegerTraceSource2", IntegerValue (-129)));
-
-  m_got1 = -2;
-  NS_TEST_ASSERT (p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (-1)));
-  NS_TEST_ASSERT (p->TraceConnectWithoutContext ("Source1", MakeCallback (&AttributeTest::NotifySource1, this)));
-  NS_TEST_ASSERT (p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (0)));
-  NS_TEST_ASSERT_EQUAL (m_got1, 0);
-  NS_TEST_ASSERT (p->TraceDisconnectWithoutContext ("Source1", MakeCallback (&AttributeTest::NotifySource1, this)));
-  NS_TEST_ASSERT (p->SetAttributeFailSafe ("IntegerTraceSource1", IntegerValue (1)));
-  NS_TEST_ASSERT_EQUAL (m_got1, 0);
-
-  m_got2 = 4.3;
-  p->InvokeCb (1.0, -5, 0.0);
-  NS_TEST_ASSERT_EQUAL (m_got2, 4.3);
-  NS_TEST_ASSERT (p->TraceConnectWithoutContext ("Source2", MakeCallback (&AttributeTest::NotifySource2, this)));
-  NS_TEST_ASSERT_EQUAL (m_got2, 4.3);
-  p->InvokeCb (1.0, -5, 0.0);
-  NS_TEST_ASSERT_EQUAL (m_got2, 1.0);
-  NS_TEST_ASSERT (p->TraceDisconnectWithoutContext ("Source2", MakeCallback (&AttributeTest::NotifySource2, this)));
-  p->InvokeCb (-1.0, -5, 0.0);
-  NS_TEST_ASSERT_EQUAL (m_got2, 1.0);
-
-  NS_TEST_ASSERT (p->TraceConnectWithoutContext ("ValueSource", MakeCallback (&AttributeTest::NotifySourceValue, this)));
-
-  PointerValue ptr;
-  p->GetAttribute ("Pointer", ptr);
-  Ptr<Derived> derived = ptr.Get<Derived> ();
-  NS_TEST_ASSERT (derived == 0);
-  derived = Create<Derived> ();
-  NS_TEST_ASSERT (p->SetAttributeFailSafe("Pointer", PointerValue (derived)));
-  p->GetAttribute ("Pointer", ptr);
-  Ptr<Derived> stored = ptr.Get<Derived> ();
-  NS_TEST_ASSERT (stored == derived);
-  p->GetAttribute ("Pointer", ptr);
-  Ptr<Object> storedBase = ptr.Get<Object> ();
-  NS_TEST_ASSERT (stored == storedBase);
-  p->GetAttribute ("Pointer", ptr);
-  Ptr<AttributeObjectTest> x = ptr.Get<AttributeObjectTest> ();
-  NS_TEST_ASSERT (x == 0);
-
-  p = CreateObjectWithAttributes<AttributeObjectTest> ("Pointer", PointerValue (Create<Derived> ()));
-  NS_TEST_ASSERT (p != 0);
-  derived = 0;
-  p->GetAttribute ("Pointer", ptr);
-  derived = ptr.Get<Derived> ();
-  NS_TEST_ASSERT (derived != 0);
-
-  p = CreateObject<AttributeObjectTest> ();
-  NS_TEST_ASSERT (p != 0);
-  m_gotCbValue = 1;
-  p->InvokeCbValue (2);
-  CallbackValue cbValue = MakeCallback (&AttributeTest::NotifyCallbackValue, this);
-  NS_TEST_ASSERT_EQUAL (m_gotCbValue, 1);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe ("Callback", 
-                                           cbValue));
-  p->InvokeCbValue (2);
-  NS_TEST_ASSERT_EQUAL (m_gotCbValue, 2);
-  NS_TEST_ASSERT (p->SetAttributeFailSafe ("Callback", 
-                                           CallbackValue (MakeNullCallback<void,int8_t> ())));
-  p->InvokeCbValue (3);
-  NS_TEST_ASSERT_EQUAL (m_gotCbValue, 2);
-  
-  return result;
-}
-
-
-
-static AttributeTest g_parameterTest;
-
-} // namespace ns3
-
-
-#endif /* RUN_SELF_TESTS */
--- a/src/core/test.cc	Mon Sep 21 11:21:05 2009 -0700
+++ b/src/core/test.cc	Wed Sep 23 15:20:23 2009 -0700
@@ -22,6 +22,36 @@
 
 namespace ns3 {
 
+
+//
+// XML files have restrictions on certain characters that may be present in
+// data.  We need to replace these characters with their alternate 
+// representation on the way into the XML file.
+//
+std::string
+ReplaceXmlSpecialCharacters (std::string xml)
+{
+  std::string specials = "<>&\"'";
+  std::string replacements[] = {"&lt;", "&gt;", "&amp;", "&#39;", "&quot;"};
+  std::string result;
+  std::size_t index, length = xml.length ();
+
+  for (size_t i = 0; i < length; ++i)
+    {
+      char character = xml[i];
+
+      if ((index = specials.find (character)) == std::string::npos)
+        {
+          result.push_back (character);
+        }
+      else
+        {
+          result += replacements[index];
+        }
+    }
+  return result;
+}
+
 bool
 TestDoubleIsEqual (const double x1, const double x2, const double epsilon)
 {
@@ -180,7 +210,7 @@
       return;
     }
   *m_ofs << "  <TestCase>" << std::endl;
-  *m_ofs << "    <CaseName>" << GetName () << "</CaseName>" << std::endl;
+  *m_ofs << "    <CaseName>" << ReplaceXmlSpecialCharacters (GetName ()) << "</CaseName>" << std::endl;
 }
 
 void
@@ -202,18 +232,20 @@
   std::string file, 
   int32_t line)
 {
+  m_error |= true;
+
   if (m_ofs == 0)
     {
       return;
     }
+
   *m_ofs << "    <CaseResult>FAIL</CaseResult>" << std::endl;
-  *m_ofs << "    <CaseCondition>" << cond << "</CaseCondition>" << std::endl;
-  *m_ofs << "    <CaseActual>" << actual << "</CaseActual>" << std::endl;
-  *m_ofs << "    <CaseLimit>" << limit << "</CaseLimit>" << std::endl;
-  *m_ofs << "    <CaseMessage>" << message << "</CaseMessage>" << std::endl;
-  *m_ofs << "    <CaseFile>" << file << "</CaseFile>" << std::endl;
+  *m_ofs << "    <CaseCondition>" << ReplaceXmlSpecialCharacters (cond) << "</CaseCondition>" << std::endl;
+  *m_ofs << "    <CaseActual>" << ReplaceXmlSpecialCharacters (actual) << "</CaseActual>" << std::endl;
+  *m_ofs << "    <CaseLimit>" << ReplaceXmlSpecialCharacters (limit) << "</CaseLimit>" << std::endl;
+  *m_ofs << "    <CaseMessage>" << ReplaceXmlSpecialCharacters (message) << "</CaseMessage>" << std::endl;
+  *m_ofs << "    <CaseFile>" << ReplaceXmlSpecialCharacters (file) << "</CaseFile>" << std::endl;
   *m_ofs << "    <CaseLine>" << line << "</CaseLine>" << std::endl;
-  m_error |= true;
 }
 
 void
@@ -387,7 +419,7 @@
       return;
     }
   *m_ofs << "<TestSuite>" << std::endl;
-  *m_ofs << "  <SuiteName>" << GetName () << "</SuiteName>" << std::endl;
+  *m_ofs << "  <SuiteName>" << ReplaceXmlSpecialCharacters (GetName ()) << "</SuiteName>" << std::endl;
 }
 
 void
--- a/src/core/test.h	Mon Sep 21 11:21:05 2009 -0700
+++ b/src/core/test.h	Wed Sep 23 15:20:23 2009 -0700
@@ -47,6 +47,12 @@
 #define NS_TEST_SOURCEDIR \
   TestCase::GetSourceDir (__FILE__)
 
+#define NS_TEST_RETURN_IF_ERROR \
+  if (GetErrorStatus ()) \
+    {                    \
+      return true;       \
+    } 
+
 // ===========================================================================
 // Test for equality (generic version)
 // ===========================================================================
@@ -64,7 +70,7 @@
         actualStream << actual;                                                                     \
         std::ostringstream limitStream;                                                             \
         limitStream << limit;                                                                       \
-        ReportFailure (std::string (#actual) + " (actual) EQ " + std::string (#limit) + " (limit)", \
+        ReportFailure (std::string (#actual) + " (actual) == " + std::string (#limit) + " (limit)", \
                        actualStream.str (), limitStream.str (), msgStream.str (), file, line);      \
         return true;                                                                                \
       }                                                                                             \
@@ -115,7 +121,7 @@
         actualStream << actual;                                                                     \
         std::ostringstream limitStream;                                                             \
         limitStream << limit;                                                                       \
-        ReportFailure (std::string (#actual) + " (actual) EQ " + std::string (#limit) + " (limit)", \
+        ReportFailure (std::string (#actual) + " (actual) == " + std::string (#limit) + " (limit)", \
                        actualStream.str (), limitStream.str (), msgStream.str (), file, line);      \
       }                                                                                             \
   } while (false)
@@ -168,8 +174,8 @@
         std::ostringstream limitStream;                                                                           \
         limitStream << limit << " +- " << tol;                                                                    \
         std::ostringstream condStream;                                                                            \
-        condStream << #actual << " (actual) LT " << #limit << " (limit) + " << #tol << " (tol) AND " <<           \
-                      #actual << " (actual) GT " << #limit << " (limit) - " << #tol << " (tol)";                  \
+        condStream << #actual << " (actual) < " << #limit << " (limit) + " << #tol << " (tol) && " <<             \
+                      #actual << " (actual) > " << #limit << " (limit) - " << #tol << " (tol)";                   \
         ReportFailure (condStream.str (), actualStream.str (), limitStream.str (), msgStream.str (), file, line); \
         return true;                                                                                              \
       }                                                                                                           \
@@ -243,8 +249,8 @@
         std::ostringstream limitStream;                                                                           \
         limitStream << limit << " +- " << tol;                                                                    \
         std::ostringstream condStream;                                                                            \
-        condStream << #actual << " (actual) LT " << #limit << " (limit) + " << #tol << " (tol) AND " <<           \
-                      #actual << " (actual) GT " << #limit << " (limit) - " << #tol << " (tol)";                  \
+        condStream << #actual << " (actual) < " << #limit << " (limit) + " << #tol << " (tol) && " <<             \
+                      #actual << " (actual) > " << #limit << " (limit) - " << #tol << " (tol)";                   \
         ReportFailure (condStream.str (), actualStream.str (), limitStream.str (), msgStream.str (), file, line); \
       }                                                                                                           \
   } while (false)
@@ -317,7 +323,7 @@
         actualStream << actual;                                                                     \
         std::ostringstream limitStream;                                                             \
         limitStream << limit;                                                                       \
-        ReportFailure (std::string (#actual) + " (actual) NE " + std::string (#limit) + " (limit)", \
+        ReportFailure (std::string (#actual) + " (actual) != " + std::string (#limit) + " (limit)", \
                        actualStream.str (), limitStream.str (), msgStream.str (), file, line);      \
         return true;                                                                                \
       }                                                                                             \
@@ -367,7 +373,7 @@
         actualStream << actual;                                                                     \
         std::ostringstream limitStream;                                                             \
         limitStream << limit;                                                                       \
-        ReportFailure (std::string (#actual) + " (actual) NE " + std::string (#limit) + " (limit)", \
+        ReportFailure (std::string (#actual) + " (actual) != " + std::string (#limit) + " (limit)", \
                        actualStream.str (), limitStream.str (), msgStream.str (), file, line);      \
       }                                                                                             \
   } while (false)
@@ -417,7 +423,7 @@
         actualStream << actual;                                                                      \
         std::ostringstream limitStream;                                                              \
         limitStream << limit;                                                                        \
-        ReportFailure (std::string (#actual) + " (actual) LT " + std::string (#limit) + " (limit)",  \
+        ReportFailure (std::string (#actual) + " (actual) < " + std::string (#limit) + " (limit)",   \
                        actualStream.str (), limitStream.str (), msgStream.str (), file, line);       \
         return true;                                                                                 \
       }                                                                                              \
@@ -457,7 +463,7 @@
         actualStream << actual;                                                                      \
         std::ostringstream limitStream;                                                              \
         limitStream << limit;                                                                        \
-        ReportFailure (std::string (#actual) + " (actual) LT " + std::string (#limit) + " (limit)",  \
+        ReportFailure (std::string (#actual) + " (actual) < " + std::string (#limit) + " (limit)",   \
                        actualStream.str (), limitStream.str (), msgStream.str (), file, line);       \
       }                                                                                              \
   } while (false)
@@ -496,7 +502,7 @@
         actualStream << actual;                                                                      \
         std::ostringstream limitStream;                                                              \
         limitStream << limit;                                                                        \
-        ReportFailure (std::string (#actual) + " (actual) GT " + std::string (#limit) + " (limit)",  \
+        ReportFailure (std::string (#actual) + " (actual) > " + std::string (#limit) + " (limit)",   \
                        actualStream.str (), limitStream.str (), msgStream.str (), file, line);       \
         return true;                                                                                 \
       }                                                                                              \
@@ -536,7 +542,7 @@
         actualStream << actual;                                                                      \
         std::ostringstream limitStream;                                                              \
         limitStream << limit;                                                                        \
-        ReportFailure (std::string (#actual) + " (actual) GT " + std::string (#limit) + " (limit)",  \
+        ReportFailure (std::string (#actual) + " (actual) > " + std::string (#limit) + " (limit)",   \
                        actualStream.str (), limitStream.str (), msgStream.str (), file, line);       \
       }                                                                                              \
   } while (false)
--- a/src/core/wscript	Mon Sep 21 11:21:05 2009 -0700
+++ b/src/core/wscript	Wed Sep 23 15:20:23 2009 -0700
@@ -70,7 +70,6 @@
         'string.cc',
         'pointer.cc',
         'object-vector.cc',
-        'attribute-test.cc',
         'object-factory.cc',
         'global-value.cc',
         'traced-callback.cc',
@@ -80,6 +79,7 @@
         'names.cc',
         'vector.cc',
         'names-test-suite.cc',
+        'attribute-test-suite.cc',
         ]
 
     headers = bld.new_task_gen('ns3header')
--- a/test.py	Mon Sep 21 11:21:05 2009 -0700
+++ b/test.py	Wed Sep 23 15:20:23 2009 -0700
@@ -27,6 +27,7 @@
 import signal
 import random
 import xml.dom.minidom
+import shutil
 
 #
 # XXX This should really be part of a waf command to list the configuration
@@ -805,8 +806,9 @@
             else:
                 f = open(xml_results_file, 'a')
                 f.write("<TestSuite>\n")
-                f.write("  <Name>%s</Name>\n" % job.display_name)
-                f.write('  <Result>CRASH</Result>\n')
+                f.write("  <SuiteName>%s</SuiteName>\n" % job.display_name)
+                f.write('  <SuiteResult>CRASH</SuiteResult>\n')
+                f.write('  <SuiteTime>Execution times not available</SuiteTime>\n')
                 f.write("</TestSuite>\n")
                 f.close()
 
@@ -832,7 +834,7 @@
 
     #
     # The last things to do are to translate the XML results file to "human
-    # readable form" if the user asked for it
+    # readable form" if the user asked for it (or make an XML file somewhere)
     #
     if len(options.html):
         translate_to_html(xml_results_file, options.html)
@@ -840,6 +842,9 @@
     if len(options.text):
         translate_to_text(xml_results_file, options.text)
 
+    if len(options.xml):
+        shutil.copyfile(xml_results_file, options.xml)
+
 def main(argv):
     random.seed()
 
@@ -876,6 +881,10 @@
                       metavar="TEXT-FILE",
                       help="write detailed test results into TEXT-FILE.txt")
 
+    parser.add_option("-x", "--xml", action="store", type="string", dest="xml", default="",
+                      metavar="XML-FILE",
+                      help="write detailed test results into XML-FILE.xml")
+
     global options
     options = parser.parse_args()[0]
     signal.signal(signal.SIGINT, sigint_hook)