Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
21.string.iterators.cpp
Go to the documentation of this file.
1
29#include <string> // for string
30#include <stdexcept> // for out_of_range, length_error
31#include <cstddef> // for size_t
32
33#include <rw_strings.h> // for StringMembers
34#include <rw_driver.h> // for rw_test()
35#include <rw_allocator.h> // for UserAlloc
36#include <rw_char.h> // for rw_expand()
37#include <rw_new.h> // for bad_alloc, replacement operator new
38
39
41static const char* const exceptions[] = {
42 "unknown exception", "bad_alloc", "exception"
43};
44
45
47// used to exercise
48// begin () and rend ()
49static const StringTestCase
50begin_void_test_cases [] = {
51
52#undef TEST
53#define TEST(str, res) { \
54 __LINE__, -1, -1, -1, -1, -1, \
55 str, sizeof (str) - 1, \
56 0, 0, 0, res, 0 \
57}
58
59 // +--------------------------------- controlled sequence
60 // | +--------------- expected result
61 // | |
62 // V V
63 TEST ("a", 'a' ),
64 TEST ("<U0>", '\0'),
65 TEST ("abc", 'a' ),
66 TEST ("<U0>ab<U0>@2c", '\0'),
67 TEST ("a<U0>b<U0>@2c", 'a' ),
68 TEST ("a<U0>bc<U0>@2", 'a' ),
69 TEST ("x@4096", 'x' ),
70 TEST ("last", 'l' )
71};
72
73
75// used to exercise
76// end () and rbegin ()
77static const StringTestCase
78end_void_test_cases [] = {
79
80#undef TEST
81#define TEST(str, res) { \
82 __LINE__, -1, -1, -1, -1, -1, \
83 str, sizeof (str) - 1, \
84 0, 0, 0, res, 0 \
85}
86
87 // +--------------------------------- controlled sequence
88 // | +--------------- expected result
89 // | |
90 // V V
91 TEST ("a", 'a' ),
92 TEST ("<U0>", '\0'),
93 TEST ("abc", 'c' ),
94 TEST ("<U0>ab<U0>@2c", 'c' ),
95 TEST ("a<U0>b<U0>@2c", 'c' ),
96 TEST ("a<U0>bc<U0>@2", '\0'),
97 TEST ("x@4096", 'x' ),
98 TEST ("last", 't' )
99};
100
101
103// exercises:
104// c_str() and data ()
105static const StringTestCase
106c_str_void_test_cases [] = {
107
108#undef TEST
109#define TEST(str) { \
110 __LINE__, -1, -1, -1, -1, -1, \
111 str, sizeof (str) - 1, 0, 0, \
112 str, sizeof (str) - 1, 0 \
113}
114
115 // +-------------------------------- controlled sequence
116 // |
117 // |
118 // |
119 // |
120 // |
121 // |
122 // |
123 // V
124 TEST ("ab" ),
125
126 TEST ("" ),
127
128 TEST ("<U0>" ),
129
130 TEST ("abcdefghij" ),
131 TEST ("abcdefghi" ),
132
133 TEST ("abbdefghij" ),
134 TEST ("abcdeeghij" ),
135 TEST ("abcdefghii" ),
136
137 TEST ("bbcdefghij" ),
138 TEST ("eeeeeeghij" ),
139 TEST ("a" ),
140 TEST ("aeeee" ),
141
142 TEST ("bbcdefghij" ),
143 TEST ("abcdffghij" ),
144 TEST ("abcdefghjj" ),
145
146 TEST ("a<U0>b<U0>@2c" ),
147 TEST ("abc<U0>@3" ),
148 TEST ("<U0>ab<U0>@2c" ),
149
150 TEST ("a<U0>b" ),
151 TEST ("ab<U0>" ),
152 TEST ("<U0>ab" ),
153
154 TEST ("x@4096" ),
155 TEST ("xx" ),
156
157 TEST ("a@2048b@2048" ),
158 TEST ("a@2048cb@2047" ),
159
160 TEST ("last" )
161};
162
163
165// exercises:
166// get_allocator ()
167static const StringTestCase
168get_allocator_void_test_cases [] = {
169
170#undef TEST
171#define TEST(str) { \
172 __LINE__, -1, -1, -1, -1, -1, \
173 str, sizeof (str) - 1, \
174 0, 0, 0, 0, 0 \
175}
176
177 // +------------------------------------------ controlled sequence
178 // |
179 // |
180 // |
181 // |
182 // |
183 // |
184 // |
185 // V
186 TEST ("ab" ),
187 TEST ("" ),
188 TEST ("<U0>" ),
189 TEST ("x@4096" ),
190 TEST ("a<U0>b" ),
191 TEST ("a@2048cb@2047" ),
192 TEST ("last" )
193};
194
195
196
198template <class charT, class Traits, class Allocator>
200 const StringTestCaseData<charT> &tdata)
201{
202 typedef std::basic_string <charT, Traits, Allocator> String;
203 typedef typename String::iterator StringIter;
204 typedef typename String::const_iterator StringCIter;
205 typedef typename String::reverse_iterator StringRIter;
206 typedef typename String::const_reverse_iterator StringCRIter;
207
208 const StringFunc &func = tdata.func_;
209 const StringTestCase &tcase = tdata.tcase_;
210
211 const bool test_iters = func.which_ == StringIds::begin_void
212 || func.which_ == StringIds::begin_const_void
213 || func.which_ == StringIds::end_void
214 || func.which_ == StringIds::end_const_void
215 || func.which_ == StringIds::rbegin_void
216 || func.which_ == StringIds::rbegin_const_void
217 || func.which_ == StringIds::rend_void
218 || func.which_ == StringIds::rend_const_void;
219
220 const bool test_const_iters = func.which_ == StringIds::begin_const_void
221 || func.which_ == StringIds::end_const_void
222 || func.which_ == StringIds::rbegin_const_void
223 || func.which_ == StringIds::rend_const_void;
224
225 const bool test_end_iters = func.which_ == StringIds::end_void
226 || func.which_ == StringIds::end_const_void
227 || func.which_ == StringIds::rend_void
228 || func.which_ == StringIds::rend_const_void;
229
230 // allocator object for test get_allocator
232
233 // construct the string object
234 String str (tdata.str_, tdata.strlen_, alloc);
235 // construct the constant string object
236 const String cstr (tdata.str_, tdata.strlen_, alloc);
237
238 const std::size_t s_size = test_const_iters ? cstr.size () : str.size ();
239
240 // save the state of the string object before the call
241 // to detect wxception safety violations (changes to
242 // the state of the object after an exception)
243 const StringState str_state (rw_get_string_state (str));
244
245 rwt_free_store* const pst = rwt_get_free_store (0);
246 SharedAlloc* const pal = SharedAlloc::instance ();
247
248 // iterate for`throw_after' starting at the next call to operator new,
249 // forcing each call to throw an exception, until the function finally
250 // succeeds (i.e, no exception is thrown)
251 std::size_t throw_count;
252 for (throw_count = 0; ; ++throw_count) {
253
254 // (name of) expected and caught exception
255 const char* expected = 0;
256 const char* caught = 0;
257
258#ifndef _RWSTD_NO_EXCEPTIONS
259
260 // by default excercise the exception safety of the function
261 // by iteratively inducing an exception at each call to operator
262 // new or Allocator::allocate() until the call succeeds
263 expected = exceptions [1]; // bad_alloc
264 *pst->throw_at_calls_ [0] = pst->new_calls_ [0] + throw_count + 1;
265 pal->throw_at_calls_ [pal->m_allocate] =
266 pal->throw_at_calls_ [pal->m_allocate] + throw_count + 1;
267
268#endif // _RWSTD_NO_EXCEPTIONS
269
270 // start checking for memory leaks
271 rw_check_leaks (str.get_allocator ());
272
273 // for data () and c_str ()
274 const charT* ret_ptr = 0;
275
276 // methods result
277 charT res;
278
279 // for begin () and end ()
280 StringIter it;
281 // for begin () const and end () const
282 StringCIter cit;
283 // for rbegin () and rend ()
284 StringRIter rit;
285 // for rbegin () const and rend () const
286 StringCRIter crit;
287
288 // for get_allocator ()
289 Allocator resalloc;
290
291 try {
292
293 bool it_relations = true;
294
295 switch (func.which_) {
296
297 case StringIds::begin_void:
298 it = str.begin();
299 res = s_size ? *it : charT ();
300 it_relations = it == str.rend ().base ();
301 break;
302
303 case StringIds::begin_const_void:
304 cit = cstr.begin();
305 res = s_size ? *cit : charT ();
306 it_relations = cit == cstr.rend ().base ();
307 break;
308
309 case StringIds::end_void:
310 it = str.end();
311 res = s_size ? *(it - 1) : charT ();
312 it_relations = it == str.rbegin ().base ();
313 break;
314
315 case StringIds::end_const_void:
316 cit = cstr.end();
317 res = s_size ? *(cit - 1) : charT ();
318 it_relations = cit == cstr.rbegin ().base ();
319 break;
320
321 case StringIds::rbegin_void:
322 rit = str.rbegin();
323 res = s_size ? *rit : charT ();
324 it_relations = rit.base () == str.end ();
325 break;
326
327 case StringIds::rbegin_const_void:
328 crit = cstr.rbegin();
329 res = s_size ? *crit : charT ();
330 it_relations = crit.base () == cstr.end ();
331 break;
332
333 case StringIds::rend_void:
334 rit = str.rend();
335 res = s_size ? *(rit - 1) : charT ();
336 it_relations = rit.base () == str.begin ();
337 break;
338
339 case StringIds::rend_const_void:
340 crit = cstr.rend();
341 res = s_size ? *(crit - 1) : charT ();
342 it_relations = crit.base () == cstr.begin ();
343 break;
344
345 case StringIds::c_str_void:
346 ret_ptr = cstr.c_str ();
347 break;
348
349 case StringIds::data_void:
350 ret_ptr = cstr.data ();
351 break;
352
353 case StringIds::get_allocator_void:
354 resalloc = cstr.get_allocator ();
355 break;
356
357 default:
358 RW_ASSERT ("test logic error: unknown iterators overload");
359 return;
360 }
361
362 // for convenience
363 static const int cwidth = sizeof (charT);
364
365 if ( func.which_ == StringIds::data_void
366 || func.which_ == StringIds::c_str_void) {
367
368 // 21.3.6
369 // the member returns a non-null pointer
370 rw_assert(0 != ret_ptr, 0, tcase.line,
371 "line %d. %{$FUNCALL} expected non null, got null",
372 __LINE__);
373
374 if (ret_ptr) {
375 // 21.3.6.1
376 // if size() is nonzero, the member returns a pointer to the
377 // initial element of an array whose first size() elements
378 // equal the corresponding elements of the string controlled
379 // by *this
380 // 21.3.6.3
381 // if size() is nonzero, the member returns a pointer to the
382 // initial element of an array whose first size() elements
383 // equal the corresponding elements of the string controlled
384 // by *this
385 const std::size_t match =
386 rw_match (tcase.res, ret_ptr, tdata.reslen_);
387
388 rw_assert (match == tdata.reslen_, 0, tcase.line,
389 "line %d. %{$FUNCALL} expected %{#*s}, "
390 "got %{/*.*Gs}, differ at pos %zu",
391 __LINE__, int (tdata.reslen_), tdata.res_,
392 cwidth, int (s_size), ret_ptr, match);
393
394 if (func.which_ == StringIds::c_str_void) {
395
396 // check the last element is equal to char ()
397 const char null = char ();
398 const bool success =
399 (1 == rw_match (&null, &ret_ptr[s_size], 1));
400
401 rw_assert(success, 0, tcase.line,
402 "line %d. %{$FUNCALL} expected last element "
403 "is a null character %{#c}, got %{#c}",
404 __LINE__, null, ret_ptr[s_size]);
405 }
406 }
407 }
408
409 if (test_iters) {
410
411 if (s_size) {
412
413 const char exp_res =
414 (NPOS != tcase.nres ? char (tcase.nres) : char ());
415
416 const bool success = (1 == rw_match (&exp_res, &res, 1));
417
418 rw_assert (success, 0, tcase.line,
419 "line %d. %{$FUNCALL}%{?} - 1%{;} expected "
420 "%{#c}, got %{#c}", __LINE__,
421 test_end_iters, exp_res, res);
422 }
423 else {
424 bool success = true;
425
426 if ( func.which_ == StringIds::begin_void
427 || func.which_ == StringIds::end_void)
428 success = it == str.begin () && it == str.end ();
429
430 if ( func.which_ == StringIds::begin_const_void
431 || func.which_ == StringIds::end_const_void)
432 success = cit == cstr.begin () && cit == cstr.end ();
433
434 if ( func.which_ == StringIds::rbegin_void
435 || func.which_ == StringIds::rend_void)
436 success = rit == str.rbegin () && rit == str.rend ();
437
438 if ( func.which_ == StringIds::rbegin_const_void
439 || func.which_ == StringIds::rend_const_void)
440 success =
441 crit == cstr.rbegin () && crit == cstr.rend ();
442
443 // check the begin () == end (), rbegin () == rend ()
444 rw_assert(success, 0, tcase.line,
445 "line %d. %{$FUNCALL} returned iterator is not "
446 "equal to begin and end for an empty string",
447 __LINE__);
448 }
449
450 // check the iterators relationship
451 rw_assert(it_relations, 0, tcase.line,
452 "line %d. %{$FUNCALL} iterators "
453 "relationship is broken", __LINE__);
454 }
455
456 if (func.which_ == StringIds::get_allocator_void) {
457
458 // verify that the allocator returned from the function
459 // equal to allocator passed to the ctor
460 const bool success = (alloc == resalloc);
461
462 rw_assert(success, 0, tcase.line,
463 "line %d. %{$FUNCALL} expected equal to allocator "
464 "passed to the ctor", __LINE__);
465 }
466 }
467
468#ifndef _RWSTD_NO_EXCEPTIONS
469
470 catch (const std::bad_alloc &ex) {
471 caught = exceptions [1];
472 rw_assert (0 == tcase.bthrow, 0, tcase.line,
473 "line %d. %{$FUNCALL} %{?}expected %s,%{:}"
474 "unexpectedly%{;} caught std::%s(%#s)",
475 __LINE__, 0 != expected, expected, caught, ex.what ());
476 }
477 catch (const std::exception &ex) {
478 caught = exceptions [2];
479 rw_assert (0, 0, tcase.line,
480 "line %d. %{$FUNCALL} %{?}expected %s,%{:}"
481 "unexpectedly%{;} caught std::%s(%#s)",
482 __LINE__, 0 != expected, expected, caught, ex.what ());
483 }
484 catch (...) {
485 caught = exceptions [0];
486 rw_assert (0, 0, tcase.line,
487 "line %d. %{$FUNCALL} %{?}expected %s,%{:}"
488 "unexpectedly%{;} caught %s",
489 __LINE__, 0 != expected, expected, caught);
490 }
491
492#endif // _RWSTD_NO_EXCEPTIONS
493
494 // FIXME: verify the number of blocks the function call
495 // is expected to allocate and detect any memory leaks
496 rw_check_leaks (str.get_allocator (), tcase.line,
497 std::size_t (-1), std::size_t (-1));
498
499 if (caught) {
500 // verify that an exception thrown during allocation
501 // didn't cause a change in the state of the object
503 __LINE__, tcase.line, caught);
504
505 // allow this call to operator new to succeed and try
506 // to make the next one to fail during the next call
507 // to the same function again
508 continue;
509 }
510
511 break;
512 }
513
514 rw_assert (0 == throw_count, 0, tcase.line,
515 "line %d: %{$FUNCALL}: expected 0 %s exceptions, got %zu",
516 __LINE__, exceptions [1], throw_count);
517
518 // disable bad_alloc exceptions
519 *pst->throw_at_calls_ [0] = 0;
520 pal->throw_at_calls_ [pal->m_allocate] = 0;
521}
522
523
526
527int main (int argc, char** argv)
528{
529 static const StringTest
530 tests [] = {
531
532#undef TEST
533#define TEST(gsig, sig) { \
534 gsig, sig ## _test_cases, \
535 sizeof sig ## _test_cases / sizeof *sig ## _test_cases \
536}
537
538 TEST (StringIds::begin_void, begin_void),
539 TEST (StringIds::begin_const_void, begin_void),
540 TEST (StringIds::end_void, end_void),
541 TEST (StringIds::end_const_void, end_void),
542 TEST (StringIds::rbegin_void, end_void),
543 TEST (StringIds::rbegin_const_void, end_void),
544 TEST (StringIds::rend_void, begin_void),
545 TEST (StringIds::rend_const_void, begin_void),
546 TEST (StringIds::c_str_void, c_str_void),
547 TEST (StringIds::data_void, c_str_void),
548 TEST (StringIds::get_allocator_void, get_allocator_void)
549 };
550
551 const std::size_t test_count = sizeof tests / sizeof *tests;
552
553 return rw_run_string_test (argc, argv, __FILE__,
554 "lib.string.iterators",
555 test_iterators_func_array, tests, test_count);
556}
#define alloc
Definition 17.names.cpp:441
#define res
Definition 17.names.cpp:531
#define charT
Definition 17.names.cpp:456
#define TEST(str, res)
void test_iterators(charT *, Traits *, Allocator *, const StringTestCaseData< charT > &tdata)
std::char_traits< S > Traits
#define NPOS
#define main
int caught
const StringTestCase & tcase_
Definition rw_strings.h:692
const charT *const res_
Definition rw_strings.h:689
const StringFunc & func_
Definition rw_strings.h:691
const charT *const str_
Definition rw_strings.h:687
const char * str
Definition exec.cpp:170
_TEST_EXPORT void rw_check_leaks(const SharedAlloc *=0, int=0, _RWSTD_SIZE_T=0, _RWSTD_SIZE_T=_RWSTD_SIZE_MAX)
_TEST_EXPORT _RWSTD_SIZE_T rw_match(const char *, const char *, _RWSTD_SIZE_T=_RWSTD_SIZE_MAX)
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
_TEST_EXPORT rwt_free_store * rwt_get_free_store(rwt_free_store *)
Definition new.cpp:597
StringState rw_get_string_state(const String &str)
Definition rw_strings.h:752
_TEST_EXPORT int rw_run_string_test(int, char **, const char *, const char *, StringTestFunc *, const StringTest *, _RWSTD_SIZE_T)
#define DEFINE_STRING_TEST_FUNCTIONS(fname)
Definition rw_strings.h:909
#define RW_ASSERT(expr)
static SharedAlloc * instance(SharedAlloc *=0)
_RWSTD_SIZE_T throw_at_calls_[n_funs]
int assert_equal(const StringState &, int, int, const char *) const
_RWSTD_SIZE_T nres
Definition rw_strings.h:603
const char * res
Definition rw_strings.h:602
_RWSTD_SIZE_T * throw_at_calls_[2]
Definition rw_new.h:83
_RWSTD_SIZE_T new_calls_[2]
Definition rw_new.h:47