1//Has to be first for StackAllocator swap overload to be taken
2//into account (at least using GCC 4.0.1)
3#include "stack_allocator.h"
4
5#include <vector>
6#include <algorithm>
7#if !defined (STLPORT) || defined (_STLP_USE_EXCEPTIONS)
8# include <stdexcept>
9#endif
10
11#include "cppunit/cppunit_proxy.h"
12
13#if !defined (STLPORT) || defined(_STLP_USE_NAMESPACES)
14using namespace std;
15#endif
16
17//
18// TestCase class
19//
20class VectorTest : public CPPUNIT_NS::TestCase
21{
22  CPPUNIT_TEST_SUITE(VectorTest);
23  CPPUNIT_TEST(vec_test_1);
24  CPPUNIT_TEST(vec_test_2);
25  CPPUNIT_TEST(vec_test_3);
26  CPPUNIT_TEST(vec_test_4);
27  CPPUNIT_TEST(vec_test_5);
28  CPPUNIT_TEST(vec_test_6);
29  CPPUNIT_TEST(vec_test_7);
30  CPPUNIT_TEST(capacity);
31  CPPUNIT_TEST(at);
32  CPPUNIT_TEST(pointer);
33  CPPUNIT_TEST(auto_ref);
34  CPPUNIT_TEST(allocator_with_state);
35  CPPUNIT_TEST(iterators);
36#if defined (STLPORT) && defined (_STLP_NO_MEMBER_TEMPLATES)
37  CPPUNIT_IGNORE;
38#endif
39  CPPUNIT_TEST(optimizations_check);
40  CPPUNIT_TEST(assign_check);
41  CPPUNIT_STOP_IGNORE;
42  CPPUNIT_TEST(ebo);
43  CPPUNIT_TEST_SUITE_END();
44
45protected:
46  void vec_test_1();
47  void vec_test_2();
48  void vec_test_3();
49  void vec_test_4();
50  void vec_test_5();
51  void vec_test_6();
52  void vec_test_7();
53  void capacity();
54  void at();
55  void pointer();
56  void auto_ref();
57  void allocator_with_state();
58  void iterators();
59  void optimizations_check();
60  void assign_check();
61  void ebo();
62};
63
64CPPUNIT_TEST_SUITE_REGISTRATION(VectorTest);
65
66//
67// tests implementation
68//
69void VectorTest::vec_test_1()
70{
71  vector<int> v1; // Empty vector of integers.
72
73  CPPUNIT_ASSERT( v1.empty() == true );
74  CPPUNIT_ASSERT( v1.size() == 0 );
75
76  // CPPUNIT_ASSERT( v1.max_size() == INT_MAX / sizeof(int) );
77  // cout << "max_size = " << v1.max_size() << endl;
78  v1.push_back(42); // Add an integer to the vector.
79
80  CPPUNIT_ASSERT( v1.size() == 1 );
81
82  CPPUNIT_ASSERT( v1[0] == 42 );
83
84  {
85    vector<vector<int> > vect(10);
86    vector<vector<int> >::iterator it(vect.begin()), end(vect.end());
87    for (; it != end; ++it) {
88      CPPUNIT_ASSERT( (*it).empty() );
89      CPPUNIT_ASSERT( (*it).size() == 0 );
90      CPPUNIT_ASSERT( (*it).capacity() == 0 );
91      CPPUNIT_ASSERT( (*it).begin() == (*it).end() );
92    }
93  }
94}
95
96void VectorTest::vec_test_2()
97{
98  vector<double> v1; // Empty vector of doubles.
99  v1.push_back(32.1);
100  v1.push_back(40.5);
101  vector<double> v2; // Another empty vector of doubles.
102  v2.push_back(3.56);
103
104  CPPUNIT_ASSERT( v1.size() == 2 );
105  CPPUNIT_ASSERT( v1[0] == 32.1 );
106  CPPUNIT_ASSERT( v1[1] == 40.5 );
107
108  CPPUNIT_ASSERT( v2.size() == 1 );
109  CPPUNIT_ASSERT( v2[0] == 3.56 );
110  size_t v1Cap = v1.capacity();
111  size_t v2Cap = v2.capacity();
112
113  v1.swap(v2); // Swap the vector's contents.
114
115  CPPUNIT_ASSERT( v1.size() == 1 );
116  CPPUNIT_ASSERT( v1.capacity() == v2Cap );
117  CPPUNIT_ASSERT( v1[0] == 3.56 );
118
119  CPPUNIT_ASSERT( v2.size() == 2 );
120  CPPUNIT_ASSERT( v2.capacity() == v1Cap );
121  CPPUNIT_ASSERT( v2[0] == 32.1 );
122  CPPUNIT_ASSERT( v2[1] == 40.5 );
123
124  v2 = v1; // Assign one vector to another.
125
126  CPPUNIT_ASSERT( v2.size() == 1 );
127  CPPUNIT_ASSERT( v2[0] == 3.56 );
128}
129
130void VectorTest::vec_test_3()
131{
132  typedef vector<char> vec_type;
133
134  vec_type v1; // Empty vector of characters.
135  v1.push_back('h');
136  v1.push_back('i');
137
138  CPPUNIT_ASSERT( v1.size() == 2 );
139  CPPUNIT_ASSERT( v1[0] == 'h' );
140  CPPUNIT_ASSERT( v1[1] == 'i' );
141
142  vec_type v2(v1.begin(), v1.end());
143  v2[1] = 'o'; // Replace second character.
144
145  CPPUNIT_ASSERT( v2.size() == 2 );
146  CPPUNIT_ASSERT( v2[0] == 'h' );
147  CPPUNIT_ASSERT( v2[1] == 'o' );
148
149  CPPUNIT_ASSERT( (v1 == v2) == false );
150
151  CPPUNIT_ASSERT( (v1 < v2) == true );
152}
153
154void VectorTest::vec_test_4()
155{
156  vector<int> v(4);
157
158  v[0] = 1;
159  v[1] = 4;
160  v[2] = 9;
161  v[3] = 16;
162
163  CPPUNIT_ASSERT( v.front() == 1 );
164  CPPUNIT_ASSERT( v.back() == 16 );
165
166  v.push_back(25);
167
168  CPPUNIT_ASSERT( v.back() == 25 );
169  CPPUNIT_ASSERT( v.size() == 5 );
170
171  v.pop_back();
172
173  CPPUNIT_ASSERT( v.back() == 16 );
174  CPPUNIT_ASSERT( v.size() == 4 );
175}
176
177void VectorTest::vec_test_5()
178{
179  int array [] = { 1, 4, 9, 16 };
180
181  vector<int> v(array, array + 4);
182
183  CPPUNIT_ASSERT( v.size() == 4 );
184
185  CPPUNIT_ASSERT( v[0] == 1 );
186  CPPUNIT_ASSERT( v[1] == 4 );
187  CPPUNIT_ASSERT( v[2] == 9 );
188  CPPUNIT_ASSERT( v[3] == 16 );
189}
190
191void VectorTest::vec_test_6()
192{
193  int array [] = { 1, 4, 9, 16, 25, 36 };
194
195  vector<int> v(array, array + 6);
196  vector<int>::iterator vit;
197
198  CPPUNIT_ASSERT( v.size() == 6 );
199  CPPUNIT_ASSERT( v[0] == 1 );
200  CPPUNIT_ASSERT( v[1] == 4 );
201  CPPUNIT_ASSERT( v[2] == 9 );
202  CPPUNIT_ASSERT( v[3] == 16 );
203  CPPUNIT_ASSERT( v[4] == 25 );
204  CPPUNIT_ASSERT( v[5] == 36 );
205
206  vit = v.erase( v.begin() ); // Erase first element.
207  CPPUNIT_ASSERT( *vit == 4 );
208
209  CPPUNIT_ASSERT( v.size() == 5 );
210  CPPUNIT_ASSERT( v[0] == 4 );
211  CPPUNIT_ASSERT( v[1] == 9 );
212  CPPUNIT_ASSERT( v[2] == 16 );
213  CPPUNIT_ASSERT( v[3] == 25 );
214  CPPUNIT_ASSERT( v[4] == 36 );
215
216  vit = v.erase(v.end() - 1); // Erase last element.
217  CPPUNIT_ASSERT( vit == v.end() );
218
219  CPPUNIT_ASSERT( v.size() == 4 );
220  CPPUNIT_ASSERT( v[0] == 4 );
221  CPPUNIT_ASSERT( v[1] == 9 );
222  CPPUNIT_ASSERT( v[2] == 16 );
223  CPPUNIT_ASSERT( v[3] == 25 );
224
225
226  v.erase(v.begin() + 1, v.end() - 1); // Erase all but first and last.
227
228  CPPUNIT_ASSERT( v.size() == 2 );
229  CPPUNIT_ASSERT( v[0] == 4 );
230  CPPUNIT_ASSERT( v[1] == 25 );
231
232}
233
234void VectorTest::vec_test_7()
235{
236  int array1 [] = { 1, 4, 25 };
237  int array2 [] = { 9, 16 };
238
239  vector<int> v(array1, array1 + 3);
240  vector<int>::iterator vit;
241  vit = v.insert(v.begin(), 0); // Insert before first element.
242  CPPUNIT_ASSERT( *vit == 0 );
243
244  vit = v.insert(v.end(), 36);  // Insert after last element.
245  CPPUNIT_ASSERT( *vit == 36 );
246
247  CPPUNIT_ASSERT( v.size() == 5 );
248  CPPUNIT_ASSERT( v[0] == 0 );
249  CPPUNIT_ASSERT( v[1] == 1 );
250  CPPUNIT_ASSERT( v[2] == 4 );
251  CPPUNIT_ASSERT( v[3] == 25 );
252  CPPUNIT_ASSERT( v[4] == 36 );
253
254  // Insert contents of array2 before fourth element.
255  v.insert(v.begin() + 3, array2, array2 + 2);
256
257  CPPUNIT_ASSERT( v.size() == 7 );
258
259  CPPUNIT_ASSERT( v[0] == 0 );
260  CPPUNIT_ASSERT( v[1] == 1 );
261  CPPUNIT_ASSERT( v[2] == 4 );
262  CPPUNIT_ASSERT( v[3] == 9 );
263  CPPUNIT_ASSERT( v[4] == 16 );
264  CPPUNIT_ASSERT( v[5] == 25 );
265  CPPUNIT_ASSERT( v[6] == 36 );
266
267  v.clear();
268  CPPUNIT_ASSERT( v.empty() );
269
270  v.insert(v.begin(), 5, 10);
271  CPPUNIT_ASSERT( v.size() == 5 );
272  CPPUNIT_ASSERT( v[0] == 10 );
273  CPPUNIT_ASSERT( v[1] == 10 );
274  CPPUNIT_ASSERT( v[2] == 10 );
275  CPPUNIT_ASSERT( v[3] == 10 );
276  CPPUNIT_ASSERT( v[4] == 10 );
277
278  /*
279  {
280    vector<float> vf(2.0f, 3.0f);
281    CPPUNIT_ASSERT( vf.size() == 2 );
282    CPPUNIT_ASSERT( vf.front() == 3.0f );
283    CPPUNIT_ASSERT( vf.back() == 3.0f );
284  }
285  */
286}
287
288struct TestStruct
289{
290  unsigned int a[3];
291};
292
293void VectorTest::capacity()
294{
295  {
296    vector<int> v;
297
298    CPPUNIT_ASSERT( v.capacity() == 0 );
299    v.push_back(42);
300    CPPUNIT_ASSERT( v.capacity() >= 1 );
301    v.reserve(5000);
302    CPPUNIT_ASSERT( v.capacity() >= 5000 );
303  }
304
305  {
306    //Test that used to generate an assertion when using __debug_alloc.
307    vector<TestStruct> va;
308    va.reserve(1);
309    va.reserve(2);
310  }
311}
312
313void VectorTest::at() {
314  vector<int> v;
315  vector<int> const& cv = v;
316
317  v.push_back(10);
318  CPPUNIT_ASSERT( v.at(0) == 10 );
319  v.at(0) = 20;
320  CPPUNIT_ASSERT( cv.at(0) == 20 );
321
322#if !defined (STLPORT) || defined (_STLP_USE_EXCEPTIONS)
323  try {
324    v.at(1) = 20;
325    CPPUNIT_FAIL;
326  }
327  catch (out_of_range const&) {
328  }
329  catch (...) {
330    CPPUNIT_FAIL;
331  }
332#endif
333}
334
335void VectorTest::pointer()
336{
337  vector<int *> v1;
338  vector<int *> v2 = v1;
339  vector<int *> v3;
340
341  v3.insert( v3.end(), v1.begin(), v1.end() );
342}
343
344void VectorTest::auto_ref()
345{
346  vector<int> ref;
347  for (int i = 0; i < 5; ++i) {
348    ref.push_back(i);
349  }
350
351  vector<vector<int> > v_v_int(1, ref);
352  v_v_int.push_back(v_v_int[0]);
353  v_v_int.push_back(ref);
354  v_v_int.push_back(v_v_int[0]);
355  v_v_int.push_back(v_v_int[0]);
356  v_v_int.push_back(ref);
357
358  vector<vector<int> >::iterator vvit(v_v_int.begin()), vvitEnd(v_v_int.end());
359  for (; vvit != vvitEnd; ++vvit) {
360    CPPUNIT_ASSERT( *vvit == ref );
361  }
362
363  /*
364   * Forbidden by the Standard:
365  v_v_int.insert(v_v_int.end(), v_v_int.begin(), v_v_int.end());
366  for (vvit = v_v_int.begin(), vvitEnd = v_v_int.end();
367       vvit != vvitEnd; ++vvit) {
368    CPPUNIT_ASSERT( *vvit == ref );
369  }
370   */
371}
372
373void VectorTest::allocator_with_state()
374  {
375    char buf1[1024];
376    StackAllocator<int> stack1(buf1, buf1 + sizeof(buf1));
377
378    char buf2[1024];
379    StackAllocator<int> stack2(buf2, buf2 + sizeof(buf2));
380
381    {
382      typedef vector<int, StackAllocator<int> > VectorInt;
383      VectorInt vint1(10, 0, stack1);
384      VectorInt vint1Cpy(vint1);
385
386      VectorInt vint2(10, 1, stack2);
387      VectorInt vint2Cpy(vint2);
388
389      vint1.swap(vint2);
390
391      CPPUNIT_ASSERT( vint1.get_allocator().swaped() );
392      CPPUNIT_ASSERT( vint2.get_allocator().swaped() );
393
394      CPPUNIT_ASSERT( vint1 == vint2Cpy );
395      CPPUNIT_ASSERT( vint2 == vint1Cpy );
396      CPPUNIT_ASSERT( vint1.get_allocator() == stack2 );
397      CPPUNIT_ASSERT( vint2.get_allocator() == stack1 );
398    }
399    CPPUNIT_ASSERT( stack1.ok() );
400    CPPUNIT_ASSERT( stack2.ok() );
401  }
402
403struct Point {
404  int x, y;
405};
406
407struct PointEx : public Point {
408  PointEx() : builtFromBase(false) {}
409  PointEx(const Point&) : builtFromBase(true) {}
410
411  bool builtFromBase;
412};
413
414#if defined (STLPORT)
415#  if defined (_STLP_USE_NAMESPACES)
416namespace std {
417#  endif
418  _STLP_TEMPLATE_NULL
419  struct __type_traits<PointEx> {
420    typedef __false_type has_trivial_default_constructor;
421    typedef __true_type has_trivial_copy_constructor;
422    typedef __true_type has_trivial_assignment_operator;
423    typedef __true_type has_trivial_destructor;
424    typedef __true_type is_POD_type;
425  };
426#  if defined (_STLP_USE_NAMESPACES)
427}
428#  endif
429#endif
430
431//This test check that vector implementation do not over optimize
432//operation as PointEx copy constructor is trivial
433void VectorTest::optimizations_check()
434{
435#if !defined (STLPORT) || !defined (_STLP_NO_MEMBER_TEMPLATES)
436  vector<Point> v1(1);
437  CPPUNIT_ASSERT( v1.size() == 1 );
438
439  vector<PointEx> v2(v1.begin(), v1.end());
440  CPPUNIT_ASSERT( v2.size() == 1 );
441  CPPUNIT_ASSERT( v2[0].builtFromBase == true );
442#endif
443}
444
445void VectorTest::assign_check()
446{
447#if !defined (STLPORT) || !defined (_STLP_NO_MEMBER_TEMPLATES)
448  vector<int> v(3,1);
449  int array[] = { 1, 2, 3, 4, 5 };
450
451  v.assign( array, array + 5 );
452  CPPUNIT_CHECK( v[4] == 5 );
453  CPPUNIT_CHECK( v[0] == 1 );
454  CPPUNIT_CHECK( v[1] == 2 );
455#endif
456}
457
458void VectorTest::iterators()
459{
460  vector<int> vint(10, 0);
461  vector<int> const& crvint = vint;
462
463  CPPUNIT_ASSERT( vint.begin() == vint.begin() );
464  CPPUNIT_ASSERT( crvint.begin() == vint.begin() );
465  CPPUNIT_ASSERT( vint.begin() == crvint.begin() );
466  CPPUNIT_ASSERT( crvint.begin() == crvint.begin() );
467
468  CPPUNIT_ASSERT( vint.begin() != vint.end() );
469  CPPUNIT_ASSERT( crvint.begin() != vint.end() );
470  CPPUNIT_ASSERT( vint.begin() != crvint.end() );
471  CPPUNIT_ASSERT( crvint.begin() != crvint.end() );
472
473  CPPUNIT_ASSERT( vint.rbegin() == vint.rbegin() );
474  // Not Standard:
475  //CPPUNIT_ASSERT( vint.rbegin() == crvint.rbegin() );
476  //CPPUNIT_ASSERT( crvint.rbegin() == vint.rbegin() );
477  CPPUNIT_ASSERT( crvint.rbegin() == crvint.rbegin() );
478
479  CPPUNIT_ASSERT( vint.rbegin() != vint.rend() );
480  // Not Standard:
481  //CPPUNIT_ASSERT( vint.rbegin() != crvint.rend() );
482  //CPPUNIT_ASSERT( crvint.rbegin() != vint.rend() );
483  CPPUNIT_ASSERT( crvint.rbegin() != crvint.rend() );
484}
485
486
487#if !defined (STLPORT) || \
488    !defined (_STLP_USE_PTR_SPECIALIZATIONS) || defined (_STLP_CLASS_PARTIAL_SPECIALIZATION)
489/* Simple compilation test: Check that nested types like iterator
490 * can be access even if type used to instanciate container is not
491 * yet completely defined.
492 */
493class IncompleteClass
494{
495  vector<IncompleteClass> instances;
496  typedef vector<IncompleteClass>::iterator it;
497};
498#endif
499
500#if defined (STLPORT)
501#  define NOTHROW _STLP_NOTHROW
502#else
503#  define NOTHROW throw()
504#endif
505
506/* This allocator implementation purpose is simply to break some
507 * internal STLport mecanism specific to the STLport own allocator
508 * implementation. */
509template <class _Tp>
510struct NotSTLportAllocator : public allocator<_Tp> {
511#if !defined (STLPORT) || defined (_STLP_MEMBER_TEMPLATE_CLASSES)
512  template <class _Tp1> struct rebind {
513    typedef NotSTLportAllocator<_Tp1> other;
514  };
515#endif
516  NotSTLportAllocator() NOTHROW {}
517#if !defined (STLPORT) || defined (_STLP_MEMBER_TEMPLATES)
518  template <class _Tp1> NotSTLportAllocator(const NotSTLportAllocator<_Tp1>&) NOTHROW {}
519#endif
520  NotSTLportAllocator(const NotSTLportAllocator<_Tp>&) NOTHROW {}
521  ~NotSTLportAllocator() NOTHROW {}
522};
523
524/* This test check a potential issue with empty base class
525 * optimization. Some compilers (VC6) do not implement it
526 * correctly resulting ina wrong behavior. */
527void VectorTest::ebo()
528{
529  // We use heap memory as test failure can corrupt vector internal
530  // representation making executable crash on vector destructor invocation.
531  // We prefer a simple memory leak, internal corruption should be reveal
532  // by size or capacity checks.
533  typedef vector<int, NotSTLportAllocator<int> > V;
534  V *pv1 = new V(1, 1);
535  V *pv2 = new V(10, 2);
536
537  size_t v1Capacity = pv1->capacity();
538  size_t v2Capacity = pv2->capacity();
539
540  pv1->swap(*pv2);
541
542  CPPUNIT_ASSERT( pv1->size() == 10 );
543  CPPUNIT_ASSERT( pv1->capacity() == v2Capacity );
544  CPPUNIT_ASSERT( (*pv1)[5] == 2 );
545
546  CPPUNIT_ASSERT( pv2->size() == 1 );
547  CPPUNIT_ASSERT( pv2->capacity() == v1Capacity );
548  CPPUNIT_ASSERT( (*pv2)[0] == 1 );
549
550  delete pv2;
551  delete pv1;
552}
553
554