Commits

Lenard Lindstrom committed 8c675d3

Fill in unit tests on memory.hpp/memory.cpp

The ClassReference class template replicates some of the Reference class code,
so needs separate testing. Also bidirectional conversions between Reference
and ClassReference instances need checking.

  • Participants
  • Parent commits 22106a2
  • Branches Reference

Comments (0)

Files changed (1)

test/testmemory.cpp

 }
 
 
+// Since the ClassReference class template duplicates much of the reference
+// counting machinery of the Reference class, test functions perform the
+// same tests on both.
+
+// The dynamically allocated object is destroyed and its memory freed with
+// operator delete when the object's reference count reaches zero.
 struct Managed : public Datum {
     Managed() : Datum() { ++alive_count; }
     ~Managed() { --alive_count; }
     a = Reference();
     assert(Managed::alive_count == 0);
 
-    // Test copy constructor.
-    Reference b = ManagedRef(new Managed);
+    ManagedRef b;
+    assert(Managed::alive_count == 0);
+    b = ManagedRef(new Managed);
+    assert(Managed::alive_count == 1);
+    b = b;
     assert(Managed::alive_count == 1);
     b = Reference();
     assert(Managed::alive_count == 0);
 
-    // Test Reference destructor.
+    // Test copy constructor.
+    Reference c(new Managed);
+    assert(Managed::alive_count == 1);
+    c = Reference();
+    assert(Managed::alive_count == 0);
+
+    ManagedRef d(new Managed);
+    assert(Managed::alive_count == 1);
+    d = Reference();
+    assert(Managed::alive_count == 0);
+
+    // Test automatic storage duration.
     {
-        ManagedRef d(new Managed);
+        Reference e(new Managed);
         assert(Managed::alive_count == 1);
-        ManagedRef e(new Managed);
+        Reference f(new Managed);
         assert(Managed::alive_count == 2);
-        a = e;
+        a = f;
+
+        ManagedRef g(new Managed);
+        assert(Managed::alive_count == 3);
+        ManagedRef h(new Managed);
+        assert(Managed::alive_count == 4);
+        b = h;
     }
+    assert(Managed::alive_count == 2);
+    a = Reference();
     assert(Managed::alive_count == 1);
-    a = Reference();
+    b = Reference();
     assert(Managed::alive_count == 0);
 }
 
 
+// The constructor, assignment operation, and destructor of a reference all
+// manipulate reference counts.
 void
 test_ref_count()
 {
     Reference a(new Datum);
     assert(a->get_ref_count() == 1);
 
+    ClassReference<Datum> b(new Datum);
+    assert(b->get_ref_count() == 1);
+
     // Self assignment does not alter the reference count.
     a = a;
     assert(a->get_ref_count() == 1);
 
-    // Reference b refers to a's datum.
-    Reference b(a);
-    assert(b->get_ref_count() == 2);
+    b = b;
+    assert(b->get_ref_count() == 1);
+
+    // The copy constructor increments the reference count.
+    Reference c(a);
+    assert(c->get_ref_count() == 2);
     assert(a->get_ref_count() == 2);
 
-    // Now only b refers the the datum created by Reference a(new Datum).
+    ClassReference<Datum> d(b);
+    assert(d->get_ref_count() == 2);
+    assert(b->get_ref_count() == 2);
+
+    // Setting a reference to NULL decrements the reference count.
     a = Reference();
-    assert(b->get_ref_count() == 1);
+    assert(c->get_ref_count() == 1);
+
+    b = Reference();
+    assert(d->get_ref_count() == 1);
 }
 
 
+// The ! operator returns true if a reference is NULL. A reference is NULL
+// when constructed with the default constructor, constructed from a NULL
+// pointer, constructed from another NULL reference, or assigned a NULL
+// reference value.
 void
 test_null_check()
 {
     assert(!Reference());
-    Reference b;
-    assert(!b);
-    Reference t(new Datum);
-    assert(!!t);
-    b = t;
+    assert(!Reference(0));
+    Reference a;
+    assert(!a);
+    assert(!Reference(a));
+    Reference b(new Datum);
     assert(!!b);
-    b = Reference();
-    assert(!b);
+    a = b;
+    assert(!!a);
+    a = Reference();
+    assert(!a);
+
+    assert(!ClassReference<Datum>());
+    assert(!ClassReference<Datum>(0));
+    ClassReference<Datum> c;
+    assert(!c);
+    assert(!ClassReference<Datum>(c));
+    Reference d(new Datum);
+    assert(!!d);
+    c = d;
+    assert(!!c);
+    c = Reference();
+    assert(!c);
+
+    // Mixing References with ClassReferences.
+    assert(!Reference(ClassReference<Datum>()));
+    assert(!ClassReference<Datum>(Reference()));
+    a = ClassReference<Datum>();
+    assert(!a);
+    c = Reference();
+    assert(!c);
+    a = d;
+    assert(!!a);
+    c = b;
+    assert(!!c);
 }
 
 
+// Other unit tests use the output of referenced objects to verify assertions.
 class WriteSomething : public Datum {
     void write(ostream &os) const;
 };
 test_ostream()
 {
     stringstream capture;
-    Reference r;
-    Reference ws(new WriteSomething);
 
-    // Non reference.
-    capture << r;
+    // NULL reference.
+    capture << Reference();
+    assert(capture.str() == "Reference()");
+
+    capture.str("");
+    capture << ClassReference<Datum>();
+    assert(capture.str() == "Reference()");
+
+    capture.str("");
+    capture << ClassReference<WriteSomething>();
     assert(capture.str() == "Reference()");
 
     // Class Datum default.
     capture << Reference(new Datum);
     assert(capture.str() == "<Empty>");
 
+    capture.str("");
+    capture << ClassReference<Datum>(new Datum);
+    assert(capture.str() == "<Empty>");
+
     // The Datum write method is virtual.
     capture.str("");
-    capture << ws;
+    capture << Reference(new WriteSomething);
+    assert(capture.str() == "<Something>");
+
+    capture.str("");
+    capture << ClassReference<Datum>(new WriteSomething);
+    assert(capture.str() == "<Something>");
+
+    capture.str("");
+    capture << ClassReference<WriteSomething>(new WriteSomething);
     assert(capture.str() == "<Something>");
 }