Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
21.string.op.plus.equal.cpp
Go to the documentation of this file.
1
29#include <string> // for string
30#include <stdexcept> // for out_of_range, length_error
31
32#include <cstddef> // for size_t
33
34#include <rw_strings.h> // for StringIds
35#include <rw_alg_test.h> // for InputIter
36#include <rw_driver.h> // for rw_test()
37#include <rw_allocator.h> // for UserAlloc
38#include <rw_char.h> // for rw_expand()
39#include <rw_new.h> // for bad_alloc, replacement operator new
40
41
43// for convenience and brevity
44#define OpPlusEq(sig) StringIds::op_plus_eq_ ## sig
45
46static const char* const exceptions[] = {
47 "unknown exception", "out_of_range", "length_error",
48 "bad_alloc", "exception"
49};
50
51
53// exercises:
54// operator += (const value_type*)
55static const StringTestCase
56cptr_test_cases [] = {
57
58#undef TEST
59#define TEST(str, src, res, bthrow) \
60 { __LINE__, -1, -1, -1, -1, -1, str, sizeof str - 1, src, \
61 sizeof src - 1, res, sizeof res - 1, bthrow }
62
63 // +----------------------------------------- controlled sequence
64 // | +----------------------- sequence to be appended
65 // | | +--------- expected result sequence
66 // | | | +---- exception info
67 // | | | | 0 - no exception
68 // | | | | 1 - length_error
69 // | | | |
70 // | | | +--------------+
71 // V V V V
72 TEST ("ab", "c", "abc", 0),
73
74 TEST ("", "", "", 0),
75 TEST ("", "<U0>", "", 0),
76 TEST ("", "abc", "abc", 0),
77
78 TEST ("<U0>", "", "<U0>", 0),
79 TEST ("<U0>", "a", "<U0>a", 0),
80 TEST ("<U0>", "<U0>@2", "<U0>", 0),
81
82 TEST ("ab", "cd", "abcd", 0),
83 TEST ("bcd", "a", "bcda", 0),
84 TEST ("cde", "ab", "cdeab", 0),
85 TEST ("abc", "", "abc", 0),
86 TEST ("ab", "c<U0>e", "abc", 0),
87
88 TEST ("<U0>@2ab", "cdefghij", "<U0>@2abcdefghij", 0),
89 TEST ("a<U0>@2b", "cdefghij", "a<U0>@2bcdefghij", 0),
90 TEST ("ab<U0>@2", "cdefghij", "ab<U0>@2cdefghij", 0),
91 TEST ("a<U0>b<U0>@2c", "e<U0>", "a<U0>b<U0>@2ce", 0),
92 TEST ("<U0>ab<U0>@2c", "e<U0>", "<U0>ab<U0>@2ce", 0),
93 TEST ("abcdefghij", "abcdefghij", "abcdefghijabcdefghij", 0),
94
95 TEST ("", "x@4096", "x@4096", 0),
96 TEST ("x@4096", "", "x@4096", 0),
97 TEST ("x@2048", "y@2048", "x@2048y@2048", 0),
98
99 TEST ("x@10", "x@118", "x@128", 0),
100 TEST ("x@128", "x@79", "x@207", 0),
101 TEST ("x@207", "x@127", "x@334", 0),
102 TEST ("x@334", "x@206", "x@540", 0),
103 TEST ("x@540", "x@333", "x@873", 0),
104 TEST ("x@539", "x@873", "x@1412", 0),
105 TEST ("x@872", "x@1412", "x@2284", 0),
106 TEST ("x@1411", "x@2284", "x@3695", 0),
107 TEST ("x@1412", "x@2284", "x@3696", 0),
108
109 TEST ("", 0, "", 0),
110 TEST ("abc", 0, "abcabc", 0),
111 TEST ("a<U0>@2bc", 0, "a<U0>@2bca", 0),
112 TEST ("<U0>@2abc", 0, "<U0>@2abc", 0),
113 TEST ("abc<U0>@2", 0, "abc<U0>@2abc", 0),
114 TEST ("x@2048", 0, "x@4096", 0),
115
116 TEST ("last", "test", "lasttest", 0)
117};
118
119
121// exercises:
122// operator += (const basic_string&)
123static const StringTestCase
124cstr_test_cases [] = {
125
126#undef TEST
127#define TEST(str, src, res, bthrow) \
128 { __LINE__, -1, -1, -1, -1, -1, str, sizeof str - 1, src, \
129 sizeof src - 1, res, sizeof res - 1, bthrow }
130
131 // +----------------------------------------- controlled sequence
132 // | +----------------------- sequence to be appended
133 // | | +--------- expected result sequence
134 // | | | +---- exception info
135 // | | | | 0 - no exception
136 // | | | | 1 - length_error
137 // | | | |
138 // | | | +--------------+
139 // V V V V
140 TEST ("ab", "c", "abc", 0),
141
142 TEST ("", "", "", 0),
143 TEST ("", "<U0>", "<U0>", 0),
144 TEST ("", "abc", "abc", 0),
145
146 TEST ("<U0>", "", "<U0>", 0),
147 TEST ("<U0>", "a", "<U0>a", 0),
148 TEST ("<U0>", "<U0>@2", "<U0>@3", 0),
149
150 TEST ("ab", "cd", "abcd", 0),
151 TEST ("bcd", "a", "bcda", 0),
152 TEST ("cde", "ab", "cdeab", 0),
153 TEST ("abc", "", "abc", 0),
154 TEST ("ab", "c<U0>e", "abc<U0>e", 0),
155
156 TEST ("<U0>@2ab", "cdefghij", "<U0>@2abcdefghij", 0),
157 TEST ("a<U0>@2b", "cdefghij", "a<U0>@2bcdefghij", 0),
158 TEST ("ab<U0>@2", "cdefghij", "ab<U0>@2cdefghij", 0),
159 TEST ("a<U0>b<U0>@2c", "e<U0>", "a<U0>b<U0>@2ce<U0>", 0),
160 TEST ("<U0>ab<U0>@2c", "e<U0>", "<U0>ab<U0>@2ce<U0>", 0),
161 TEST ("ab<U0>@2c<U0>", "<U0>e", "ab<U0>@2c<U0>@2e", 0),
162 TEST ("abcdefghij", "abcdefghij", "abcdefghijabcdefghij", 0),
163
164 TEST ("", "x@4096", "x@4096", 0),
165 TEST ("x@4096", "", "x@4096", 0),
166 TEST ("x@2048", "y@2048", "x@2048y@2048", 0),
167
168 TEST ("x@10", "x@118", "x@128", 0),
169 TEST ("x@128", "x@79", "x@207", 0),
170 TEST ("x@207", "x@127", "x@334", 0),
171 TEST ("x@334", "x@206", "x@540", 0),
172 TEST ("x@540", "x@333", "x@873", 0),
173 TEST ("x@539", "x@873", "x@1412", 0),
174 TEST ("x@872", "x@1412", "x@2284", 0),
175 TEST ("x@1411", "x@2284", "x@3695", 0),
176 TEST ("x@1412", "x@2284", "x@3696", 0),
177
178 TEST ("", 0, "", 0),
179 TEST ("abc", 0, "abcabc", 0),
180 TEST ("a<U0>@2bc", 0, "a<U0>@2bca<U0>@2bc", 0),
181 TEST ("<U0>@2abc", 0, "<U0>@2abc<U0>@2abc", 0),
182 TEST ("abc<U0>@2", 0, "abc<U0>@2abc<U0>@2", 0),
183 TEST ("x@2048", 0, "x@4096", 0),
184
185 TEST ("last", "test", "lasttest", 0)
186};
187
188
190// exercises:
191// operator+= (value_type)
192static const StringTestCase
193val_test_cases [] = {
194
195#undef TEST
196#define TEST(str, val, res, bthrow) \
197 { __LINE__, -1, -1, -1, -1, val, str, sizeof str - 1, 0, 0, \
198 res, sizeof res - 1, bthrow }
199
200 // +---------------------------------- controlled sequence
201 // | +----------------- character to be appended
202 // | | +------------- expected result sequence
203 // | | | +- exception info
204 // | | | | 0 - no exception
205 // | | | | 1 - length_error
206 // | | | |
207 // | | | +----+
208 // V V V V
209 TEST ("ab", 'c', "abc", 0),
210
211 TEST ("", 'a', "a", 0),
212 TEST ("", '\0', "<U0>", 0),
213
214 TEST ("<U0>", 'a', "<U0>a", 0),
215 TEST ("<U0>", '\0', "<U0>@2", 0),
216
217 TEST ("cde", 'a', "cdea", 0),
218 TEST ("abc", '\0', "abc<U0>", 0),
219
220 TEST ("a<U0>b<U0>@2c", '\0', "a<U0>b<U0>@2c<U0>", 0),
221 TEST ("<U0>ab<U0>@2c", '\0', "<U0>ab<U0>@2c<U0>", 0),
222 TEST ("a<U0>bc<U0>@2", 'a', "a<U0>bc<U0>@2a", 0),
223
224 TEST ("x@127", 'x', "x@128", 0),
225 TEST ("x@206", 'x', "x@207", 0),
226 TEST ("x@333", 'x', "x@334", 0),
227 TEST ("x@539", 'x', "x@540", 0),
228 TEST ("x@1411", 'x', "x@1412", 0),
229 TEST ("x@2283", 'x', "x@2284", 0),
230 TEST ("x@3694", 'x', "x@3695", 0),
231 TEST ("x@540", 'x', "x@541", 0),
232
233 TEST ("last", 't', "lastt", 0)
234};
235
236
238template <class charT, class Traits, class Allocator>
240 const StringFunc &func,
241 const StringTestCase &tcase)
242{
243 typedef std::basic_string <charT, Traits, Allocator> String;
244 typedef typename String::iterator StringIter;
245 typedef typename UserTraits<charT>::MemFun UTMemFun;
246
247 static const std::size_t BUFSIZE = 256;
248
249 static charT wstr_buf [BUFSIZE];
250 static charT warg_buf [BUFSIZE];
251
252 std::size_t str_len = sizeof wstr_buf / sizeof *wstr_buf;
253 std::size_t arg_len = sizeof warg_buf / sizeof *warg_buf;
254
255 charT* wstr = rw_expand (wstr_buf, tcase.str, tcase.str_len, &str_len);
256 charT* warg = rw_expand (warg_buf, tcase.arg, tcase.arg_len, &arg_len);
257
258 static charT wres_buf [BUFSIZE];
259 std::size_t res_len = sizeof wres_buf / sizeof *wres_buf;
260 charT* wres = rw_expand (wres_buf, tcase.res, tcase.nres, &res_len);
261
262 // construct the string object to be modified
263 // and the (possibly unused) argument string
264 /* const */ String str (wstr, str_len);
265 const String arg (warg, arg_len);
266
267 if (wstr != wstr_buf)
268 delete[] wstr;
269
270 if (warg != warg_buf)
271 delete[] warg;
272
273 wstr = 0;
274 warg = 0;
275
276 // save the state of the string object before the call
277 // to detect wxception safety violations (changes to
278 // the state of the object after an exception)
279 const StringState str_state (rw_get_string_state (str));
280
281 const charT* const arg_ptr = tcase.arg ? arg.c_str () : str.c_str ();
282 const String& arg_str = tcase.arg ? arg : str;
283 const charT arg_val = make_char (char (tcase.val), (charT*)0);
284
285 std::size_t total_length_calls = 0;
286 std::size_t n_length_calls = 0;
287 std::size_t* const rg_calls = rw_get_call_counters ((Traits*)0, (charT*)0);
288
289 if (rg_calls)
290 total_length_calls = rg_calls [UTMemFun::length];
291
292 rwt_free_store* const pst = rwt_get_free_store (0);
293 SharedAlloc* const pal = SharedAlloc::instance ();
294
295 // iterate for`throw_after' starting at the next call to operator new,
296 // forcing each call to throw an exception, until the function finally
297 // succeeds (i.e, no exception is thrown)
298 std::size_t throw_count;
299 for (throw_count = 0; ; ++throw_count) {
300
301 // (name of) expected and caught exception
302 const char* expected = 0;
303 const char* caught = 0;
304
305#ifndef _RWSTD_NO_EXCEPTIONS
306
307 if (1 == tcase.bthrow)
308 expected = exceptions [2]; // length_error
309 else if (0 == tcase.bthrow) {
310 // by default excercise the exception safety of the function
311 // by iteratively inducing an exception at each call to operator
312 // new or Allocator::allocate() until the call succeeds
313 expected = exceptions [3]; // bad_alloc
314 *pst->throw_at_calls_ [0] = pst->new_calls_ [0] + throw_count + 1;
315 pal->throw_at_calls_ [pal->m_allocate] =
316 pal->throw_at_calls_ [pal->m_allocate] + throw_count + 1;
317 }
318 else {
319 // exceptions disabled for this test case
320 }
321
322#else // if defined (_RWSTD_NO_EXCEPTIONS)
323
324 if (tcase.bthrow) {
325 if (wres != wres_buf)
326 delete[] wres;
327
328 return;
329 }
330
331#endif // _RWSTD_NO_EXCEPTIONS
332
333 // start checking for memory leaks
334 rw_check_leaks (str.get_allocator ());
335
336 try {
337
338 // pointer to the returned reference
339 const String* ret_ptr = 0;
340
341 switch (func.which_) {
342
343 case OpPlusEq (cptr):
344 ret_ptr = &str.operator+= (arg_ptr);
345 if (rg_calls)
346 n_length_calls = rg_calls [UTMemFun::length];
347 break;
348
349 case OpPlusEq (cstr):
350 ret_ptr = &str.operator+= (arg_str);
351 break;
352
353 case OpPlusEq (val):
354 ret_ptr = &str.operator+= (arg_val);
355 break;
356
357 default:
358 RW_ASSERT ("test logic error: unknown operator += overload");
359 return;
360 }
361
362 // verify that the reference returned from the function
363 // refers to the modified string object (i.e., *this
364 // within the function)
365 const std::ptrdiff_t ret_off = ret_ptr - &str;
366
367 // verify the returned value
368 rw_assert (0 == ret_off, 0, tcase.line,
369 "line %d. %{$FUNCALL} returned invalid reference, "
370 "offset is %td", __LINE__, ret_off);
371
372 // verfiy that strings length are equal
373 rw_assert (res_len == str.size (), 0, tcase.line,
374 "line %d. %{$FUNCALL} expected %{#*s} "
375 "with length %zu, got %{/*.*Gs} with length %zu",
376 __LINE__, int (tcase.nres), tcase.res, res_len,
377 int (sizeof (charT)), int (str.size ()),
378 str.c_str (), str.size ());
379
380 if (res_len == str.size ()) {
381 // if the result length matches the expected length
382 // (and only then), also verify that the modified
383 // string matches the expected result
384 const std::size_t match =
385 rw_match (tcase.res, str.c_str(), str.size ());
386
387 rw_assert (match == res_len, 0, tcase.line,
388 "line %d. %{$FUNCALL} expected %{#*s}, "
389 "got %{/*.*Gs}, difference at offset %zu",
390 __LINE__, int (tcase.nres), tcase.res,
391 int (sizeof (charT)), int (str.size ()),
392 str.c_str (), match);
393 }
394
395 // verify that Traits::length was used
396 if (OpPlusEq (cptr) == func.which_ && rg_calls) {
397 rw_assert (n_length_calls - total_length_calls > 0,
398 0, tcase.line, "line %d. %{$FUNCALL} doesn't "
399 "use traits::length()", __LINE__);
400 }
401 }
402
403#ifndef _RWSTD_NO_EXCEPTIONS
404
405 catch (const std::length_error &ex) {
406 caught = exceptions [2];
407 rw_assert (caught == expected, 0, tcase.line,
408 "line %d. %{$FUNCALL} %{?}expected %s,%{:}"
409 "unexpectedly%{;} caught std::%s(%#s)",
410 __LINE__, 0 != expected, expected, caught, ex.what ());
411 }
412 catch (const std::bad_alloc &ex) {
413 caught = exceptions [3];
414 rw_assert (0 == tcase.bthrow, 0, tcase.line,
415 "line %d. %{$FUNCALL} %{?}expected %s,%{:}"
416 "unexpectedly%{;} caught std::%s(%#s)",
417 __LINE__, 0 != expected, expected, caught, ex.what ());
418 }
419 catch (const std::exception &ex) {
420 caught = exceptions [4];
421 rw_assert (0, 0, tcase.line,
422 "line %d. %{$FUNCALL} %{?}expected %s,%{:}"
423 "unexpectedly%{;} caught std::%s(%#s)",
424 __LINE__, 0 != expected, expected, caught, ex.what ());
425 }
426 catch (...) {
427 caught = exceptions [0];
428 rw_assert (0, 0, tcase.line,
429 "line %d. %{$FUNCALL} %{?}expected %s,%{:}"
430 "unexpectedly%{;} caught %s",
431 __LINE__, 0 != expected, expected, caught);
432 }
433
434#endif // _RWSTD_NO_EXCEPTIONS
435
436 // FIXME: verify the number of blocks the function call
437 // is expected to allocate and detect any memory leaks
438 rw_check_leaks (str.get_allocator (), tcase.line,
439 std::size_t (-1), std::size_t (-1));
440
441 if (caught) {
442 // verify that an exception thrown during allocation
443 // didn't cause a change in the state of the object
445 __LINE__, tcase.line, caught);
446
447 if (0 == tcase.bthrow) {
448 // allow this call to operator new to succeed and try
449 // to make the next one to fail during the next call
450 // to the same function again
451 continue;
452 }
453 }
454 else if (0 < tcase.bthrow) {
455 rw_assert (caught == expected, 0, tcase.line,
456 "line %d. %{$FUNCALL} %{?}expected %s, caught %s"
457 "%{:}unexpectedly caught %s%{;}",
458 __LINE__, 0 != expected, expected, caught, caught);
459 }
460
461 break;
462 }
463
464#ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE
465
466 // verify that if exceptions are enabled and when capacity changes
467 // at least one exception is thrown
468 const std::size_t expect_throws = str_state.capacity_ < str.capacity ();
469
470#else // if defined (_RWSTD_NO_REPLACEABLE_NEW_DELETE)
471
472 const std::size_t expect_throws =
473 (StringIds::UserAlloc == func.alloc_id_)
474 ? str_state.capacity_ < str.capacity (): 0;
475
476#endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE
477
478 rw_assert (expect_throws == throw_count, 0, tcase.line,
479 "line %d: %{$FUNCALL}: expected exactly 1 %s exception "
480 "while changing capacity from %zu to %zu, got %zu",
481 __LINE__, exceptions [3],
482 str_state.capacity_, str.capacity (), throw_count);
483
484 // disable bad_alloc exceptions
485 *pst->throw_at_calls_ [0] = 0;
486 pal->throw_at_calls_ [pal->m_allocate] = 0;
487
488 if (wres != wres_buf)
489 delete[] wres;
490}
491
492
495
496int main (int argc, char** argv)
497{
498 static const StringTest
499 tests [] = {
500
501#undef TEST
502#define TEST(sig) { \
503 OpPlusEq (sig), sig ## _test_cases, \
504 sizeof sig ## _test_cases / sizeof *sig ## _test_cases \
505 }
506
507 TEST (cptr),
508 TEST (cstr),
509 TEST (val)
510 };
511
512 const std::size_t test_count = sizeof tests / sizeof *tests;
513
514 return rw_run_string_test (argc, argv, __FILE__,
515 "lib.string.op+=",
516 test_op_plus_eq, tests, test_count);
517}
#define charT
Definition 17.names.cpp:456
#define val
Definition 17.names.cpp:570
#define OpPlusEq(sig)
void test_op_plus_eq(charT, Traits *, Allocator *, const StringFunc &func, const StringTestCase &tcase)
#define TEST(str, src, res, bthrow)
std::char_traits< S > Traits
#define main
int caught
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)
UserChar make_char(char c, UserChar *)
Definition rw_char.h:74
_TEST_EXPORT char * rw_expand(char *, const char *, _RWSTD_SIZE_T=_RWSTD_SIZE_MAX, _RWSTD_SIZE_T *=0)
_RWSTD_SIZE_T * rw_get_call_counters(std::char_traits< charT > *, charT *)
Definition rw_char.h:495
_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
#define DEFINE_STRING_TEST_DISPATCH(fname)
Definition rw_strings.h:885
_TEST_EXPORT int rw_run_string_test(int, char **, const char *, const char *, StringTestFunc *, const StringTest *, _RWSTD_SIZE_T)
#define RW_ASSERT(expr)
static SharedAlloc * instance(SharedAlloc *=0)
_RWSTD_SIZE_T throw_at_calls_[n_funs]
_RWSTD_SIZE_T capacity_
Definition rw_strings.h:741
int assert_equal(const StringState &, int, int, const char *) const
_RWSTD_SIZE_T arg_len
Definition rw_strings.h:600
_RWSTD_SIZE_T str_len
Definition rw_strings.h:597
const char * str
Definition rw_strings.h:596
const char * arg
Definition rw_strings.h:599
_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
int arg
Definition locale.cpp:2806