wxWidgets/tests/vectors/vectors.cpp
Vadim Zeitlin f7d9098f1f Fix building wxVector unit tests in STL build without C++11
There is no shrink_to_fit() in wxVector in this case.

Arguably, we shouldn't be building wxVector unit tests in STL build at
all as there is no point in testing the standard class, but OTOH it
could be useful for checking that the tests themselves are correct, so
keep them for now.
2017-11-21 14:44:06 +01:00

393 lines
9.7 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: tests/vectors/vectors.cpp
// Purpose: wxVector<T> unit test
// Author: Vaclav Slavik
// Created: 2007-07-07
// Copyright: (c) 2007 Vaclav Slavik
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif // WX_PRECOMP
#include "wx/vector.h"
// ----------------------------------------------------------------------------
// simple class capable of detecting leaks of its objects
// ----------------------------------------------------------------------------
class CountedObject
{
public:
CountedObject(int n = 0) : m_n(n) { ms_count++; }
CountedObject(const CountedObject& co) : m_n(co.m_n) { ms_count++; }
~CountedObject() { ms_count--; }
int GetValue() const { return m_n; }
static int GetCount() { return ms_count; }
private:
static int ms_count;
int m_n;
};
int CountedObject::ms_count = 0;
// ----------------------------------------------------------------------------
// simple class capable of checking its "this" pointer validity
// ----------------------------------------------------------------------------
class SelfPointingObject
{
public:
SelfPointingObject() { m_self = this; }
SelfPointingObject(const SelfPointingObject&) { m_self = this; }
~SelfPointingObject() { CPPUNIT_ASSERT( this == m_self ); }
// the assignment operator should not modify our "this" pointer so
// implement it just to prevent the default version from doing it
SelfPointingObject& operator=(const SelfPointingObject&) { return *this; }
private:
SelfPointingObject *m_self;
};
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
class VectorsTestCase : public CppUnit::TestCase
{
public:
VectorsTestCase() {}
private:
CPPUNIT_TEST_SUITE( VectorsTestCase );
CPPUNIT_TEST( PushPopTest );
CPPUNIT_TEST( Insert );
CPPUNIT_TEST( Erase );
CPPUNIT_TEST( Iterators );
CPPUNIT_TEST( Objects );
CPPUNIT_TEST( NonPODs );
CPPUNIT_TEST( Resize );
CPPUNIT_TEST( Swap );
CPPUNIT_TEST( Sort );
CPPUNIT_TEST_SUITE_END();
void PushPopTest();
void Insert();
void Erase();
void Iterators();
void Objects();
void NonPODs();
void Resize();
void Swap();
void Sort();
wxDECLARE_NO_COPY_CLASS(VectorsTestCase);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( VectorsTestCase );
// also include in its own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( VectorsTestCase, "VectorsTestCase" );
void VectorsTestCase::PushPopTest()
{
wxVector<int> v;
CPPUNIT_ASSERT( v.size() == 0 );
v.push_back(1);
CPPUNIT_ASSERT( v.size() == 1 );
v.push_back(2);
CPPUNIT_ASSERT( v.size() == 2 );
v.push_back(42);
CPPUNIT_ASSERT( v.size() == 3 );
CPPUNIT_ASSERT( v[0] == 1 );
CPPUNIT_ASSERT( v[1] == 2 );
CPPUNIT_ASSERT( v[2] == 42 );
v.pop_back();
CPPUNIT_ASSERT( v.size() == 2 );
CPPUNIT_ASSERT( v[0] == 1 );
CPPUNIT_ASSERT( v[1] == 2 );
v.pop_back();
CPPUNIT_ASSERT( v.size() == 1 );
CPPUNIT_ASSERT( v[0] == 1 );
v.pop_back();
CPPUNIT_ASSERT( v.size() == 0 );
CPPUNIT_ASSERT( v.empty() );
wxVector<char> vEmpty;
}
void VectorsTestCase::Insert()
{
wxVector<char> v;
v.insert(v.end(), 'a');
CPPUNIT_ASSERT( v.size() == 1 );
CPPUNIT_ASSERT( v[0] == 'a' );
v.insert(v.end(), 'b');
CPPUNIT_ASSERT( v.size() == 2 );
CPPUNIT_ASSERT( v[0] == 'a' );
CPPUNIT_ASSERT( v[1] == 'b' );
v.insert(v.begin(), '0');
CPPUNIT_ASSERT( v.size() == 3 );
CPPUNIT_ASSERT( v[0] == '0' );
CPPUNIT_ASSERT( v[1] == 'a' );
CPPUNIT_ASSERT( v[2] == 'b' );
v.insert(v.begin() + 2, 'X');
CPPUNIT_ASSERT( v.size() == 4 );
CPPUNIT_ASSERT( v[0] == '0' );
CPPUNIT_ASSERT( v[1] == 'a' );
CPPUNIT_ASSERT( v[2] == 'X' );
CPPUNIT_ASSERT( v[3] == 'b' );
v.insert(v.begin() + 3, 3, 'Z');
REQUIRE( v.size() == 7 );
CHECK( v[0] == '0' );
CHECK( v[1] == 'a' );
CHECK( v[2] == 'X' );
CHECK( v[3] == 'Z' );
CHECK( v[4] == 'Z' );
CHECK( v[5] == 'Z' );
CHECK( v[6] == 'b' );
}
void VectorsTestCase::Erase()
{
wxVector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
CPPUNIT_ASSERT( v.size() == 4 );
v.erase(v.begin(), v.end()-1);
CPPUNIT_ASSERT( v.size() == 1 );
CPPUNIT_ASSERT( v[0] == 4 );
v.clear();
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
CPPUNIT_ASSERT( v.size() == 4 );
v.erase(v.begin());
CPPUNIT_ASSERT( v.size() == 3 );
CPPUNIT_ASSERT( v[0] == 2 );
CPPUNIT_ASSERT( v[1] == 3 );
CPPUNIT_ASSERT( v[2] == 4 );
}
void VectorsTestCase::Iterators()
{
wxVector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
int value = 1;
for ( wxVector<int>::iterator i = v.begin(); i != v.end(); ++i, ++value )
{
CPPUNIT_ASSERT_EQUAL( value, *i );
}
}
void VectorsTestCase::Objects()
{
wxVector<CountedObject> v;
v.push_back(CountedObject(1));
v.push_back(CountedObject(2));
v.push_back(CountedObject(3));
v.erase(v.begin());
CPPUNIT_ASSERT_EQUAL( 2, v.size() );
CPPUNIT_ASSERT_EQUAL( 2, CountedObject::GetCount() );
v.clear();
CPPUNIT_ASSERT_EQUAL( 0, CountedObject::GetCount() );
}
void VectorsTestCase::NonPODs()
{
wxVector<SelfPointingObject> v;
v.push_back(SelfPointingObject());
v.push_back(SelfPointingObject());
v.push_back(SelfPointingObject());
v.erase(v.begin());
v.clear();
// try the same with wxString, which is not POD, but is implemented in
// a movable way (this won't assert, but would crash or show some memory
// problems under Valgrind if wxString couldn't be safely moved with
// memmove()):
wxVector<wxString> vs;
vs.push_back("one");
vs.push_back("two");
vs.push_back("three");
vs.erase(vs.begin());
vs.clear();
}
void VectorsTestCase::Resize()
{
wxVector<CountedObject> v;
v.resize(3);
CPPUNIT_ASSERT_EQUAL( 3, v.size() );
CPPUNIT_ASSERT_EQUAL( 3, CountedObject::GetCount() );
CPPUNIT_ASSERT_EQUAL( 0, v[0].GetValue() );
CPPUNIT_ASSERT_EQUAL( 0, v[1].GetValue() );
CPPUNIT_ASSERT_EQUAL( 0, v[2].GetValue() );
v.resize(1);
CPPUNIT_ASSERT_EQUAL( 1, v.size() );
CPPUNIT_ASSERT_EQUAL( 1, CountedObject::GetCount() );
v.resize(4, CountedObject(17));
CPPUNIT_ASSERT_EQUAL( 4, v.size() );
CPPUNIT_ASSERT_EQUAL( 4, CountedObject::GetCount() );
CPPUNIT_ASSERT_EQUAL( 0, v[0].GetValue() );
CPPUNIT_ASSERT_EQUAL( 17, v[1].GetValue() );
CPPUNIT_ASSERT_EQUAL( 17, v[2].GetValue() );
CPPUNIT_ASSERT_EQUAL( 17, v[3].GetValue() );
}
void VectorsTestCase::Swap()
{
wxVector<int> v1, v2;
v1.push_back(17);
v1.swap(v2);
CPPUNIT_ASSERT( v1.empty() );
CPPUNIT_ASSERT_EQUAL( 1, v2.size() );
CPPUNIT_ASSERT_EQUAL( 17, v2[0] );
v1.push_back(9);
v2.swap(v1);
CPPUNIT_ASSERT_EQUAL( 1, v1.size() );
CPPUNIT_ASSERT_EQUAL( 17, v1[0] );
CPPUNIT_ASSERT_EQUAL( 1, v2.size() );
CPPUNIT_ASSERT_EQUAL( 9, v2[0] );
v2.clear();
v1.swap(v2);
CPPUNIT_ASSERT( v1.empty() );
}
void VectorsTestCase::Sort()
{
size_t idx;
wxVector<int> v;
v.push_back(5);
v.push_back(7);
v.push_back(2);
v.push_back(9);
v.push_back(4);
v.push_back(1);
v.push_back(3);
v.push_back(8);
v.push_back(0);
v.push_back(6);
wxVectorSort(v);
for (idx=1; idx<v.size(); idx++)
{
CPPUNIT_ASSERT( v[idx-1] <= v[idx] );
}
}
TEST_CASE("wxVector::operator==", "[vector][compare]")
{
wxVector<wxString> v1, v2;
CHECK( v1 == v2 );
CHECK( !(v1 != v2) );
v1.push_back("foo");
CHECK( v1 != v2 );
v2.push_back("foo");
CHECK( v1 == v2 );
v1.push_back("bar");
v2.push_back("baz");
CHECK( v1 != v2 );
}
TEST_CASE("wxVector::reverse_iterator", "[vector][reverse_iterator]")
{
wxVector<int> v;
for ( int i = 0; i < 10; ++i )
v.push_back(i + 1);
const wxVector<int>::reverse_iterator rb = v.rbegin();
const wxVector<int>::reverse_iterator re = v.rend();
CHECK( re - rb == 10 );
wxVector<int>::reverse_iterator ri = rb;
++ri;
CHECK( ri - rb == 1 );
CHECK( re - ri == 9 );
ri = rb + 2;
CHECK( ri - rb == 2 );
CHECK( re - ri == 8 );
}
TEST_CASE("wxVector::capacity", "[vector][capacity][shrink_to_fit]")
{
wxVector<int> v;
CHECK( v.capacity() == 0 );
v.push_back(0);
// When using the standard library vector, we don't know what growth
// strategy it uses, so we can't rely on the stricter check passing, but
// with our own one we can, allowing us to check that shrink_to_fit()
// really shrinks the capacity below.
#if !wxUSE_STD_CONTAINERS
CHECK( v.capacity() > 1 );
#else
CHECK( v.capacity() >= 1 );
#endif
// There is no shrink_to_fit() in STL build when not using C++11.
#if !wxUSE_STD_CONTAINERS || __cplusplus >= 201103L || wxCHECK_VISUALC_VERSION(10)
v.shrink_to_fit();
CHECK( v.capacity() == 1 );
v.erase(v.begin());
CHECK( v.capacity() == 1 );
v.shrink_to_fit();
CHECK( v.capacity() == 0 );
#endif
}