//Has to be first for StackAllocator swap overload to be taken
//into account (at least using GCC 4.0.1)
#include "stack_allocator.h"
#include <list>
#include <algorithm>
#include <functional>
#include "cppunit/cppunit_proxy.h"
#if !defined (STLPORT) || defined(_STLP_USE_NAMESPACES)
using namespace std;
#endif
//
// TestCase class
//
class ListTest : public CPPUNIT_NS::TestCase
{
CPPUNIT_TEST_SUITE(ListTest);
CPPUNIT_TEST(list1);
CPPUNIT_TEST(list2);
CPPUNIT_TEST(list3);
CPPUNIT_TEST(list4);
CPPUNIT_TEST(erase);
CPPUNIT_TEST(resize);
CPPUNIT_TEST(push_back);
CPPUNIT_TEST(push_front);
CPPUNIT_TEST(allocator_with_state);
CPPUNIT_TEST(swap);
CPPUNIT_TEST(adl);
//CPPUNIT_TEST(const_list);
CPPUNIT_TEST_SUITE_END();
protected:
void list1();
void list2();
void list3();
void list4();
void erase();
void resize();
void push_back();
void push_front();
void allocator_with_state();
void swap();
void adl();
//void const_list();
};
CPPUNIT_TEST_SUITE_REGISTRATION(ListTest);
//
// tests implementation
//
void ListTest::list1()
{
int array1 [] = { 9, 16, 36 };
int array2 [] = { 1, 4 };
list<int> l1(array1, array1 + 3);
list<int> l2(array2, array2 + 2);
list<int>::iterator i1 = l1.begin();
list<int>::iterator i2 = l2.begin();
list<int>::const_iterator ci(i1);
list<int>::const_iterator ci1(ci);
l1.splice(i1, l2);
i1 = l1.begin();
CPPUNIT_ASSERT( *i1++ == 1 );
CPPUNIT_ASSERT( *i1++ == 4 );
CPPUNIT_ASSERT( *i1++ == 9 );
CPPUNIT_ASSERT( *i1++ == 16 );
CPPUNIT_ASSERT( *i1++ == 36 );
#if defined (STLPORT) && \
(!defined (_STLP_DEBUG) || (_STLP_DEBUG_LEVEL != _STLP_STANDARD_DBG_LEVEL))
CPPUNIT_ASSERT( i2 == l1.begin() );
#endif
//Default construct check (_STLP_DEF_CONST_PLCT_NEW_BUG)
list<int> l(2);
i1 = l.begin();
CPPUNIT_ASSERT( *(i1++) == 0 );
CPPUNIT_ASSERT( *i1 == 0 );
#if 0
//A small compilation time check to be activated from time to time,
//compilation should fail.
{
list<char>::iterator l_char_ite;
list<int>::iterator l_int_ite;
CPPUNIT_ASSERT( l_char_ite != l_int_ite );
}
#endif
}
void ListTest::list2()
{
int array1 [] = { 1, 16 };
int array2 [] = { 4, 9 };
list<int> l1(array1, array1 + 2);
list<int> l2(array2, array2 + 2);
list<int>::iterator i = l1.begin();
i++;
l1.splice(i, l2, l2.begin(), l2.end());
i = l1.begin();
CPPUNIT_ASSERT(*i++==1);
CPPUNIT_ASSERT(*i++==4);
CPPUNIT_ASSERT(*i++==9);
CPPUNIT_ASSERT(*i++==16);
}
void ListTest::list3()
{
char array [] = { 'x', 'l', 'x', 't', 's', 's' };
list<char> str(array, array + 6);
list<char>::iterator i;
str.reverse();
i = str.begin();
CPPUNIT_ASSERT(*i++=='s');
CPPUNIT_ASSERT(*i++=='s');
CPPUNIT_ASSERT(*i++=='t');
CPPUNIT_ASSERT(*i++=='x');
CPPUNIT_ASSERT(*i++=='l');
CPPUNIT_ASSERT(*i++=='x');
str.remove('x');
i = str.begin();
CPPUNIT_ASSERT(*i++=='s');
CPPUNIT_ASSERT(*i++=='s');
CPPUNIT_ASSERT(*i++=='t');
CPPUNIT_ASSERT(*i++=='l');
str.unique();
i = str.begin();
CPPUNIT_ASSERT(*i++=='s');
CPPUNIT_ASSERT(*i++=='t');
CPPUNIT_ASSERT(*i++=='l');
str.sort();
i = str.begin();
CPPUNIT_ASSERT(*i++=='l');
CPPUNIT_ASSERT(*i++=='s');
CPPUNIT_ASSERT(*i++=='t');
}
void ListTest::list4()
{
int array1 [] = { 1, 3, 6, 7 };
int array2 [] = { 2, 4 };
list<int> l1(array1, array1 + 4);
list<int> l2(array2, array2 + 2);
l1.merge(l2);
list<int>::iterator i = l1.begin();
CPPUNIT_ASSERT(*i++==1);
CPPUNIT_ASSERT(*i++==2);
CPPUNIT_ASSERT(*i++==3);
CPPUNIT_ASSERT(*i++==4);
CPPUNIT_ASSERT(*i++==6);
CPPUNIT_ASSERT(*i++==7);
//We use distance to avoid a simple call to an internal counter
CPPUNIT_ASSERT(distance(l1.begin(), l1.end()) == 6);
CPPUNIT_ASSERT(distance(l2.begin(), l2.end()) == 0);
l1.swap(l2);
CPPUNIT_ASSERT(distance(l1.begin(), l1.end()) == 0);
CPPUNIT_ASSERT(distance(l2.begin(), l2.end()) == 6);
}
void ListTest::erase()
{
list<int> l;
l.push_back( 1 );
l.erase(l.begin());
CPPUNIT_ASSERT( l.empty() );
int array[] = { 0, 1, 2, 3 };
l.assign(array, array + 4);
list<int>::iterator lit;
lit = l.erase(l.begin());
CPPUNIT_ASSERT( *lit == 1 );
lit = l.erase(l.begin(), --l.end());
CPPUNIT_ASSERT( *lit == 3 );
l.clear();
CPPUNIT_ASSERT( l.empty() );
}
void ListTest::resize()
{
{
list<int> l;
l.resize(5, 1);
size_t i;
list<int>::iterator lit(l.begin());
for (i = 0; i < 5; ++i) {
CPPUNIT_ASSERT( lit != l.end() );
CPPUNIT_ASSERT( *(lit++) == 1 );
}
CPPUNIT_ASSERT( lit == l.end() );
l.resize(3);
lit = l.begin();
for (i = 0; i < 3; ++i) {
CPPUNIT_ASSERT( lit != l.end() );
CPPUNIT_ASSERT( *(lit++) == 1 );
}
CPPUNIT_ASSERT( lit == l.end() );
}
{
list<int> l;
l.resize(5);
size_t i;
list<int>::iterator lit(l.begin());
for (i = 0; i < 5; ++i) {
CPPUNIT_ASSERT( lit != l.end() );
CPPUNIT_ASSERT( *(lit++) == 0 );
}
CPPUNIT_ASSERT( lit == l.end() );
}
}
void ListTest::push_back()
{
list<int> l;
l.push_back( 1 );
l.push_back( 2 );
l.push_back( 3 );
list<int>::reverse_iterator r = l.rbegin();
CPPUNIT_ASSERT( *r == 3 );
l.push_back( 4 );
/*
* Following lines are commented, because ones show standard contradiction
* (24.4.1 and 23.2.2.3); but present behaviour is valid, 24.4.1, paragraphs 1 and 2,
* 24.4.1.3.3 and 23.1 paragraph 9 (Table 66). The 24.4.1 is more common rule,
* so it has preference under 23.2.2.3, by my opinion.
*
* - ptr
*/
// CPPUNIT_ASSERT( *r == 3 );
// ++r;
// CPPUNIT_ASSERT( *r == 2 );
}
void ListTest::push_front()
{
list<int> l;
l.push_back( 1 );
l.push_back( 2 );
l.push_back( 3 );
list<int>::iterator i = l.begin();
CPPUNIT_ASSERT( *i == 1 );
l.push_front( 0 );
CPPUNIT_ASSERT( *i == 1 );
++i;
CPPUNIT_ASSERT( *i == 2 );
}
void ListTest::allocator_with_state()
{
char buf1[1024];
StackAllocator<int> stack1(buf1, buf1 + sizeof(buf1));
char buf2[1024];
StackAllocator<int> stack2(buf2, buf2 + sizeof(buf2));
typedef list<int, StackAllocator<int> > ListInt;
{
//Swap with both list non empty
ListInt lint1(10, 0, stack1);
ListInt lint1Cpy(lint1);
ListInt lint2(10, 1, stack2);
ListInt lint2Cpy(lint2);
lint1.swap(lint2);
CPPUNIT_ASSERT( lint1.get_allocator().swaped() );
CPPUNIT_ASSERT( lint2.get_allocator().swaped() );
CPPUNIT_ASSERT( lint1 == lint2Cpy );
CPPUNIT_ASSERT( lint2 == lint1Cpy );
CPPUNIT_ASSERT( lint1.get_allocator() == stack2 );
CPPUNIT_ASSERT( lint2.get_allocator() == stack1 );
}
CPPUNIT_CHECK( stack1.ok() );
CPPUNIT_CHECK( stack2.ok() );
stack1.reset(); stack2.reset();
{
//Swap with empty calle list
ListInt lint1(10, 0, stack1);
ListInt lint1Cpy(lint1);
ListInt lint2(stack2);
ListInt lint2Cpy(lint2);
lint1.swap(lint2);
CPPUNIT_ASSERT( lint1.get_allocator().swaped() );
CPPUNIT_ASSERT( lint2.get_allocator().swaped() );
CPPUNIT_ASSERT( lint1 == lint2Cpy );
CPPUNIT_ASSERT( lint2 == lint1Cpy );
CPPUNIT_ASSERT( lint1.get_allocator() == stack2 );
CPPUNIT_ASSERT( lint2.get_allocator() == stack1 );
}
CPPUNIT_CHECK( stack1.ok() );
CPPUNIT_CHECK( stack2.ok() );
stack1.reset(); stack2.reset();
{
//Swap with empty caller list
ListInt lint1(stack1);
ListInt lint1Cpy(lint1);
ListInt lint2(10, 0, stack2);
ListInt lint2Cpy(lint2);
lint1.swap(lint2);
CPPUNIT_ASSERT( lint1.get_allocator().swaped() );
CPPUNIT_ASSERT( lint2.get_allocator().swaped() );
CPPUNIT_ASSERT( lint1 == lint2Cpy );
CPPUNIT_ASSERT( lint2 == lint1Cpy );
CPPUNIT_ASSERT( lint1.get_allocator() == stack2 );
CPPUNIT_ASSERT( lint2.get_allocator() == stack1 );
}
CPPUNIT_CHECK( stack1.ok() );
CPPUNIT_CHECK( stack2.ok() );
stack1.reset(); stack2.reset();
{
ListInt lint1(10, 0, stack1);
ListInt lint2(10, 1, stack2);
lint1.splice(lint1.begin(), lint2);
CPPUNIT_ASSERT( lint1.size() == 20 );
CPPUNIT_ASSERT( lint2.empty() );
}
CPPUNIT_CHECK( stack1.ok() );
CPPUNIT_CHECK( stack2.ok() );
stack1.reset(); stack2.reset();
{
ListInt lint1(10, 0, stack1);
ListInt lint2(10, 1, stack2);
lint1.splice(lint1.begin(), lint2, lint2.begin());
CPPUNIT_ASSERT( lint1.size() == 11 );
CPPUNIT_ASSERT( lint2.size() == 9 );
}
CPPUNIT_CHECK( stack1.ok() );
CPPUNIT_CHECK( stack2.ok() );
stack1.reset(); stack2.reset();
{
ListInt lint1(10, 0, stack1);
ListInt lint2(10, 1, stack2);
ListInt::iterator lit(lint2.begin());
advance(lit, 5);
lint1.splice(lint1.begin(), lint2, lint2.begin(), lit);
CPPUNIT_ASSERT( lint1.size() == 15 );
CPPUNIT_ASSERT( lint2.size() == 5 );
}
CPPUNIT_CHECK( stack1.ok() );
CPPUNIT_CHECK( stack2.ok() );
stack1.reset(); stack2.reset();
{
ListInt lint1(10, 0, stack1);
ListInt lint2(10, 1, stack2);
ListInt lintref(stack2);
lintref.insert(lintref.begin(), 10, 1);
lintref.insert(lintref.begin(), 10, 0);
lint1.merge(lint2);
CPPUNIT_ASSERT( lint1.size() == 20 );
CPPUNIT_ASSERT( lint1 == lintref );
CPPUNIT_ASSERT( lint2.empty() );
}
CPPUNIT_CHECK( stack1.ok() );
CPPUNIT_CHECK( stack2.ok() );
#if defined (STLPORT) && !defined (_STLP_NO_MEMBER_TEMPLATES) && \
(!defined (_MSC_VER) || (_MSC_VER >= 1300))
{
//This is a compile time test.
//We check that sort implementation is correct when list is instanciated
//with an allocator that do not have a default constructor.
ListInt lint1(10, 0, stack1);
lint1.sort();
lint1.sort(greater<int>());
}
#endif
}
/*
void ListTest::const_list()
{
list<const int> cint_list;
cint_list.push_back(1);
cint_list.push_front(2);
}
*/
void ListTest::swap()
{
list<int> lst1;
list<int> lst2;
lst1.push_back(1);
lst2.push_back(2);
lst1.swap( lst2 );
CPPUNIT_CHECK( lst1.front() == 2 );
CPPUNIT_CHECK( lst2.front() == 1 );
CPPUNIT_CHECK( lst1.size() == 1 );
CPPUNIT_CHECK( lst2.size() == 1 );
lst1.pop_front();
lst2.pop_front();
CPPUNIT_CHECK( lst1.empty() );
CPPUNIT_CHECK( lst2.empty() );
}
namespace foo {
class bar {};
template <class _It>
size_t distance(_It, _It);
}
void ListTest::adl()
{
list<foo::bar> lbar;
CPPUNIT_ASSERT( lbar.size() == 0);
}
#if !defined (STLPORT) || \
!defined (_STLP_USE_PTR_SPECIALIZATIONS) || defined (_STLP_CLASS_PARTIAL_SPECIALIZATION)
/* Simple compilation test: Check that nested types like iterator
* can be access even if type used to instanciate container is not
* yet completely defined.
*/
class IncompleteClass
{
list<IncompleteClass> instances;
typedef list<IncompleteClass>::iterator it;
};
#endif