views:

44

answers:

2

I'm currently practising the Test-Driven Development style of programming as well as trying to memorize some useful idioms and exception safety rules I've learned. I've used an old programming assignment from semester one to simply go nuts, use stuff where it shouldn't be used to get a feel for them, learn their respective pros and cons. You know, practising.

I've been coding with the Boost_Unit_Test framework, and it's been going good so far(only testing framework I've tried). Except here in this test:

BOOST_AUTO_TEST_CASE(CopyConstructor)
{
    Field *field = Field::EmptyField();
    PushValsToField(&field, 5);
    Field *field2 = new Field(*field);

    BOOST_REQUIRE_EQUAL(field->Size(), field2->Size());
    BOOST_REQUIRE_EQUAL((*field)[0], (*field2)[0]);
    BOOST_REQUIRE_EQUAL((*field)[1], (*field2)[1]);
    BOOST_REQUIRE_EQUAL((*field)[2], (*field2)[2]);
    BOOST_REQUIRE_EQUAL((*field)[3], (*field2)[3]);
    BOOST_REQUIRE_EQUAL((*field)[4], (*field2)[4]);
    // Error with BOOST_EQUAL_REQUIRE_COLLECTIONS
    BOOST_REQUIRE_EQUAL_COLLECTIONS(&(*field)[0], &(*field)[5],
                                    &(*field2)[0], &(*field)[5]);
    delete field;
    delete field2;
}

I'm not sure why, but the collections test fails on the last compare ([5]). However, the other tests pass. Why is the last test failing?

Also, any style guides or pointers would be greatly appreciated, but not in the scope of the question.

Error:

fatal error in "CopyConstructor": 

critical check { &(*field)[0], &(*field)[5] } == { &(*field2)[0], &(*field)[5] } failed. 

Collections size mismatch: 5 != 1073731817

Useful Information and Code Snippets

void PushValsToField(Field **field, int numPushes)
{
    for (int i(1); i <= numPushes; ++i)
        (*field)->Push_Back(i*10);
}

Constructors

Field *Field::EmptyField()
{
    return new Field();
}

Field::Field()
    : v_(new ElemType[10000]), vused_(0), vsize_(10000)
{}

Field::Field(const Field& other)
    : v_(h::NewCopy(other.v_, 
                    other.vsize_, 
                    other.vsize_)), 
      vused_(other.vused_), 
      vsize_(other.vsize_)
{}    

// Also available as a const& version
int& Field::operator[](int index) throw(const char *)
{
    if (index < 0 || index > vused_)
        throw "Index out of bounds.";
    else
        return v_[index];
}

Copy function

template <class T>
T *NewCopy( const T* src,
            size_t srcSize,
            size_t destSize)
{
    assert( destSize >= srcSize );

    T *dest = new T[destSize];
    try
    {
        std::copy(src, (src + srcSize), dest);
    }
    catch(...)
    {
        delete[] dest;
        throw;
    }

    return dest;
}
+2  A: 

If your size is 5, aren't your valid indices 0-4? 5 would be out of range. I think you have an error in your operator[] bounds check:

if (index < 0 || index > vused_)

... should be ...

if (index < 0 || index >= vused_)
Fred Larson
@Fred: Yup, my mistake. However, the Collections works with iterator ranges, so the [5] is to denote the end anyway. It needs to stay there as one past the range of appropriate values (if I understand the collections check correctly). I will erase the dangerous [5] check, thanks!
SoulBeaver
+2  A: 
BOOST_REQUIRE_EQUAL((*field)[0], (*field2)[0]); // one
BOOST_REQUIRE_EQUAL((*field)[1], (*field2)[1]); // two
BOOST_REQUIRE_EQUAL((*field)[2], (*field2)[2]); // three
BOOST_REQUIRE_EQUAL((*field)[3], (*field2)[3]); // four
BOOST_REQUIRE_EQUAL((*field)[4], (*field2)[4]); // five
BOOST_REQUIRE_EQUAL((*field)[5], (*field2)[5]); // wait, six?

Count the number of elements you are checking, zero through five... It gives you six. But your collection is supposed to have five elements.

Alex Emelianov
@Alex: Yes, it's been pointed out by Fred ^^ I've already fixed it, but, as I mentioned in his comment, the collections should work with an iterator range that points to the one element past the range of values to be checked.
SoulBeaver
Dereferencing that iterator is an error, though.
Alex Emelianov