Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
21.strings.cpp
Go to the documentation of this file.
1
27// expand _TEST_EXPORT macros
28#define _RWSTD_TEST_SRC
29
30#include <memory> // for allocator
31#include <string> // for char_traits
32
33#include <rw_strings.h>
34#include <rw_cmdopt.h> // for rw_enabled()
35#include <rw_driver.h> // for rw_info()
36#include <rw_allocator.h> // for UserAlloc
37#include <rw_char.h> // for rw_expand()
38#include <rw_printf.h> // for rw_asnprintf()
39
40#include <ctype.h> // for isdigit()
41#include <stdarg.h> // for va_arg, ...
42#include <stddef.h> // for size_t
43#include <stdlib.h> // for free()
44#include <string.h> // for memset()
45
46
48static const char
49_rw_this_file[] = __FILE__;
50
51
52static const char* const
53_rw_char_names[] = {
54 "char", "wchar_t", "UserChar"
55};
56
57
58static const char* const
59_rw_traits_names[] = {
60 "char_traits", "UserTraits"
61};
62
63
64static const char* const
65_rw_alloc_names[] = {
66 "allocator", "UserAlloc"
67};
68
69
70static const char* const
71_rw_iter_names[] = {
72 "",
73 "InputIterator", "ForwardIterator", "BidirectionalIterator",
74 "RandomAccessIterator",
75 "pointer", "const_pointer",
76 "iterator", "const_iterator",
77 "reverse_iterator", "const_reverse_iterator"
78};
79
80
81// order of elements depends on the values of StringIds::FuncId
82static const char* const
83_rw_func_names[] = {
84 "append", "assign", "erase", "insert", "replace", "operator+=", "find",
85 "rfind", "find_first_of", "find_last_of", "find_first_not_of",
86 "find_last_not_of", "compare", "substr", "operator[]", "at", "copy",
87 0 /* special handling for the ctor */, "operator=", "swap", "push_back",
88 "operator+", "operator==", "operator!=", "operator<", "operator<=",
89 "operator>", "operator>=", "size", "length", "max_size", "resize",
90 "capacity", "reserve", "clear", "empty", "begin", "end", "rbegin",
91 "rend", "c_str", "data", "get_allocator", "operator>>", "operator<<",
92 "getline"
93};
94
95
97const size_t MAX_OVERLOADS = 32;
98
99// disabled (-1) or explicitly enabled (+1) for each overload
100// of the string function being tested
101static int
102_rw_opt_func [MAX_OVERLOADS];
103
104// array of tests each exercising a single string function
105static const StringTest*
106_rw_string_tests;
107
108// size of the array above
109static size_t
110_rw_string_test_count;
111
112static int
113_rw_opt_char_types [sizeof _rw_char_names / sizeof *_rw_char_names];
114
115static int
116_rw_opt_traits_types [sizeof _rw_traits_names / sizeof *_rw_traits_names];
117
118static int
119_rw_opt_alloc_types [sizeof _rw_alloc_names / sizeof *_rw_alloc_names];
120
121static int
122_rw_opt_iter_types [sizeof _rw_iter_names / sizeof *_rw_iter_names];
123
124static int
125_rw_opt_no_exceptions;
126
127static int
128_rw_opt_no_exception_safety;
129
130static int
131_rw_opt_self_ref;
132
133
135static size_t
136_rw_get_func_inx (StringIds::OverloadId fid)
137{
138 size_t inx = _RWSTD_SIZE_MAX;
139
140 for (size_t i = 0; _rw_string_test_count; ++i) {
141 if (fid == _rw_string_tests [i].which) {
142 inx = i;
143 break;
144 }
145 }
146
147 RW_ASSERT (inx < _RWSTD_SIZE_MAX);
148
149 return inx;
150}
151
152
155assert_equal (const StringState &state, int line, int case_line,
156 const char *when) const
157{
158 const int equal =
159 data_ == state.data_
160 && size_ == state.size_
161 && capacity_ == state.capacity_;
162
163 rw_assert (equal, 0, case_line,
164 "line %d: %{$FUNCALL}: object state unexpectedly changed "
165 "from { %#p, %zu, %zu } to { %#p, %zu, %zu } (data, size, "
166 "capacity) after %s",
168 state.data_, state.size_, state.capacity_,
169 when);
170
171 return equal;
172}
173
174
176static const char*
177_rw_class_name (const StringFunc &func)
178{
179 if ( StringIds::DefaultTraits == func.traits_id_
180 && StringIds::DefaultAlloc == func.alloc_id_) {
181
182 if (StringIds::Char == func.char_id_)
183 return "string";
184
185 if (StringIds::WChar == func.char_id_)
186 return "wstring";
187 }
188
189 return "basic_string";
190}
191
192
194// appends the signature of the function specified by which
195// to the provided buffer; when the second argument is null,
196// appends the mnemonic representing the signature, including
197// the name of the function, as specified by the third argument
198static void
199_rw_sigcat (char **pbuf, size_t *pbufsize,
200 const StringFunc *func,
202{
203 // for convenience
204 typedef StringIds Ids;
205
206 if (func)
207 which = func->which_;
208
209 // determine whether the function is a member function
210 const bool is_member = 0 != (Ids::bit_member & int (which));
211
212 // get the bitmap describing the function's argument types
213 int argmap = (~Ids::bit_member & int (which)) >> Ids::fid_bits;
214
215 // determine whether the function is a const member function
216 bool is_const_member =
217 is_member && Ids::arg_cstr == (argmap & Ids::arg_mask);
218
219 // remove the *this argument if the function is a member
220 if (is_member)
221 argmap >>= Ids::arg_bits;
222
223 const char* funcname = 0;
224
225 if (0 == func) {
226 const int fid = StringIds::fid_mask & int (which);
227
228 switch (fid) {
229 // translate names with funky characters to mnemonics
230 case Ids::fid_ctor: funcname = "ctor"; break;
231 case Ids::fid_op_plus_eq: funcname = "op_plus_eq"; break;
232 case Ids::fid_op_index: funcname = "op_index"; break;
233 case Ids::fid_op_set: funcname = "op_assign"; break;
234 case Ids::fid_op_plus: funcname = "op_plus"; break;
235 case Ids::fid_op_equal: funcname = "op_equal"; break;
236 case Ids::fid_op_not_equal: funcname = "op_not_equal"; break;
237 case Ids::fid_op_less: funcname = "op_less"; break;
238 case Ids::fid_op_less_equal: funcname = "op_less_equal"; break;
239 case Ids::fid_op_greater: funcname = "op_greater"; break;
240 case Ids::fid_op_greater_equal: funcname = "op_greater_equal"; break;
241 case Ids::fid_extractor: funcname = "extractor"; break;
242 case Ids::fid_inserter: funcname = "inserter"; break;
243
244 case Ids::fid_compare:
245 case Ids::fid_copy:
246 case Ids::fid_find:
247 case Ids::fid_find_first_not_of:
248 case Ids::fid_find_first_of:
249 case Ids::fid_find_last_not_of:
250 case Ids::fid_find_last_of:
251 case Ids::fid_rfind:
252 case Ids::fid_substr:
253 case Ids::fid_c_str:
254 case Ids::fid_data:
255 case Ids::fid_get_allocator:
256 // prevent appending the "_const" bit to the mnemonics
257 // of member functions not overloaded on const
258 is_const_member = false;
259
260 // fall through
261
262 default: {
263 // determine the string function name (for brief output)
264 const size_t nfuncs =
265 sizeof _rw_func_names / sizeof *_rw_func_names;
266
267 RW_ASSERT (size_t (fid) < nfuncs);
268
269 funcname = _rw_func_names [fid];
270 RW_ASSERT (0 != funcname);
271 break;
272 }
273 }
274 }
275
276 // iterator name for member templates, empty string for other functions
277 const char* const iname = func ? _rw_iter_names [func->iter_id_] : "";
278
279 rw_asnprintf (pbuf, pbufsize,
280 "%{+}%{?}%s%{?}_const%{;}%{:}%{?}<%s>%{;}(%{;}",
281 0 == func, funcname, is_const_member, 0 != *iname, iname);
282
283 char iname_buf [80];
284 *iname_buf = '\0';
285
286 // iterate through the map of argument types one field at a time
287 // determining and formatting the type of each argument until
288 // void is reached
289 for (size_t argno = 0; argmap; ++argno, argmap >>= Ids::arg_bits) {
290
291 const char* pfx = "";
292 const char* sfx = "";
293
294 const int argtype = argmap & Ids::arg_mask;
295
296 const char* tname = 0;
297
298 if (func) {
299 switch (argtype) {
300 case Ids::arg_size: tname = "size_type"; break;
301 case Ids::arg_val: tname = "value_type"; break;
302 case Ids::arg_ptr: tname = "pointer"; break;
303 case Ids::arg_cptr: tname = "const_pointer"; break;
304 case Ids::arg_ref: tname = "reference"; break;
305 case Ids::arg_cref: tname = "const_reference"; break;
306 case Ids::arg_iter: tname = "iterator"; break;
307 case Ids::arg_citer: tname = "const_iterator"; break;
308 case Ids::arg_range:
309 if ('\0' == *iname_buf) {
310 strcpy (iname_buf, iname);
311 strcat (iname_buf, ", ");
312 strcat (iname_buf, iname);
313 }
314 tname = iname_buf;
315 break;
316
317 case Ids::arg_alloc: tname = "const allocator_type&"; break;
318 case Ids::arg_cstr:
319 pfx = "const ";
320 // fall through
321 case Ids::arg_str:
322 tname = _rw_class_name (*func);
323 sfx = "&";
324 break;
325
326 case Ids::arg_istream: tname = "istream&"; break;
327 case Ids::arg_ostream: tname = "ostream&"; break;
328 }
329 }
330 else {
331 switch (argtype) {
332 case Ids::arg_size: tname = "size"; break;
333 case Ids::arg_val: tname = "val"; break;
334 case Ids::arg_ptr: tname = "ptr"; break;
335 case Ids::arg_cptr: tname = "cptr"; break;
336 case Ids::arg_ref: tname = "ref"; break;
337 case Ids::arg_cref: tname = "cref"; break;
338 case Ids::arg_iter: tname = "iter"; break;
339 case Ids::arg_citer: tname = "citer"; break;
340 case Ids::arg_range: tname = "range"; break;
341 case Ids::arg_alloc: tname = "alloc"; break;
342 case Ids::arg_str: tname = "str"; break;
343 case Ids::arg_cstr: tname = "cstr"; break;
344 case Ids::arg_istream: tname = "istream"; break;
345 case Ids::arg_ostream: tname = "ostream"; break;
346 }
347 }
348
349 RW_ASSERT (0 != tname);
350
351 if ( 0 == func || is_member
352 || Ids::arg_str != argtype && Ids::arg_cstr != argtype
353 && Ids::arg_istream != argtype && Ids::arg_ostream != argtype) {
354 // append the name or mnemonic of the argument type
355 rw_asnprintf (pbuf, pbufsize, "%{+}%{?}_%{:}%{?}, %{;}%{;}%s%s%s",
356 0 == func, 0 < argno, pfx, tname, sfx);
357 }
358 else if (Ids::arg_istream == argtype || Ids::arg_ostream == argtype) {
359 // in non-member functions use ${{I|O}STREAM} to format
360 // the basic_{i|o}stream argument in order to expand
361 // its template argument list
362 rw_asnprintf (pbuf, pbufsize,
363 "%{+}%{?}, %{;}%{?}%{$ISTREAM}%{:}%{$OSTREAM}%{;}&",
364 0 < argno, Ids::arg_istream == argtype);
365 }
366 else {
367 // in non-member functions use ${CLASS} to format
368 // the basic_string argument in order to expand
369 // its template argument list
370 rw_asnprintf (pbuf, pbufsize,
371 "%{+}%{?}, %{;}%{?}const %{;}%{$CLASS}&",
372 0 < argno, Ids::arg_cstr == argtype);
373
374 }
375 }
376
377 if (func)
378 rw_asnprintf (pbuf, pbufsize, "%{+})%{?} const%{;}", is_const_member);
379}
380
381
383// returns the zero-based index of the argument type specified
384// by arg in the function signature given by which
385static int
386_rw_argno (StringIds::OverloadId which, int arg)
387{
388 // get the bitmap describing the function's argument types
389 int argmap = (which & ~StringIds::bit_member) >> StringIds::fid_bits;
390
391 int argno = 0;
392
393 // iterate over argument types looking for the first one
394 // that equals arg
395 for (; argmap; argmap >>= StringIds::arg_bits, ++argno) {
396 if ((argmap & StringIds::arg_mask) == arg) {
397 return argno;
398 }
399 }
400
401 // return -1 when the function doesn't take an argument
402 // of the specified type
403 return -1;
404}
405
406
408_TEST_EXPORT void
410 const StringTestCase *pcase /* = 0 */)
411{
412 char* buf = 0;
413 size_t bufsize = 0;
414
415 const char* const class_name = _rw_class_name (func);
416
417 if (0 == pcase) {
418 // set the {charT}, {Traits}, and {Allocator} environment
419 // variables to the name of the character type and the
420 // Traits and Allocator specializations
421 rw_fprintf (0, "%{$charT!:*}", _rw_char_names [func.char_id_]);
422
423 rw_fprintf (0, "%{$Traits!:*}", _rw_traits_names [func.traits_id_]);
424
425 rw_fprintf (0, "%{$Allocator!:*}", _rw_alloc_names [func.alloc_id_]);
426
427 rw_fprintf (0, "%{$Iterator!:*}", _rw_iter_names [func.iter_id_]);
428
429 // set the {CLASS}, {FUNC}, and {FUNCSIG} environment variables
430 // to the name of the specialization of the template, the name
431 // of the string function, and the name of the overload of the
432 // string function, respectively, when no test case is given
433
434 if ( StringIds::DefaultTraits == func.traits_id_
435 && StringIds::DefaultAlloc == func.alloc_id_
436 && ( StringIds::Char == func.char_id_
437 || StringIds::WChar == func.char_id_)) {
438 // format std::string and std::wstring
439 rw_asnprintf (&buf, &bufsize, "std::%{?}w%{;}string",
440 StringIds::WChar == func.char_id_);
441 }
442 else {
443 // format std::basic_string specializations other than
444 // std::string and std::wstring, leaving out the name
445 // of the default allocator for brevity
446 rw_asnprintf (&buf, &bufsize,
447 "std::basic_string<%s, %s<%1$s>%{?}, %s<%1$s>%{;}>",
448 _rw_char_names [func.char_id_],
449 _rw_traits_names [func.traits_id_],
450 StringIds::DefaultAlloc != func.alloc_id_,
451 _rw_alloc_names [func.alloc_id_]);
452 }
453
454 // set the {CLASS} variable to the name of the specialization
455 // of basic_string
456 rw_fprintf (0, "%{$CLASS!:*}", buf);
457 free (buf);
458 buf = 0;
459 bufsize = 0;
460
461 // set the {ISTREAM} environment variable
462 // to the name of the specialization of the template basic_istream
463
464 if ( StringIds::DefaultTraits == func.traits_id_
465 && ( StringIds::Char == func.char_id_
466 || StringIds::WChar == func.char_id_)) {
467 // format std::istream and std::wistream
468 rw_asnprintf (&buf, &bufsize, "std::%{?}w%{;}istream",
469 StringIds::WChar == func.char_id_);
470 }
471 else {
472 // format std::basic_istream specializations other than
473 // std::istream and std::wistream
474 rw_asnprintf (&buf, &bufsize,
475 "std::basic_istream<%s, %s<%1$s>>",
476 _rw_char_names [func.char_id_],
477 _rw_traits_names [func.traits_id_]);
478 }
479
480 rw_fprintf (0, "%{$ISTREAM!:*}", buf);
481 free (buf);
482 buf = 0;
483 bufsize = 0;
484
485 // set the {OSTREAM} environment variable
486 // to the name of the specialization of the template basic_ostream
487
488 if ( StringIds::DefaultTraits == func.traits_id_
489 && ( StringIds::Char == func.char_id_
490 || StringIds::WChar == func.char_id_)) {
491 // format std::ostream and std::wostream
492 rw_asnprintf (&buf, &bufsize, "std::%{?}w%{;}ostream",
493 StringIds::WChar == func.char_id_);
494 }
495 else {
496 // format std::basic_ostream specializations other than
497 // std::ostream and std::wostream
498 rw_asnprintf (&buf, &bufsize,
499 "std::basic_ostream<%s, %s<%1$s>>",
500 _rw_char_names [func.char_id_],
501 _rw_traits_names [func.traits_id_]);
502 }
503
504 rw_fprintf (0, "%{$OSTREAM!:*}", buf);
505 free (buf);
506 buf = 0;
507 bufsize = 0;
508
509 // determine the string function name
510 const size_t funcinx = StringIds::fid_mask & int (func.which_);
511 const size_t nfuncs = sizeof _rw_func_names / sizeof *_rw_func_names;
512
513 RW_ASSERT (funcinx < nfuncs);
514
515 // get the undecorated function name; ctors are treated
516 // specially so that we can have string, wstring, or
517 // basic_string, depending on the template arguments
518 const char* const funcname = _rw_func_names [funcinx] ?
519 _rw_func_names [funcinx] : class_name;
520
521 // determine whether the function is a member function
522 const bool is_member =
523 0 != (StringIds::bit_member & int (func.which_));
524
525 // set the {FUNC} variable to the unqualified/undecorated
526 // name of the string function (member or otherwise)
527 rw_asnprintf (&buf, &bufsize, "%{?}std::%{;}%s",
528 !is_member, funcname);
529
530 rw_fprintf (0, "%{$FUNC!:*}", buf);
531
532 // append the function signature
533 _rw_sigcat (&buf, &bufsize, &func);
534
535 rw_fprintf (0, "%{$FUNCSIG!:*}", buf);
536 free (buf);
537
538 return;
539 }
540
541 // do the function call arguments reference *this?
542 const bool self = 0 == pcase->arg;
543
544 char str_buf [256];
545 char arg_buf [256];
546
547 char *str;
548 char *arg;
549
550 size_t str_len = sizeof str_buf;
551 size_t arg_len = sizeof arg_buf;
552
553 if (pcase->str)
554 str = rw_expand (str_buf, pcase->str, pcase->str_len, &str_len);
555 else
556 str = 0;
557
558 if (pcase->arg)
559 arg = rw_expand (arg_buf, pcase->arg, pcase->arg_len, &arg_len);
560 else
561 arg = 0;
562
563 // determine whether the function is a member function
564 const bool is_member =
565 0 != (StringIds::bit_member & int (func.which_));
566
567 // determine whether the function is a ctor
568 const bool is_ctor =
569 StringIds::fid_ctor == (StringIds::fid_mask & int (func.which_));
570
571 if (is_ctor) {
572 // for ctors append just the class name here
573 // the class name will inserted below during argument
574 // formatting
575 rw_asnprintf (&buf, &bufsize, "%{$CLASS}::%s", class_name);
576 }
577 else if (is_member) {
578 // for other members append the ctor argument(s) followed
579 // by the string member function name
580 rw_asnprintf (&buf, &bufsize,
581 "%{$CLASS} (%{?}%{#*s}%{;}).%{$FUNC}",
582 str != 0, int (str_len), str);
583 }
584 else {
585 // for non-members append just the function name here
586 // the class name will inserted below during argument
587 // formatting
588 rw_asnprintf (&buf, &bufsize, "%{$FUNC}");
589 }
590
591 // compute the end offsets for convenience
592 const size_t range1_end = pcase->off + pcase->size;
593 const size_t range2_end = pcase->off2 + pcase->size2;
594
595 // determine whether the function takes an allocator_type argument
596 const bool use_alloc = 0 < _rw_argno (func.which_, StringIds::arg_alloc);
597
598 // format and append string function arguments abbreviating complex
599 // expressions as much as possible to make them easy to understand
600 switch (func.which_) {
601 case StringIds::append_cptr:
602 case StringIds::assign_cptr:
603 case StringIds::op_plus_eq_cptr:
604 case StringIds::find_cptr:
605 case StringIds::rfind_cptr:
606 case StringIds::find_first_of_cptr:
607 case StringIds::find_last_of_cptr:
608 case StringIds::find_first_not_of_cptr:
609 case StringIds::find_last_not_of_cptr:
610 case StringIds::compare_cptr:
611 case StringIds::op_set_cptr:
612 case StringIds::ctor_cptr:
613 case StringIds::ctor_cptr_alloc:
614 // format self-referential ptr argument without size as c_str()
615 rw_asnprintf (&buf, &bufsize,
616 "%{+} (%{?}c_str()%{:}%{#*s}%{;}"
617 "%{?}, const allocator_type&%{;})",
618 self, int (arg_len), arg, use_alloc);
619 break;
620
621 case StringIds::append_cstr:
622 case StringIds::assign_cstr:
623 case StringIds::op_plus_eq_cstr:
624 case StringIds::find_cstr:
625 case StringIds::rfind_cstr:
626 case StringIds::find_first_of_cstr:
627 case StringIds::find_last_of_cstr:
628 case StringIds::find_first_not_of_cstr:
629 case StringIds::find_last_not_of_cstr:
630 case StringIds::compare_cstr:
631 case StringIds::ctor_cstr:
632 case StringIds::op_set_cstr:
633 case StringIds::swap_str:
634 // format self-referential str argument as *this
635 rw_asnprintf (&buf, &bufsize,
636 "%{+} (%{?}*this%{:}%s(%{#*s})%{;}"
637 "%{?}, const allocator_type&%{;})",
638 self, class_name, int (arg_len), arg, use_alloc);
639 break;
640
641 case StringIds::append_cptr_size:
642 case StringIds::assign_cptr_size:
643 case StringIds::copy_ptr_size:
644 case StringIds::ctor_cptr_size:
645 case StringIds::ctor_cptr_size_alloc:
646 // format self-referential ptr argument with size as data()
647 rw_asnprintf (&buf, &bufsize, "%{+} ("
648 "%{?}data()%{:}%{#*s}%{;}, %zu"
649 "%{?}, const allocator_type&%{;})",
650 self, int (arg_len), arg, pcase->size, use_alloc);
651 break;
652
653 case StringIds::find_cptr_size:
654 case StringIds::rfind_cptr_size:
655 case StringIds::find_first_of_cptr_size:
656 case StringIds::find_last_of_cptr_size:
657 case StringIds::find_first_not_of_cptr_size:
658 case StringIds::find_last_not_of_cptr_size:
659 // format self-referential ptr argument with size as data()
660 rw_asnprintf (&buf, &bufsize, "%{+} ("
661 "%{?}data()%{:}%{#*s}%{;}, %zu)",
662 self, int (arg_len), arg, pcase->off);
663 break;
664
665 case StringIds::find_cstr_size:
666 case StringIds::rfind_cstr_size:
667 case StringIds::find_first_of_cstr_size:
668 case StringIds::find_last_of_cstr_size:
669 case StringIds::find_first_not_of_cstr_size:
670 case StringIds::find_last_not_of_cstr_size:
671 case StringIds::ctor_cstr_size:
672 case StringIds::ctor_cstr_size_alloc:
673 // format self-referential str argument as *this
674 rw_asnprintf (&buf, &bufsize, "%{+} ("
675 "%{?}*this%{:}%s(%{#*s})%{;}, %zu"
676 "%{?}, const allocator_type%{;})",
677 self, class_name, int (arg_len), arg, pcase->off,
678 use_alloc);
679 break;
680
681 case StringIds::find_cptr_size_size:
682 case StringIds::rfind_cptr_size_size:
683 case StringIds::find_first_of_cptr_size_size:
684 case StringIds::find_last_of_cptr_size_size:
685 case StringIds::find_first_not_of_cptr_size_size:
686 case StringIds::find_last_not_of_cptr_size_size:
687 // format self-referential ptr argument with size as data()
688 rw_asnprintf (&buf, &bufsize, "%{+} ("
689 "%{?}data()%{:}%{#*s}%{;}, %zu, %zu)",
690 self, int (arg_len), arg,
691 pcase->off, pcase->size);
692 break;
693
694 case StringIds::copy_ptr_size_size:
695 // format self-referential ptr argument with size as data()
696 rw_asnprintf (&buf, &bufsize, "%{+} ("
697 "%{?}data()%{:}%{#*s}%{;}, %zu, %zu)",
698 self, int (arg_len), arg,
699 pcase->size, pcase->off);
700 break;
701
702 case StringIds::append_cstr_size_size:
703 case StringIds::assign_cstr_size_size:
704 case StringIds::ctor_cstr_size_size:
705 case StringIds::ctor_cstr_size_size_alloc:
706 // format self-referential str argument as *this
707 rw_asnprintf (&buf, &bufsize, "%{+} ("
708 "%{?}*this%{:}%s(%{#*s})%{;}, %zu, %zu"
709 "%{?}, const allocator_type%{;})",
710 self, class_name, int (arg_len), arg,
711 pcase->off, pcase->size, use_alloc);
712 break;
713
714 case StringIds::append_size_val:
715 case StringIds::assign_size_val:
716 case StringIds::ctor_size_val:
717 case StringIds::ctor_size_val_alloc:
718 rw_asnprintf (&buf, &bufsize,
719 "%{+} (%zu, %{#c}%{?}, const allocator_type&%{;})",
720 pcase->size, pcase->val, use_alloc);
721 break;
722
723 case StringIds::append_range:
724 case StringIds::assign_range:
725 case StringIds::ctor_range:
726 case StringIds::ctor_range_alloc:
727 rw_asnprintf (&buf, &bufsize, "%{+}<%{$Iterator:-Iterator}>("
728 "%{?}begin()%{:}%{$Iterator:-Iterator}(%{#*s})%{;}"
729 "%{?} + %zu%{;}, "
730 "%{?}begin()%{:}%{$Iterator:-Iterator}(...)%{;}"
731 "%{?} + %zu%{;}"
732 "%{?}, const allocator_type&%{;})",
733 self, int (arg_len), arg,
734 0 != pcase->off2, pcase->off2,
735 self, 0 != range2_end, range2_end, use_alloc);
736 break;
737
738 case StringIds::insert_size_cptr:
739 // format self-referential ptr argument without size as c_str()
740 rw_asnprintf (&buf, &bufsize,
741 "%{+} (%zu, %{?}c_str()%{:}%{#*s}%{;})",
742 pcase->off, self, int (arg_len), arg);
743 break;
744
745 case StringIds::insert_size_cstr:
746 // format self-referential str argument as *this
747 rw_asnprintf (&buf, &bufsize,
748 "%{+} (%zu, %{?}*this%{:}%s(%{#*s})%{;})",
749 pcase->off, self, class_name, int (arg_len), arg);
750 break;
751
752 case StringIds::insert_size_cptr_size:
753 // format self-referential ptr argument with size as data()
754 rw_asnprintf (&buf, &bufsize, "%{+} ("
755 "%zu, %{?}data()%{:}%{#*s}%{;}, %zu)",
756 pcase->off, self, int (arg_len), arg,
757 pcase->size2);
758 break;
759
760 case StringIds::insert_size_cstr_size_size:
761 // format self-referential str argument as *this
762 rw_asnprintf (&buf, &bufsize, "%{+} ("
763 "%zu, %{?}*this%{:}%s(%{#*s})%{;}, %zu, %zu)",
764 pcase->off, self, class_name, int (arg_len), arg,
765 pcase->off2, pcase->size2);
766 break;
767
768 case StringIds::insert_size_size_val:
769 rw_asnprintf (&buf, &bufsize,
770 "%{+} (%zu, %zu, %{#c})",
771 pcase->off, pcase->size2, pcase->val);
772 break;
773
774 case StringIds::insert_iter_val:
775 rw_asnprintf (&buf, &bufsize,
776 "%{+} (begin()%{?} + %zu%{;}, %{#c})",
777 0 != pcase->off, pcase->off, pcase->val);
778 break;
779
780 case StringIds::insert_iter_size_val:
781 rw_asnprintf (&buf, &bufsize,
782 "%{+} (begin()%{?} + %zu%{;}, %zu, %{#c})",
783 0 != pcase->off, pcase->off, pcase->size, pcase->val);
784 break;
785
786 case StringIds::insert_iter_range:
787 rw_asnprintf (&buf, &bufsize, "%{+}<%{$Iterator:-Iterator}>"
788 "(begin()%{?} + %zu%{;}, "
789 "%{?}begin()%{:}%{$Iterator:-Iterator}(%{#*s})%{;}"
790 "%{?} + %zu%{;}, "
791 "%{?}begin()%{:}%{$Iterator:-Iterator}(...)"
792 "%{?} + %zu%{;})",
793 0 != pcase->off, pcase->off,
794 self, int (arg_len), arg,
795 0 != pcase->off2, pcase->off2,
796 self, 0 != range2_end, range2_end);
797 break;
798
799 case StringIds::replace_size_size_cptr:
800 case StringIds::compare_size_size_cptr:
801 // format self-referential ptr argument without size as c_str()
802 rw_asnprintf (&buf, &bufsize, "%{+} ("
803 "%zu, %zu, %{?}c_str()%{:}%{#*s}%{;})",
804 pcase->off, pcase->size, self,
805 int (arg_len), arg);
806 break;
807
808 case StringIds::replace_size_size_cstr:
809 case StringIds::compare_size_size_cstr:
810 // format self-referential str argument as *this
811 rw_asnprintf (&buf, &bufsize, "%{+} ("
812 "%zu, %zu, %{?}*this%{:}%s(%{#*s})%{;})",
813 pcase->off, pcase->size, self, class_name,
814 int (arg_len), arg);
815 break;
816
817 case StringIds::replace_size_size_cptr_size:
818 case StringIds::compare_size_size_cptr_size:
819 // format self-referential ptr argument with size as data()
820 rw_asnprintf (&buf, &bufsize, "%{+} ("
821 "%zu, %zu, %{?}data()%{:}%{#*s}%{;}, %zu)",
822 pcase->off, pcase->size, self,
823 int (arg_len), arg, pcase->size2);
824 break;
825
826 case StringIds::replace_size_size_cstr_size_size:
827 case StringIds::compare_size_size_cstr_size_size:
828 // format self-referential str argument as *this
829 rw_asnprintf (&buf, &bufsize, "%{+} (%zu, %zu, "
830 "%{?}*this%{:}%s(%{#*s})%{;}, %zu, %zu)",
831 pcase->off, pcase->size,
832 self, class_name, int (arg_len), arg,
833 pcase->off2, pcase->size2);
834 break;
835
836 case StringIds::replace_size_size_size_val:
837 rw_asnprintf (&buf, &bufsize,
838 "%{+} (%zu, %zu, %zu, %{#c})",
839 pcase->off, pcase->size, pcase->size2, pcase->val);
840 break;
841
842 case StringIds::replace_iter_iter_cptr:
843 // format self-referential ptr argument without size as c_str()
844 rw_asnprintf (&buf, &bufsize, "%{+} (begin()%{?} + %zu%{;}, "
845 "begin()%{?} + %zu%{;}, "
846 "%{?}c_str()%{:}%{#*s}%{;})",
847 0 != pcase->off, pcase->off,
848 0 != range1_end, range1_end,
849 self, int (arg_len), arg);
850 break;
851
852 case StringIds::replace_iter_iter_cstr:
853 // format self-referential str argument as *this
854 rw_asnprintf (&buf, &bufsize, "%{+} (begin()%{?} + %zu%{;}, "
855 "begin()%{?} + %zu%{;}, "
856 "%{?}*this%{:}%s(%{#*s})%{;})",
857 0 != pcase->off, pcase->off,
858 0 != range1_end, range1_end,
859 self, class_name, int (arg_len), arg);
860 break;
861
862 case StringIds::replace_iter_iter_cptr_size:
863 // format self-referential ptr argument with size as data()
864 rw_asnprintf (&buf, &bufsize, "%{+} (begin()%{?} + %zu%{;}, "
865 "begin()%{?} + %zu%{;}, "
866 "%{?}data()%{:}%{#*s}%{;}, %zu)",
867 0 != pcase->off, pcase->off,
868 0 != range1_end, range1_end,
869 self, int (arg_len), arg, pcase->size2);
870 break;
871
872 case StringIds::replace_iter_iter_size_val:
873 rw_asnprintf (&buf, &bufsize,
874 "%{+} (begin()%{?} + %zu%{;}, begin()%{? + %zu%{;}, "
875 "%zu, %{#c})",
876 0 != pcase->off, pcase->off, 0 != range1_end, range1_end,
877 pcase->size2, pcase->val);
878 break;
879
880 case StringIds::replace_iter_iter_range:
881 rw_asnprintf (&buf, &bufsize, "%{+}<%{$Iterator:-Iterator}>("
882 "begin()%{?} + %zu%{;}, "
883 "begin()%{?} + %zu%{;}, "
884 "%{?}begin()%{:}%{$Iterator:-Iterator}(%{#*s})%{;}"
885 "%{?} + %zu%{;}, "
886 "%{?}begin()%{:}%{$Iterator:-Iterator}(...)%{;}"
887 "%{?} + %zu%{;})",
888 0 != pcase->off, pcase->off,
889 0 != range1_end, range1_end,
890 self, int (arg_len), arg,
891 0 != pcase->off2, pcase->off2,
892 self, 0 != range2_end, range2_end);
893 break;
894
895 case StringIds::op_plus_eq_val:
896 case StringIds::find_val:
897 case StringIds::rfind_val:
898 case StringIds::find_first_of_val:
899 case StringIds::find_last_of_val:
900 case StringIds::find_first_not_of_val:
901 case StringIds::find_last_not_of_val:
902 case StringIds::op_set_val:
903 case StringIds::push_back_val:
904 rw_asnprintf (&buf, &bufsize,
905 "%{+} (%{#c})", pcase->val);
906 break;
907
908 case StringIds::find_val_size:
909 case StringIds::rfind_val_size:
910 case StringIds::find_first_of_val_size:
911 case StringIds::find_last_of_val_size:
912 case StringIds::find_first_not_of_val_size:
913 case StringIds::find_last_not_of_val_size:
914 rw_asnprintf (&buf, &bufsize,
915 "%{+} (%{#c}, %zu)", pcase->val, pcase->off);
916 break;
917
918 case StringIds::erase_void:
919 case StringIds::substr_void:
920 case StringIds::ctor_void:
921 case StringIds::size_void:
922 case StringIds::length_void:
923 case StringIds::max_size_void:
924 case StringIds::capacity_void:
925 case StringIds::reserve_void:
926 case StringIds::clear_void:
927 case StringIds::empty_void:
928 case StringIds::begin_void:
929 case StringIds::end_void:
930 case StringIds::rbegin_void:
931 case StringIds::rend_void:
932 case StringIds::c_str_void:
933 case StringIds::data_void:
934 case StringIds::get_allocator_void:
935 rw_asnprintf (&buf, &bufsize,
936 "%{+} ()");
937 break;
938
939 case StringIds::begin_const_void:
940 case StringIds::end_const_void:
941 case StringIds::rbegin_const_void:
942 case StringIds::rend_const_void:
943 rw_asnprintf (&buf, &bufsize,
944 "%{+} () const");
945 break;
946
947 case StringIds::ctor_alloc:
948 rw_asnprintf (&buf, &bufsize,
949 "%{+} (const allocator_type&)");
950 break;
951
952 case StringIds::erase_size:
953 case StringIds::substr_size:
954 case StringIds::op_index_size:
955 case StringIds::at_size:
956 rw_asnprintf (&buf, &bufsize,
957 "%{+} (%zu)", pcase->off);
958 break;
959
960 case StringIds::op_index_const_size:
961 case StringIds::at_const_size:
962 rw_asnprintf (&buf, &bufsize,
963 "%{+} (%zu) const", pcase->off);
964 break;
965
966 case StringIds::erase_size_size:
967 case StringIds::substr_size_size:
968 rw_asnprintf (&buf, &bufsize,
969 "%{+} (%zu, %zu)", pcase->off, pcase->size);
970 break;
971
972 case StringIds::erase_iter:
973 rw_asnprintf (&buf, &bufsize,
974 "%{+} (begin()%{?} + %zu%{;})",
975 0 != pcase->off, pcase->off);
976 break;
977
978 case StringIds::erase_iter_iter:
979 rw_asnprintf (&buf, &bufsize,
980 "%{+} (begin()%{?} + %zu%{;}, begin()%{?} + %zu%{;})",
981 0 != pcase->off, pcase->off,
982 0 != range1_end, range1_end);
983 break;
984
985 case StringIds::op_plus_cptr_cstr:
986 case StringIds::op_equal_cptr_cstr:
987 case StringIds::op_not_equal_cptr_cstr:
988 case StringIds::op_less_cptr_cstr:
989 case StringIds::op_less_equal_cptr_cstr:
990 case StringIds::op_greater_cptr_cstr:
991 case StringIds::op_greater_equal_cptr_cstr:
992 // format zero ptr argument without size as arg.c_str()
993 rw_asnprintf (&buf, &bufsize,
994 "%{+} (%{?}arg2.c_str()%{:}%{#*s}%{;}, "
995 "%{$CLASS}(%{#*s}))",
996 0 == str, int (str_len), str, int (arg_len), arg);
997 break;
998
999 case StringIds::op_plus_cstr_cptr:
1000 case StringIds::op_equal_cstr_cptr:
1001 case StringIds::op_not_equal_cstr_cptr:
1002 case StringIds::op_less_cstr_cptr:
1003 case StringIds::op_less_equal_cstr_cptr:
1004 case StringIds::op_greater_cstr_cptr:
1005 case StringIds::op_greater_equal_cstr_cptr:
1006 // format zero ptr argument without size as arg.c_str()
1007 rw_asnprintf (&buf, &bufsize,
1008 "%{+} (%{$CLASS}(%{#*s}), "
1009 "%{?}arg1.c_str()%{:}%{#*s}%{;})",
1010 int (str_len), str, self, int (arg_len), arg);
1011 break;
1012
1013 case StringIds::op_plus_cstr_cstr:
1014 case StringIds::op_equal_cstr_cstr:
1015 case StringIds::op_not_equal_cstr_cstr:
1016 case StringIds::op_less_cstr_cstr:
1017 case StringIds::op_less_equal_cstr_cstr:
1018 case StringIds::op_greater_cstr_cstr:
1019 case StringIds::op_greater_equal_cstr_cstr:
1020 // format zero str argument without size as arg
1021 rw_asnprintf (&buf, &bufsize,
1022 "%{+} (%{?}arg2%{:}%{$CLASS}(%{#*s})%{;}, "
1023 "%{?}arg1%{:}%{$CLASS}(%{#*s})%{;})",
1024 0 == str, int (str_len), str, self, int (arg_len), arg);
1025 break;
1026
1027 case StringIds::op_plus_cstr_val:
1028 rw_asnprintf (&buf, &bufsize,
1029 "%{+} (%{$CLASS}(%{#*s}), %{#c})",
1030 int (arg_len), arg, pcase->val);
1031 break;
1032
1033 case StringIds::op_plus_val_cstr:
1034 rw_asnprintf (&buf, &bufsize,
1035 "%{+} (%{#c}, %{$CLASS}(%{#*s}))",
1036 pcase->val, int (arg_len), arg);
1037 break;
1038
1039 case StringIds::extractor_istream_str:
1040 case StringIds::getline_istream_str:
1041 rw_asnprintf (&buf, &bufsize,
1042 "%{+} (%{$ISTREAM}&, %{$CLASS}(%{?}%{#*s}%{;}))",
1043 0 < str_len, int (str_len), str);
1044 break;
1045
1046 case StringIds::getline_istream_str_val:
1047 rw_asnprintf (&buf, &bufsize,
1048 "%{+} (%{$ISTREAM}&, %{$CLASS}(%{?}%{#*s}%{;}), %{#c})",
1049 0 < str_len, int (str_len), str, pcase->val);
1050 break;
1051
1052 case StringIds::inserter_ostream_cstr:
1053 rw_asnprintf (&buf, &bufsize,
1054 "%{+} (%{$OSTREAM}&, %{$CLASS}(%{?}%{#*s}%{;}))",
1055 0 < str_len, int (str_len), str);
1056 break;
1057
1058 case StringIds::resize_size_val:
1059 rw_asnprintf (&buf, &bufsize,
1060 "%{+} (%zu, %{#c})", pcase->size, pcase->val);
1061 break;
1062
1063 case StringIds::resize_size:
1064 case StringIds::reserve_size:
1065 rw_asnprintf (&buf, &bufsize,
1066 "%{+} (%zu)", pcase->size);
1067 break;
1068
1069 default:
1070 RW_ASSERT (!"test logic error: unknown overload");
1071 }
1072
1073 rw_fprintf (0, "%{$FUNCALL!:*}", buf);
1074 free (buf);
1075
1076 if (str != str_buf)
1077 delete[] str;
1078
1079 if (arg != arg_buf)
1080 delete[] arg;
1081}
1082
1083
1085// helper function to reverse substring in the resulting sequence
1088 size_t off, size_t ext)
1089{
1090 // expand expected results
1091 size_t res_len = 0;
1092 char* const new_res = rw_expand ((char*)0, tsrc.res, tsrc.nres, &res_len);
1093
1094 // reverse them
1095 const size_t res_off = off;
1096 const size_t res_ext = (ext < res_len ? ext : res_len) - 1;
1097
1098 char* beg = new_res + res_off;
1099 char* end = beg + res_ext;
1100
1101 for (; beg < end; ++beg, --end) {
1102 const char tmp = *beg;
1103 *beg = *end;
1104 *end = tmp;
1105 }
1106
1107 // form new test case
1108 const StringTestCase new_case = {
1109 tsrc.line, tsrc.off, tsrc.size, tsrc.off2,
1110 tsrc.size2, tsrc.val, tsrc.str, tsrc.str_len,
1111 tsrc.arg, tsrc.arg_len, new_res, res_len, tsrc.bthrow
1112 };
1113
1114 return new_case;
1115}
1116
1117
1118template <class charT, class Traits, class Allocator>
1119void
1121 VoidFunc* const *farray,
1122 const StringFunc &func,
1123 const StringTestCase &tcase)
1124{
1125 typedef StringTestCaseData<charT> Data;
1126 typedef void TestFunc (charT*, Traits*, Allocator*, const Data&);
1127
1128 const size_t inx = func.char_id_ * 4 + func.traits_id_ * 2 + func.alloc_id_;
1129
1130 TestFunc* const tfunc = _RWSTD_REINTERPRET_CAST (TestFunc*, farray [inx]);
1131
1132 if (0 == tfunc) {
1133 rw_error (0, __FILE__, __LINE__,
1134 "logic error: null test function for %{$FUNCSIG}");
1135 return;
1136 }
1137
1138 const bool reverse_iter =
1139 StringIds::ReverseIterator == func.iter_id_
1141
1142 const Data tdata (func, tcase);
1143
1144 if (reverse_iter) {
1145 // special processing for reverse iterators
1146
1147 const size_t func_id = StringIds::fid_mask & int (tdata.func_.which_);
1148
1149 const bool like_ctor = StringIds::fid_ctor == func_id
1150 || StringIds::fid_assign == func_id;
1151
1152 // ctor and assignment operator require the full string reverse
1153 const size_t off = like_ctor ? 0 : tdata.off1_;
1154 const size_t ext = like_ctor ? tdata.reslen_ : tdata.ext2_;
1155
1156 const StringTestCase rev_tcase =
1157 ::_rw_reverse_results (tcase, off, ext);
1158
1159 const Data rev_tdata (func, rev_tcase);
1160
1161 tfunc ((charT*)0, (Traits*)0, (Allocator*)0, rev_tdata);
1162
1163 // clean up allocated memory, if any
1164 delete[] rev_tcase.res;
1165 }
1166 else
1167 tfunc ((charT*)0, (Traits*)0, (Allocator*)0, tdata);
1168}
1169
1170
1171template <class charT, class Traits>
1172void
1174 VoidFunc* const *farray,
1175 const StringFunc &func,
1176 const StringTestCase &tcase)
1177{
1178 if (StringIds::DefaultAlloc == func.alloc_id_) {
1179 typedef std::allocator<charT> Alloc;
1180 _rw_dispatch ((charT*)0, (Traits*)0, (Alloc*)0, farray, func, tcase);
1181 }
1182 else if (StringIds::UserAlloc == func.alloc_id_) {
1183 typedef UserAlloc<charT> Alloc;
1184 _rw_dispatch ((charT*)0, (Traits*)0, (Alloc*)0, farray, func, tcase);
1185 }
1186 else {
1187 RW_ASSERT (!"logic error: unknown Allocator argument");
1188 }
1189}
1190
1191
1192template <class charT>
1193void
1195 VoidFunc* const *farray,
1196 const StringFunc &func,
1197 const StringTestCase &tcase)
1198{
1199 if (StringIds::DefaultTraits == func.traits_id_) {
1200 typedef std::char_traits<charT> Traits;
1201 _rw_dispatch ((charT*)0, (Traits*)0, farray, func, tcase);
1202 }
1203 else if (StringIds::UserTraits == func.traits_id_) {
1204 typedef UserTraits<charT> Traits;
1205 _rw_dispatch ((charT*)0, (Traits*)0, farray, func, tcase);
1206 }
1207 else {
1208 RW_ASSERT (!"logic error: unknown Traits argument");
1209 }
1210
1211}
1212
1213
1214static void
1215_rw_dispatch (VoidFunc* const *farray,
1216 const StringFunc &func,
1217 const StringTestCase &tcase)
1218{
1219 if (StringIds::Char == func.char_id_) {
1220 _rw_dispatch ((char*)0, farray, func, tcase);
1221 }
1222 else if (StringIds::WChar == func.char_id_) {
1223 _rw_dispatch ((wchar_t*)0, farray, func, tcase);
1224 }
1225 else if (StringIds::UChar == func.char_id_) {
1226 if (StringIds::DefaultTraits == func.traits_id_) {
1227 RW_ASSERT (!"logic error: std::char_traits<UserChar> not allowed");
1228 }
1229 else if (StringIds::UserTraits == func.traits_id_) {
1231 _rw_dispatch ((UserChar*)0, (Traits*)0, farray, func, tcase);
1232 }
1233 }
1234 else {
1235 RW_ASSERT (!"logic error: unknown charT argument");
1236 }
1237}
1238
1239
1241// exercise a single test case for the given function
1242static void
1243_rw_test_case (const StringFunc &func,
1244 const StringTestCase &tcase,
1245 StringTestFunc *test_callback,
1246 VoidFunc* const *farray)
1247{
1248 // check to see if this is an exception safety test case
1249 // and avoid running it when exception safety has been
1250 // disabled via a command line option
1251 if (-1 == tcase.bthrow && _rw_opt_no_exception_safety) {
1252
1253 // issue only the first note
1254 rw_note (1 < _rw_opt_no_exception_safety++, _rw_this_file, __LINE__,
1255 "exception safety tests disabled");
1256 return;
1257 }
1258
1259 // check to see if this is a test case that involves the throwing
1260 // of an exception and avoid running it when exceptions have been
1261 // disabled
1262 if (tcase.bthrow && _rw_opt_no_exceptions) {
1263
1264 // issue only the first note
1265 rw_note (1 < _rw_opt_no_exceptions++, _rw_this_file, __LINE__,
1266 "exception tests disabled");
1267 return;
1268 }
1269
1270 const bool self_ref = 0 == tcase.arg;
1271
1272 // check for tests exercising self-referential modifications
1273 // (e.g., insert(1, *this))
1274 if (_rw_opt_self_ref < 0 && self_ref) {
1275 // issue only the first note
1276 rw_note (0, _rw_this_file, tcase.line,
1277 "self-referential test disabled");
1278 return;
1279 }
1280 else if (0 < _rw_opt_self_ref && !self_ref) {
1281 // issue only the first note
1282 rw_note (0, _rw_this_file, tcase.line,
1283 "non-self-referential test disabled");
1284 return;
1285 }
1286
1287 // check to see if the test case is enabled
1288 if (rw_enabled (tcase.line)) {
1289
1290 // set the {FUNCALL} environment variable to describe
1291 // the function call specified by this test case
1292 rw_setvars (func, &tcase);
1293
1294 if (test_callback) {
1295 // invoke the test callback function
1296 test_callback (func, tcase);
1297 }
1298 else {
1299 _rw_dispatch (farray, func, tcase);
1300 }
1301 }
1302 else
1303 rw_note (0, _rw_this_file, tcase.line,
1304 "test on line %d disabled", tcase.line);
1305}
1306
1307
1309static StringTestFunc*
1310_rw_test_callback;
1311
1312
1313static VoidFunc* const*
1314_rw_func_array;
1315
1316
1317// exercise all test cases defined for the given function
1318static void
1319_rw_run_cases (const StringFunc &func,
1320 const StringTest &test)
1321{
1322 // set the {CLASS}, {FUNC}, and {FUNCSIG} environment
1323 // variable to the name of the basic_string specializaton
1324 // and the string function being exercised
1325 rw_setvars (func);
1326
1327 // determine whether the function is a member function
1328 const bool is_member = 0 != (StringIds::bit_member & int (test.which));
1329
1330 // compute the function overload's 0-based index
1331 const size_t siginx = _rw_get_func_inx (test.which);
1332
1333 // check if tests of the function overload
1334 // have been disabled
1335 if (0 == rw_note (0 <= _rw_opt_func [siginx], _rw_this_file, __LINE__,
1336 "%{?}%{$CLASS}::%{;}%{$FUNCSIG} tests disabled",
1337 is_member))
1338 return;
1339
1340 rw_info (0, 0, 0, "%{?}%{$CLASS}::%{;}%{$FUNCSIG}", is_member);
1341
1342 const size_t case_count = test.case_count;
1343
1344 // iterate over all test cases for this function
1345 // overload invoking the test case handler for each
1346 // in turn
1347 for (size_t n = 0; n != case_count; ++n) {
1348
1349 const StringTestCase& tcase = test.cases [n];
1350
1351 _rw_test_case (func, tcase, _rw_test_callback, _rw_func_array);
1352 }
1353}
1354
1355
1357static void
1358_rw_toggle_options (int *opts, size_t count)
1359{
1360 for (size_t i = 0; i != count; ++i) {
1361 if (0 < opts [i]) {
1362 // if one or more options has been explicitly enabled
1363 // treat all those that haven't been as if they had
1364 // been disabled
1365 for (i = 0; i != count; ++i) {
1366 if (0 == opts [i])
1367 opts [i] = -1;
1368 }
1369 break;
1370 }
1371 }
1372}
1373
1374
1375static int
1376_rw_run_test (int, char*[])
1377{
1378#ifdef _RWSTD_NO_EXCEPTIONS
1379
1380 rw_note (0, 0, 0, "exception tests disabled (macro "
1381 "_RWSTD_NO_EXCEPTIONS #defined)");
1382
1383 // disable all exception tests and avoid further notes
1384 _rw_no_exceptions = 2;
1385 _rw_no_exception_safety = 2;
1386
1387#endif // _RWSTD_NO_EXCEPTIONS
1388
1389#ifdef _RWSTD_NO_WCHAR_T
1390
1391 rw_note (0, 0, 0, "wchar_t tests disabled (macro "
1392 "_RWSTD_NO_WCHAR_T #defined)");
1393
1394 // disable wchar_t tests and avoid further notes
1395 _rw_opt_char_types [StringIds::WChar] = -2;
1396
1397#endif // _RWSTD_NO_WCHAR_T
1398
1399 // see if any option controlling a string function has been
1400 // explicitly enabled and if so disable all those that haven't
1401 // been (i.e., so that --enable-foo-size will have the effect
1402 // of specifying --disable-foo-val and --disable-foo-range,
1403 // given the three overloads of foo)
1404 const size_t nopts = sizeof _rw_opt_func / sizeof *_rw_opt_func;
1405 _rw_toggle_options (_rw_opt_func, nopts);
1406
1407 static const StringIds::CharId char_types[] = {
1409 };
1410
1411 static const StringIds::TraitsId traits_types[] = {
1413 };
1414
1415 static const StringIds::AllocId alloc_types[] = {
1417 };
1418
1419 static const StringIds::IteratorId iter_types[] = {
1425 };
1426
1427 const size_t n_char_types = sizeof char_types / sizeof *char_types;
1428 const size_t n_traits_types = sizeof traits_types / sizeof *traits_types;
1429 const size_t n_alloc_types = sizeof alloc_types / sizeof *alloc_types;
1430 const size_t n_iter_types = sizeof iter_types / sizeof *iter_types;
1431
1432 // see if any option controlling the basic_string template arguments
1433 // explicitly enabled and if so disable all those that haven't been
1434 _rw_toggle_options (_rw_opt_char_types, n_char_types);
1435 _rw_toggle_options (_rw_opt_traits_types, n_traits_types);
1436 _rw_toggle_options (_rw_opt_alloc_types, n_alloc_types);
1437 _rw_toggle_options (_rw_opt_iter_types, n_iter_types);
1438
1439 // exercise different charT specializations last
1440 for (size_t i = 0; i != n_char_types; ++i) {
1441
1442 if (_rw_opt_char_types [i] < 0) {
1443 // issue only the first note
1444 rw_note (-1 > _rw_opt_char_types [i]--,
1445 _rw_this_file, __LINE__,
1446 "%s tests disabled", _rw_char_names [i]);
1447 continue;
1448 }
1449
1450 // exercise all specializations on Traits before those on charT
1451 for (size_t j = 0; j != n_traits_types; ++j) {
1452
1453 if (0 == j && StringIds::UChar == char_types [i]) {
1454 // std::char_traits can only be instantiated on
1455 // char and wchar_t, only UserTraits may be used
1456 // with UserChar
1457 continue;
1458 }
1459
1460 if (_rw_opt_traits_types [j] < 0) {
1461 // issue only the first note
1462 rw_note (-1 > _rw_opt_traits_types [j]--,
1463 _rw_this_file, __LINE__,
1464 "%s tests disabled", _rw_traits_names [j]);
1465 continue;
1466 }
1467
1468 for (size_t k = 0; k != n_alloc_types; ++k) {
1469
1470 if (_rw_opt_alloc_types [k] < 0) {
1471 // issue only the first note
1472 rw_note (-1 > _rw_opt_alloc_types [k]--,
1473 _rw_this_file, __LINE__,
1474 "%s tests disabled", _rw_alloc_names [k]);
1475 continue;
1476 }
1477
1478 for (size_t m = 0; m != _rw_string_test_count; ++m) {
1479
1480 const StringTest& test = _rw_string_tests [m];
1481
1482 // create an object uniquely identifying the overload
1483 // of the string function exercised by the set of test
1484 // cases defined to exercise it
1485 StringFunc func = {
1486 char_types [i],
1487 traits_types [j],
1488 alloc_types [k],
1490 test.which
1491 };
1492
1493 // determine whether the function is a template
1494 if (-1 < _rw_argno (test.which, StringIds::arg_range)) {
1495
1496 // iterate over the standard iterator categories
1497 // and iterator types the template might perhaps
1498 // be specialized on
1499 for (size_t l = 0; l != n_iter_types; ++l) {
1500
1501 if (_rw_opt_iter_types [l] < 0) {
1502 // issue only the first note
1503 rw_note (-1 > _rw_opt_iter_types [l]--,
1504 _rw_this_file, __LINE__,
1505 "%s tests disabled",
1506 _rw_iter_names [l]);
1507 continue;
1508 }
1509
1510 func.iter_id_ = iter_types [l];
1511
1512 // exercise all test cases defined for
1513 // the function template
1514 _rw_run_cases (func, test);
1515 }
1516 }
1517 else {
1518 // exercise all test cases defined for the ordinary
1519 // (i.e., non-template) function
1520 _rw_run_cases (func, test);
1521 }
1522 }
1523 }
1524 }
1525 }
1526
1527 return 0;
1528}
1529
1530
1532// add a bunch of toggle-type command line options based on the names array
1533static void
1534_rw_add_toggles (char **pbuf, size_t *pbufsize,
1535 const char* const names[], size_t count)
1536{
1537 for (size_t i = 0; i != count; ++i) {
1538 rw_asnprintf (pbuf, pbufsize, "%{+}|-%s~ ", names [i]);
1539 }
1540}
1541
1542
1543static int
1544_rw_run_test (int argc,
1545 char *argv [],
1546 const char *file,
1547 const char *clause,
1548 StringTestFunc *test_callback,
1549 VoidFunc* const *func_array,
1550 const StringTest *tests,
1551 size_t test_count)
1552{
1553 // set the global variables accessed in _rw_run_test
1554 _rw_test_callback = test_callback;
1555 _rw_func_array = func_array,
1556 _rw_string_tests = tests;
1557 _rw_string_test_count = test_count;
1558
1559 // put together a command line option specification with options
1560 // to enable and disable tests exercising functions for all known
1561 // specializations of the functions specified by the test array
1562 char *optbuf = 0;
1563 size_t optbufsize = 0;
1564
1565 rw_asnprintf (&optbuf, &optbufsize,
1566 "|-no-exceptions# "
1567 "|-no-exception-safety# "
1568 "|-self-ref~ ");
1569
1570 const size_t n_chars = sizeof _rw_char_names / sizeof *_rw_char_names;
1571 const size_t n_traits = sizeof _rw_traits_names / sizeof *_rw_traits_names;
1572 const size_t n_allocs = sizeof _rw_alloc_names / sizeof *_rw_alloc_names;
1573 const size_t n_iters = sizeof _rw_iter_names / sizeof *_rw_iter_names;
1574
1575 // see if any option has been explicitly enabled and if so,
1576 // uncodnitionally disable all those that have not been
1577 _rw_add_toggles (&optbuf, &optbufsize, _rw_char_names, n_chars);
1578 _rw_add_toggles (&optbuf, &optbufsize, _rw_traits_names, n_traits);
1579 _rw_add_toggles (&optbuf, &optbufsize, _rw_alloc_names, n_allocs);
1580 _rw_add_toggles (&optbuf, &optbufsize, _rw_iter_names + 1, n_iters - 1);
1581
1582 for (size_t i = 0; i != test_count; ++i) {
1583
1584 // for each function append a command line option specification
1585 // to allow to enable or disable it
1586 rw_asnprintf (&optbuf, &optbufsize, "%{+}|-");
1587 _rw_sigcat (&optbuf, &optbufsize, 0, tests [i].which);
1588 rw_asnprintf (&optbuf, &optbufsize, "%{+}~ ");
1589 }
1590
1591 RW_ASSERT (test_count <= 32);
1592 RW_ASSERT (test_count <= MAX_OVERLOADS);
1593
1594 // process command line arguments run tests
1595 const int status =
1596 rw_test (argc, argv, file, clause,
1597 0, // comment
1598 _rw_run_test, // test callback
1599 optbuf, // option specification
1600
1601 // handlers controlling exceptions
1602 &_rw_opt_no_exceptions,
1603 &_rw_opt_no_exception_safety,
1604
1605 // handler controlling self-referential modifiers
1606 &_rw_opt_self_ref,
1607
1608 // handlers controlling specializations of the template
1609 // ...on the charT template parameter
1610 _rw_opt_char_types + 0,
1611 _rw_opt_char_types + 1,
1612 _rw_opt_char_types + 2,
1613
1614 // ...on the Traits template parameter
1615 _rw_opt_traits_types + 0,
1616 _rw_opt_traits_types + 1,
1617
1618 // ...on the Allocator template parameter
1619 _rw_opt_alloc_types + 0,
1620 _rw_opt_alloc_types + 1,
1621
1622 // FIXME: add handlers (and options) only for tests
1623 // that exercise member templates
1624
1625 // handlers controlling specializations of the member
1626 // template (if this is one) on the InputIterator
1627 // template parameter
1628 _rw_opt_iter_types + 0,
1629 _rw_opt_iter_types + 1,
1630 _rw_opt_iter_types + 2,
1631 _rw_opt_iter_types + 3,
1632 _rw_opt_iter_types + 4,
1633 _rw_opt_iter_types + 5,
1634 _rw_opt_iter_types + 6,
1635 _rw_opt_iter_types + 7,
1636 _rw_opt_iter_types + 8,
1637 _rw_opt_iter_types + 9,
1638
1639 // FIXME: install exactly as many handlers (and options)
1640 // as there are distinct functions being exercised
1641
1642 // handlers for up to 32 overloads
1643 _rw_opt_func + 0,
1644 _rw_opt_func + 1,
1645 _rw_opt_func + 2,
1646 _rw_opt_func + 3,
1647 _rw_opt_func + 4,
1648 _rw_opt_func + 5,
1649 _rw_opt_func + 6,
1650 _rw_opt_func + 7,
1651 _rw_opt_func + 8,
1652 _rw_opt_func + 9,
1653 _rw_opt_func + 10,
1654 _rw_opt_func + 11,
1655 _rw_opt_func + 12,
1656 _rw_opt_func + 13,
1657 _rw_opt_func + 14,
1658 _rw_opt_func + 15,
1659 _rw_opt_func + 16,
1660 _rw_opt_func + 17,
1661 _rw_opt_func + 18,
1662 _rw_opt_func + 19,
1663 _rw_opt_func + 20,
1664 _rw_opt_func + 21,
1665 _rw_opt_func + 22,
1666 _rw_opt_func + 23,
1667 _rw_opt_func + 24,
1668 _rw_opt_func + 25,
1669 _rw_opt_func + 26,
1670 _rw_opt_func + 27,
1671 _rw_opt_func + 28,
1672 _rw_opt_func + 29,
1673 _rw_opt_func + 30,
1674 _rw_opt_func + 31,
1675
1676 // sentinel
1677 (void*)0);
1678
1679 // free storage allocated for the option specification
1680 free (optbuf);
1681
1682 return status;
1683}
1684
1685
1686
1687_TEST_EXPORT int
1689 char *argv [],
1690 const char *file,
1691 const char *clause,
1692 StringTestFunc *callback,
1693 const StringTest *tests,
1694 size_t count)
1695{
1696 return _rw_run_test (argc, argv, file, clause, callback, 0, tests, count);
1697}
1698
1699
1700_TEST_EXPORT int
1702 char *argv [],
1703 const char *file,
1704 const char *clause,
1705 VoidFunc* const *farray,
1706 const StringTest *tests,
1707 size_t count)
1708{
1709 return _rw_run_test (argc, argv, file, clause, 0, farray, tests, count);
1710}
void count(T, T, const U &,...)
#define m
Definition 17.names.cpp:129
#define i
Definition 17.names.cpp:126
#define k
Definition 17.names.cpp:128
#define line
Definition 17.names.cpp:490
#define which
Definition 17.names.cpp:575
#define Traits
Definition 17.names.cpp:556
#define Alloc
Definition 17.names.cpp:439
#define buf
Definition 17.names.cpp:452
#define j
Definition 17.names.cpp:127
#define off
Definition 17.names.cpp:507
#define charT
Definition 17.names.cpp:456
#define tmp
Definition 17.names.cpp:553
#define n
Definition 17.names.cpp:130
#define inx
Definition 17.names.cpp:484
bool equal(const T &x, const U &y)
const size_t MAX_OVERLOADS
_TEST_EXPORT int rw_run_string_test(int argc, char *argv[], const char *file, const char *clause, StringTestFunc *callback, const StringTest *tests, size_t count)
_TEST_EXPORT void rw_setvars(const StringFunc &func, const StringTestCase *pcase)
_RWSTD_INTERNAL StringTestCase _rw_reverse_results(const StringTestCase &tsrc, size_t off, size_t ext)
void _rw_dispatch(charT *, Traits *, Allocator *, VoidFunc *const *farray, const StringFunc &func, const StringTestCase &tcase)
std::char_traits< S > Traits
const int end
#define _RWSTD_REINTERPRET_CAST(T, x)
Definition _defs.h:535
#define _RWSTD_INTERNAL
Definition _defs.h:1005
const char * str
Definition exec.cpp:170
_TEST_EXPORT char * rw_expand(char *, const char *, _RWSTD_SIZE_T=_RWSTD_SIZE_MAX, _RWSTD_SIZE_T *=0)
_TEST_EXPORT int rw_enabled(const char *name)
void VoidFunc()
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
Definition driver.cpp:1681
_TEST_EXPORT int rw_note(int, const char *, int, const char *,...)
Definition driver.cpp:1664
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
_TEST_EXPORT int rw_error(int, const char *, int, const char *,...)
Definition driver.cpp:1613
_TEST_EXPORT int rw_fprintf(rw_file *, const char *,...)
Definition printf.cpp:3397
_TEST_EXPORT int rw_asnprintf(char **pbuf, _RWSTD_SIZE_T *pbufsize, const char *fmt,...)
void StringTestFunc(const StringFunc &, const StringTestCase &)
Definition rw_strings.h:636
#define _TEST_EXPORT
Definition rw_testdefs.h:55
#define RW_ASSERT(expr)
@ DefaultTraits
Definition rw_strings.h:45
_RWSTD_SIZE_T size_
Definition rw_strings.h:740
_RWSTD_SIZE_T capacity_
Definition rw_strings.h:741
int assert_equal(const StringState &, int, int, const char *) const
const void * data_
Definition rw_strings.h:739
_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
int arg
Definition locale.cpp:2806