blob: c658cb5b93e0395d2253cdaa02b2fb9042be1e1a [file] [log] [blame]
/************************************************************************
*
* 21.strings.cpp - definitions of helpers used in clause 21 tests
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
**************************************************************************/
// expand _TEST_EXPORT macros
#define _RWSTD_TEST_SRC
#include <memory> // for allocator
#include <string> // for char_traits
#include <rw_strings.h>
#include <rw_cmdopt.h> // for rw_enabled()
#include <rw_driver.h> // for rw_info()
#include <rw_allocator.h> // for UserAlloc
#include <rw_char.h> // for rw_expand()
#include <rw_printf.h> // for rw_asnprintf()
#include <ctype.h> // for isdigit()
#include <stdarg.h> // for va_arg, ...
#include <stddef.h> // for size_t
#include <stdlib.h> // for free()
#include <string.h> // for memset()
/**************************************************************************/
static const char
_rw_this_file[] = __FILE__;
static const char* const
_rw_char_names[] = {
"char", "wchar_t", "UserChar"
};
static const char* const
_rw_traits_names[] = {
"char_traits", "UserTraits"
};
static const char* const
_rw_alloc_names[] = {
"allocator", "UserAlloc"
};
static const char* const
_rw_iter_names[] = {
"",
"InputIterator", "ForwardIterator", "BidirectionalIterator",
"RandomAccessIterator",
"pointer", "const_pointer",
"iterator", "const_iterator",
"reverse_iterator", "const_reverse_iterator"
};
// order of elements depends on the values of StringIds::FuncId
static const char* const
_rw_func_names[] = {
"append", "assign", "erase", "insert", "replace", "operator+=", "find",
"rfind", "find_first_of", "find_last_of", "find_first_not_of",
"find_last_not_of", "compare", "substr", "operator[]", "at", "copy",
0 /* special handling for the ctor */, "operator=", "swap", "push_back",
"operator+", "operator==", "operator!=", "operator<", "operator<=",
"operator>", "operator>=", "size", "length", "max_size", "resize",
"capacity", "reserve", "clear", "empty", "begin", "end", "rbegin",
"rend", "c_str", "data", "get_allocator", "operator>>", "operator<<",
"getline"
};
/**************************************************************************/
const size_t MAX_OVERLOADS = 32;
// disabled (-1) or explicitly enabled (+1) for each overload
// of the string function being tested
static int
_rw_opt_func [MAX_OVERLOADS];
// array of tests each exercising a single string function
static const StringTest*
_rw_string_tests;
// size of the array above
static size_t
_rw_string_test_count;
static int
_rw_opt_char_types [sizeof _rw_char_names / sizeof *_rw_char_names];
static int
_rw_opt_traits_types [sizeof _rw_traits_names / sizeof *_rw_traits_names];
static int
_rw_opt_alloc_types [sizeof _rw_alloc_names / sizeof *_rw_alloc_names];
static int
_rw_opt_iter_types [sizeof _rw_iter_names / sizeof *_rw_iter_names];
static int
_rw_opt_no_exceptions;
static int
_rw_opt_no_exception_safety;
static int
_rw_opt_self_ref;
/**************************************************************************/
static size_t
_rw_get_func_inx (StringIds::OverloadId fid)
{
size_t inx = _RWSTD_SIZE_MAX;
for (size_t i = 0; _rw_string_test_count; ++i) {
if (fid == _rw_string_tests [i].which) {
inx = i;
break;
}
}
RW_ASSERT (inx < _RWSTD_SIZE_MAX);
return inx;
}
/**************************************************************************/
int StringState::
assert_equal (const StringState &state, int line, int case_line,
const char *when) const
{
const int equal =
data_ == state.data_
&& size_ == state.size_
&& capacity_ == state.capacity_;
rw_assert (equal, 0, case_line,
"line %d: %{$FUNCALL}: object state unexpectedly changed "
"from { %#p, %zu, %zu } to { %#p, %zu, %zu } (data, size, "
"capacity) after %s",
line, data_, size_, capacity_,
state.data_, state.size_, state.capacity_,
when);
return equal;
}
/**************************************************************************/
static const char*
_rw_class_name (const StringFunc &func)
{
if ( StringIds::DefaultTraits == func.traits_id_
&& StringIds::DefaultAlloc == func.alloc_id_) {
if (StringIds::Char == func.char_id_)
return "string";
if (StringIds::WChar == func.char_id_)
return "wstring";
}
return "basic_string";
}
/**************************************************************************/
// appends the signature of the function specified by which
// to the provided buffer; when the second argument is null,
// appends the mnemonic representing the signature, including
// the name of the function, as specified by the third argument
static void
_rw_sigcat (char **pbuf, size_t *pbufsize,
const StringFunc *func,
StringIds::OverloadId which = StringIds::OverloadId ())
{
// for convenience
typedef StringIds Ids;
if (func)
which = func->which_;
// determine whether the function is a member function
const bool is_member = 0 != (Ids::bit_member & int (which));
// get the bitmap describing the function's argument types
int argmap = (~Ids::bit_member & int (which)) >> Ids::fid_bits;
// determine whether the function is a const member function
bool is_const_member =
is_member && Ids::arg_cstr == (argmap & Ids::arg_mask);
// remove the *this argument if the function is a member
if (is_member)
argmap >>= Ids::arg_bits;
const char* funcname = 0;
if (0 == func) {
const int fid = StringIds::fid_mask & int (which);
switch (fid) {
// translate names with funky characters to mnemonics
case Ids::fid_ctor: funcname = "ctor"; break;
case Ids::fid_op_plus_eq: funcname = "op_plus_eq"; break;
case Ids::fid_op_index: funcname = "op_index"; break;
case Ids::fid_op_set: funcname = "op_assign"; break;
case Ids::fid_op_plus: funcname = "op_plus"; break;
case Ids::fid_op_equal: funcname = "op_equal"; break;
case Ids::fid_op_not_equal: funcname = "op_not_equal"; break;
case Ids::fid_op_less: funcname = "op_less"; break;
case Ids::fid_op_less_equal: funcname = "op_less_equal"; break;
case Ids::fid_op_greater: funcname = "op_greater"; break;
case Ids::fid_op_greater_equal: funcname = "op_greater_equal"; break;
case Ids::fid_extractor: funcname = "extractor"; break;
case Ids::fid_inserter: funcname = "inserter"; break;
case Ids::fid_compare:
case Ids::fid_copy:
case Ids::fid_find:
case Ids::fid_find_first_not_of:
case Ids::fid_find_first_of:
case Ids::fid_find_last_not_of:
case Ids::fid_find_last_of:
case Ids::fid_rfind:
case Ids::fid_substr:
case Ids::fid_c_str:
case Ids::fid_data:
case Ids::fid_get_allocator:
// prevent appending the "_const" bit to the mnemonics
// of member functions not overloaded on const
is_const_member = false;
// fall through
default: {
// determine the string function name (for brief output)
const size_t nfuncs =
sizeof _rw_func_names / sizeof *_rw_func_names;
RW_ASSERT (size_t (fid) < nfuncs);
funcname = _rw_func_names [fid];
RW_ASSERT (0 != funcname);
break;
}
}
}
// iterator name for member templates, empty string for other functions
const char* const iname = func ? _rw_iter_names [func->iter_id_] : "";
rw_asnprintf (pbuf, pbufsize,
"%{+}%{?}%s%{?}_const%{;}%{:}%{?}<%s>%{;}(%{;}",
0 == func, funcname, is_const_member, 0 != *iname, iname);
char iname_buf [80];
*iname_buf = '\0';
// iterate through the map of argument types one field at a time
// determining and formatting the type of each argument until
// void is reached
for (size_t argno = 0; argmap; ++argno, argmap >>= Ids::arg_bits) {
const char* pfx = "";
const char* sfx = "";
const int argtype = argmap & Ids::arg_mask;
const char* tname = 0;
if (func) {
switch (argtype) {
case Ids::arg_size: tname = "size_type"; break;
case Ids::arg_val: tname = "value_type"; break;
case Ids::arg_ptr: tname = "pointer"; break;
case Ids::arg_cptr: tname = "const_pointer"; break;
case Ids::arg_ref: tname = "reference"; break;
case Ids::arg_cref: tname = "const_reference"; break;
case Ids::arg_iter: tname = "iterator"; break;
case Ids::arg_citer: tname = "const_iterator"; break;
case Ids::arg_range:
if ('\0' == *iname_buf) {
strcpy (iname_buf, iname);
strcat (iname_buf, ", ");
strcat (iname_buf, iname);
}
tname = iname_buf;
break;
case Ids::arg_alloc: tname = "const allocator_type&"; break;
case Ids::arg_cstr:
pfx = "const ";
// fall through
case Ids::arg_str:
tname = _rw_class_name (*func);
sfx = "&";
break;
case Ids::arg_istream: tname = "istream&"; break;
case Ids::arg_ostream: tname = "ostream&"; break;
}
}
else {
switch (argtype) {
case Ids::arg_size: tname = "size"; break;
case Ids::arg_val: tname = "val"; break;
case Ids::arg_ptr: tname = "ptr"; break;
case Ids::arg_cptr: tname = "cptr"; break;
case Ids::arg_ref: tname = "ref"; break;
case Ids::arg_cref: tname = "cref"; break;
case Ids::arg_iter: tname = "iter"; break;
case Ids::arg_citer: tname = "citer"; break;
case Ids::arg_range: tname = "range"; break;
case Ids::arg_alloc: tname = "alloc"; break;
case Ids::arg_str: tname = "str"; break;
case Ids::arg_cstr: tname = "cstr"; break;
case Ids::arg_istream: tname = "istream"; break;
case Ids::arg_ostream: tname = "ostream"; break;
}
}
RW_ASSERT (0 != tname);
if ( 0 == func || is_member
|| Ids::arg_str != argtype && Ids::arg_cstr != argtype
&& Ids::arg_istream != argtype && Ids::arg_ostream != argtype) {
// append the name or mnemonic of the argument type
rw_asnprintf (pbuf, pbufsize, "%{+}%{?}_%{:}%{?}, %{;}%{;}%s%s%s",
0 == func, 0 < argno, pfx, tname, sfx);
}
else if (Ids::arg_istream == argtype || Ids::arg_ostream == argtype) {
// in non-member functions use ${{I|O}STREAM} to format
// the basic_{i|o}stream argument in order to expand
// its template argument list
rw_asnprintf (pbuf, pbufsize,
"%{+}%{?}, %{;}%{?}%{$ISTREAM}%{:}%{$OSTREAM}%{;}&",
0 < argno, Ids::arg_istream == argtype);
}
else {
// in non-member functions use ${CLASS} to format
// the basic_string argument in order to expand
// its template argument list
rw_asnprintf (pbuf, pbufsize,
"%{+}%{?}, %{;}%{?}const %{;}%{$CLASS}&",
0 < argno, Ids::arg_cstr == argtype);
}
}
if (func)
rw_asnprintf (pbuf, pbufsize, "%{+})%{?} const%{;}", is_const_member);
}
/**************************************************************************/
// returns the zero-based index of the argument type specified
// by arg in the function signature given by which
static int
_rw_argno (StringIds::OverloadId which, int arg)
{
// get the bitmap describing the function's argument types
int argmap = (which & ~StringIds::bit_member) >> StringIds::fid_bits;
int argno = 0;
// iterate over argument types looking for the first one
// that equals arg
for (; argmap; argmap >>= StringIds::arg_bits, ++argno) {
if ((argmap & StringIds::arg_mask) == arg) {
return argno;
}
}
// return -1 when the function doesn't take an argument
// of the specified type
return -1;
}
/**************************************************************************/
_TEST_EXPORT void
rw_setvars (const StringFunc &func,
const StringTestCase *pcase /* = 0 */)
{
char* buf = 0;
size_t bufsize = 0;
const char* const class_name = _rw_class_name (func);
if (0 == pcase) {
// set the {charT}, {Traits}, and {Allocator} environment
// variables to the name of the character type and the
// Traits and Allocator specializations
rw_fprintf (0, "%{$charT!:*}", _rw_char_names [func.char_id_]);
rw_fprintf (0, "%{$Traits!:*}", _rw_traits_names [func.traits_id_]);
rw_fprintf (0, "%{$Allocator!:*}", _rw_alloc_names [func.alloc_id_]);
rw_fprintf (0, "%{$Iterator!:*}", _rw_iter_names [func.iter_id_]);
// set the {CLASS}, {FUNC}, and {FUNCSIG} environment variables
// to the name of the specialization of the template, the name
// of the string function, and the name of the overload of the
// string function, respectively, when no test case is given
if ( StringIds::DefaultTraits == func.traits_id_
&& StringIds::DefaultAlloc == func.alloc_id_
&& ( StringIds::Char == func.char_id_
|| StringIds::WChar == func.char_id_)) {
// format std::string and std::wstring
rw_asnprintf (&buf, &bufsize, "std::%{?}w%{;}string",
StringIds::WChar == func.char_id_);
}
else {
// format std::basic_string specializations other than
// std::string and std::wstring, leaving out the name
// of the default allocator for brevity
rw_asnprintf (&buf, &bufsize,
"std::basic_string<%s, %s<%1$s>%{?}, %s<%1$s>%{;}>",
_rw_char_names [func.char_id_],
_rw_traits_names [func.traits_id_],
StringIds::DefaultAlloc != func.alloc_id_,
_rw_alloc_names [func.alloc_id_]);
}
// set the {CLASS} variable to the name of the specialization
// of basic_string
rw_fprintf (0, "%{$CLASS!:*}", buf);
free (buf);
buf = 0;
bufsize = 0;
// set the {ISTREAM} environment variable
// to the name of the specialization of the template basic_istream
if ( StringIds::DefaultTraits == func.traits_id_
&& ( StringIds::Char == func.char_id_
|| StringIds::WChar == func.char_id_)) {
// format std::istream and std::wistream
rw_asnprintf (&buf, &bufsize, "std::%{?}w%{;}istream",
StringIds::WChar == func.char_id_);
}
else {
// format std::basic_istream specializations other than
// std::istream and std::wistream
rw_asnprintf (&buf, &bufsize,
"std::basic_istream<%s, %s<%1$s>>",
_rw_char_names [func.char_id_],
_rw_traits_names [func.traits_id_]);
}
rw_fprintf (0, "%{$ISTREAM!:*}", buf);
free (buf);
buf = 0;
bufsize = 0;
// set the {OSTREAM} environment variable
// to the name of the specialization of the template basic_ostream
if ( StringIds::DefaultTraits == func.traits_id_
&& ( StringIds::Char == func.char_id_
|| StringIds::WChar == func.char_id_)) {
// format std::ostream and std::wostream
rw_asnprintf (&buf, &bufsize, "std::%{?}w%{;}ostream",
StringIds::WChar == func.char_id_);
}
else {
// format std::basic_ostream specializations other than
// std::ostream and std::wostream
rw_asnprintf (&buf, &bufsize,
"std::basic_ostream<%s, %s<%1$s>>",
_rw_char_names [func.char_id_],
_rw_traits_names [func.traits_id_]);
}
rw_fprintf (0, "%{$OSTREAM!:*}", buf);
free (buf);
buf = 0;
bufsize = 0;
// determine the string function name
const size_t funcinx = StringIds::fid_mask & int (func.which_);
const size_t nfuncs = sizeof _rw_func_names / sizeof *_rw_func_names;
RW_ASSERT (funcinx < nfuncs);
// get the undecorated function name; ctors are treated
// specially so that we can have string, wstring, or
// basic_string, depending on the template arguments
const char* const funcname = _rw_func_names [funcinx] ?
_rw_func_names [funcinx] : class_name;
// determine whether the function is a member function
const bool is_member =
0 != (StringIds::bit_member & int (func.which_));
// set the {FUNC} variable to the unqualified/undecorated
// name of the string function (member or otherwise)
rw_asnprintf (&buf, &bufsize, "%{?}std::%{;}%s",
!is_member, funcname);
rw_fprintf (0, "%{$FUNC!:*}", buf);
// append the function signature
_rw_sigcat (&buf, &bufsize, &func);
rw_fprintf (0, "%{$FUNCSIG!:*}", buf);
free (buf);
return;
}
// do the function call arguments reference *this?
const bool self = 0 == pcase->arg;
char str_buf [256];
char arg_buf [256];
char *str;
char *arg;
size_t str_len = sizeof str_buf;
size_t arg_len = sizeof arg_buf;
if (pcase->str)
str = rw_expand (str_buf, pcase->str, pcase->str_len, &str_len);
else
str = 0;
if (pcase->arg)
arg = rw_expand (arg_buf, pcase->arg, pcase->arg_len, &arg_len);
else
arg = 0;
// determine whether the function is a member function
const bool is_member =
0 != (StringIds::bit_member & int (func.which_));
// determine whether the function is a ctor
const bool is_ctor =
StringIds::fid_ctor == (StringIds::fid_mask & int (func.which_));
if (is_ctor) {
// for ctors append just the class name here
// the class name will inserted below during argument
// formatting
rw_asnprintf (&buf, &bufsize, "%{$CLASS}::%s", class_name);
}
else if (is_member) {
// for other members append the ctor argument(s) followed
// by the string member function name
rw_asnprintf (&buf, &bufsize,
"%{$CLASS} (%{?}%{#*s}%{;}).%{$FUNC}",
str != 0, int (str_len), str);
}
else {
// for non-members append just the function name here
// the class name will inserted below during argument
// formatting
rw_asnprintf (&buf, &bufsize, "%{$FUNC}");
}
// compute the end offsets for convenience
const size_t range1_end = pcase->off + pcase->size;
const size_t range2_end = pcase->off2 + pcase->size2;
// determine whether the function takes an allocator_type argument
const bool use_alloc = 0 < _rw_argno (func.which_, StringIds::arg_alloc);
// format and append string function arguments abbreviating complex
// expressions as much as possible to make them easy to understand
switch (func.which_) {
case StringIds::append_cptr:
case StringIds::assign_cptr:
case StringIds::op_plus_eq_cptr:
case StringIds::find_cptr:
case StringIds::rfind_cptr:
case StringIds::find_first_of_cptr:
case StringIds::find_last_of_cptr:
case StringIds::find_first_not_of_cptr:
case StringIds::find_last_not_of_cptr:
case StringIds::compare_cptr:
case StringIds::op_set_cptr:
case StringIds::ctor_cptr:
case StringIds::ctor_cptr_alloc:
// format self-referential ptr argument without size as c_str()
rw_asnprintf (&buf, &bufsize,
"%{+} (%{?}c_str()%{:}%{#*s}%{;}"
"%{?}, const allocator_type&%{;})",
self, int (arg_len), arg, use_alloc);
break;
case StringIds::append_cstr:
case StringIds::assign_cstr:
case StringIds::op_plus_eq_cstr:
case StringIds::find_cstr:
case StringIds::rfind_cstr:
case StringIds::find_first_of_cstr:
case StringIds::find_last_of_cstr:
case StringIds::find_first_not_of_cstr:
case StringIds::find_last_not_of_cstr:
case StringIds::compare_cstr:
case StringIds::ctor_cstr:
case StringIds::op_set_cstr:
case StringIds::swap_str:
// format self-referential str argument as *this
rw_asnprintf (&buf, &bufsize,
"%{+} (%{?}*this%{:}%s(%{#*s})%{;}"
"%{?}, const allocator_type&%{;})",
self, class_name, int (arg_len), arg, use_alloc);
break;
case StringIds::append_cptr_size:
case StringIds::assign_cptr_size:
case StringIds::copy_ptr_size:
case StringIds::ctor_cptr_size:
case StringIds::ctor_cptr_size_alloc:
// format self-referential ptr argument with size as data()
rw_asnprintf (&buf, &bufsize, "%{+} ("
"%{?}data()%{:}%{#*s}%{;}, %zu"
"%{?}, const allocator_type&%{;})",
self, int (arg_len), arg, pcase->size, use_alloc);
break;
case StringIds::find_cptr_size:
case StringIds::rfind_cptr_size:
case StringIds::find_first_of_cptr_size:
case StringIds::find_last_of_cptr_size:
case StringIds::find_first_not_of_cptr_size:
case StringIds::find_last_not_of_cptr_size:
// format self-referential ptr argument with size as data()
rw_asnprintf (&buf, &bufsize, "%{+} ("
"%{?}data()%{:}%{#*s}%{;}, %zu)",
self, int (arg_len), arg, pcase->off);
break;
case StringIds::find_cstr_size:
case StringIds::rfind_cstr_size:
case StringIds::find_first_of_cstr_size:
case StringIds::find_last_of_cstr_size:
case StringIds::find_first_not_of_cstr_size:
case StringIds::find_last_not_of_cstr_size:
case StringIds::ctor_cstr_size:
case StringIds::ctor_cstr_size_alloc:
// format self-referential str argument as *this
rw_asnprintf (&buf, &bufsize, "%{+} ("
"%{?}*this%{:}%s(%{#*s})%{;}, %zu"
"%{?}, const allocator_type%{;})",
self, class_name, int (arg_len), arg, pcase->off,
use_alloc);
break;
case StringIds::find_cptr_size_size:
case StringIds::rfind_cptr_size_size:
case StringIds::find_first_of_cptr_size_size:
case StringIds::find_last_of_cptr_size_size:
case StringIds::find_first_not_of_cptr_size_size:
case StringIds::find_last_not_of_cptr_size_size:
// format self-referential ptr argument with size as data()
rw_asnprintf (&buf, &bufsize, "%{+} ("
"%{?}data()%{:}%{#*s}%{;}, %zu, %zu)",
self, int (arg_len), arg,
pcase->off, pcase->size);
break;
case StringIds::copy_ptr_size_size:
// format self-referential ptr argument with size as data()
rw_asnprintf (&buf, &bufsize, "%{+} ("
"%{?}data()%{:}%{#*s}%{;}, %zu, %zu)",
self, int (arg_len), arg,
pcase->size, pcase->off);
break;
case StringIds::append_cstr_size_size:
case StringIds::assign_cstr_size_size:
case StringIds::ctor_cstr_size_size:
case StringIds::ctor_cstr_size_size_alloc:
// format self-referential str argument as *this
rw_asnprintf (&buf, &bufsize, "%{+} ("
"%{?}*this%{:}%s(%{#*s})%{;}, %zu, %zu"
"%{?}, const allocator_type%{;})",
self, class_name, int (arg_len), arg,
pcase->off, pcase->size, use_alloc);
break;
case StringIds::append_size_val:
case StringIds::assign_size_val:
case StringIds::ctor_size_val:
case StringIds::ctor_size_val_alloc:
rw_asnprintf (&buf, &bufsize,
"%{+} (%zu, %{#c}%{?}, const allocator_type&%{;})",
pcase->size, pcase->val, use_alloc);
break;
case StringIds::append_range:
case StringIds::assign_range:
case StringIds::ctor_range:
case StringIds::ctor_range_alloc:
rw_asnprintf (&buf, &bufsize, "%{+}<%{$Iterator:-Iterator}>("
"%{?}begin()%{:}%{$Iterator:-Iterator}(%{#*s})%{;}"
"%{?} + %zu%{;}, "
"%{?}begin()%{:}%{$Iterator:-Iterator}(...)%{;}"
"%{?} + %zu%{;}"
"%{?}, const allocator_type&%{;})",
self, int (arg_len), arg,
0 != pcase->off2, pcase->off2,
self, 0 != range2_end, range2_end, use_alloc);
break;
case StringIds::insert_size_cptr:
// format self-referential ptr argument without size as c_str()
rw_asnprintf (&buf, &bufsize,
"%{+} (%zu, %{?}c_str()%{:}%{#*s}%{;})",
pcase->off, self, int (arg_len), arg);
break;
case StringIds::insert_size_cstr:
// format self-referential str argument as *this
rw_asnprintf (&buf, &bufsize,
"%{+} (%zu, %{?}*this%{:}%s(%{#*s})%{;})",
pcase->off, self, class_name, int (arg_len), arg);
break;
case StringIds::insert_size_cptr_size:
// format self-referential ptr argument with size as data()
rw_asnprintf (&buf, &bufsize, "%{+} ("
"%zu, %{?}data()%{:}%{#*s}%{;}, %zu)",
pcase->off, self, int (arg_len), arg,
pcase->size2);
break;
case StringIds::insert_size_cstr_size_size:
// format self-referential str argument as *this
rw_asnprintf (&buf, &bufsize, "%{+} ("
"%zu, %{?}*this%{:}%s(%{#*s})%{;}, %zu, %zu)",
pcase->off, self, class_name, int (arg_len), arg,
pcase->off2, pcase->size2);
break;
case StringIds::insert_size_size_val:
rw_asnprintf (&buf, &bufsize,
"%{+} (%zu, %zu, %{#c})",
pcase->off, pcase->size2, pcase->val);
break;
case StringIds::insert_iter_val:
rw_asnprintf (&buf, &bufsize,
"%{+} (begin()%{?} + %zu%{;}, %{#c})",
0 != pcase->off, pcase->off, pcase->val);
break;
case StringIds::insert_iter_size_val:
rw_asnprintf (&buf, &bufsize,
"%{+} (begin()%{?} + %zu%{;}, %zu, %{#c})",
0 != pcase->off, pcase->off, pcase->size, pcase->val);
break;
case StringIds::insert_iter_range:
rw_asnprintf (&buf, &bufsize, "%{+}<%{$Iterator:-Iterator}>"
"(begin()%{?} + %zu%{;}, "
"%{?}begin()%{:}%{$Iterator:-Iterator}(%{#*s})%{;}"
"%{?} + %zu%{;}, "
"%{?}begin()%{:}%{$Iterator:-Iterator}(...)"
"%{?} + %zu%{;})",
0 != pcase->off, pcase->off,
self, int (arg_len), arg,
0 != pcase->off2, pcase->off2,
self, 0 != range2_end, range2_end);
break;
case StringIds::replace_size_size_cptr:
case StringIds::compare_size_size_cptr:
// format self-referential ptr argument without size as c_str()
rw_asnprintf (&buf, &bufsize, "%{+} ("
"%zu, %zu, %{?}c_str()%{:}%{#*s}%{;})",
pcase->off, pcase->size, self,
int (arg_len), arg);
break;
case StringIds::replace_size_size_cstr:
case StringIds::compare_size_size_cstr:
// format self-referential str argument as *this
rw_asnprintf (&buf, &bufsize, "%{+} ("
"%zu, %zu, %{?}*this%{:}%s(%{#*s})%{;})",
pcase->off, pcase->size, self, class_name,
int (arg_len), arg);
break;
case StringIds::replace_size_size_cptr_size:
case StringIds::compare_size_size_cptr_size:
// format self-referential ptr argument with size as data()
rw_asnprintf (&buf, &bufsize, "%{+} ("
"%zu, %zu, %{?}data()%{:}%{#*s}%{;}, %zu)",
pcase->off, pcase->size, self,
int (arg_len), arg, pcase->size2);
break;
case StringIds::replace_size_size_cstr_size_size:
case StringIds::compare_size_size_cstr_size_size:
// format self-referential str argument as *this
rw_asnprintf (&buf, &bufsize, "%{+} (%zu, %zu, "
"%{?}*this%{:}%s(%{#*s})%{;}, %zu, %zu)",
pcase->off, pcase->size,
self, class_name, int (arg_len), arg,
pcase->off2, pcase->size2);
break;
case StringIds::replace_size_size_size_val:
rw_asnprintf (&buf, &bufsize,
"%{+} (%zu, %zu, %zu, %{#c})",
pcase->off, pcase->size, pcase->size2, pcase->val);
break;
case StringIds::replace_iter_iter_cptr:
// format self-referential ptr argument without size as c_str()
rw_asnprintf (&buf, &bufsize, "%{+} (begin()%{?} + %zu%{;}, "
"begin()%{?} + %zu%{;}, "
"%{?}c_str()%{:}%{#*s}%{;})",
0 != pcase->off, pcase->off,
0 != range1_end, range1_end,
self, int (arg_len), arg);
break;
case StringIds::replace_iter_iter_cstr:
// format self-referential str argument as *this
rw_asnprintf (&buf, &bufsize, "%{+} (begin()%{?} + %zu%{;}, "
"begin()%{?} + %zu%{;}, "
"%{?}*this%{:}%s(%{#*s})%{;})",
0 != pcase->off, pcase->off,
0 != range1_end, range1_end,
self, class_name, int (arg_len), arg);
break;
case StringIds::replace_iter_iter_cptr_size:
// format self-referential ptr argument with size as data()
rw_asnprintf (&buf, &bufsize, "%{+} (begin()%{?} + %zu%{;}, "
"begin()%{?} + %zu%{;}, "
"%{?}data()%{:}%{#*s}%{;}, %zu)",
0 != pcase->off, pcase->off,
0 != range1_end, range1_end,
self, int (arg_len), arg, pcase->size2);
break;
case StringIds::replace_iter_iter_size_val:
rw_asnprintf (&buf, &bufsize,
"%{+} (begin()%{?} + %zu%{;}, begin()%{? + %zu%{;}, "
"%zu, %{#c})",
0 != pcase->off, pcase->off, 0 != range1_end, range1_end,
pcase->size2, pcase->val);
break;
case StringIds::replace_iter_iter_range:
rw_asnprintf (&buf, &bufsize, "%{+}<%{$Iterator:-Iterator}>("
"begin()%{?} + %zu%{;}, "
"begin()%{?} + %zu%{;}, "
"%{?}begin()%{:}%{$Iterator:-Iterator}(%{#*s})%{;}"
"%{?} + %zu%{;}, "
"%{?}begin()%{:}%{$Iterator:-Iterator}(...)%{;}"
"%{?} + %zu%{;})",
0 != pcase->off, pcase->off,
0 != range1_end, range1_end,
self, int (arg_len), arg,
0 != pcase->off2, pcase->off2,
self, 0 != range2_end, range2_end);
break;
case StringIds::op_plus_eq_val:
case StringIds::find_val:
case StringIds::rfind_val:
case StringIds::find_first_of_val:
case StringIds::find_last_of_val:
case StringIds::find_first_not_of_val:
case StringIds::find_last_not_of_val:
case StringIds::op_set_val:
case StringIds::push_back_val:
rw_asnprintf (&buf, &bufsize,
"%{+} (%{#c})", pcase->val);
break;
case StringIds::find_val_size:
case StringIds::rfind_val_size:
case StringIds::find_first_of_val_size:
case StringIds::find_last_of_val_size:
case StringIds::find_first_not_of_val_size:
case StringIds::find_last_not_of_val_size:
rw_asnprintf (&buf, &bufsize,
"%{+} (%{#c}, %zu)", pcase->val, pcase->off);
break;
case StringIds::erase_void:
case StringIds::substr_void:
case StringIds::ctor_void:
case StringIds::size_void:
case StringIds::length_void:
case StringIds::max_size_void:
case StringIds::capacity_void:
case StringIds::reserve_void:
case StringIds::clear_void:
case StringIds::empty_void:
case StringIds::begin_void:
case StringIds::end_void:
case StringIds::rbegin_void:
case StringIds::rend_void:
case StringIds::c_str_void:
case StringIds::data_void:
case StringIds::get_allocator_void:
rw_asnprintf (&buf, &bufsize,
"%{+} ()");
break;
case StringIds::begin_const_void:
case StringIds::end_const_void:
case StringIds::rbegin_const_void:
case StringIds::rend_const_void:
rw_asnprintf (&buf, &bufsize,
"%{+} () const");
break;
case StringIds::ctor_alloc:
rw_asnprintf (&buf, &bufsize,
"%{+} (const allocator_type&)");
break;
case StringIds::erase_size:
case StringIds::substr_size:
case StringIds::op_index_size:
case StringIds::at_size:
rw_asnprintf (&buf, &bufsize,
"%{+} (%zu)", pcase->off);
break;
case StringIds::op_index_const_size:
case StringIds::at_const_size:
rw_asnprintf (&buf, &bufsize,
"%{+} (%zu) const", pcase->off);
break;
case StringIds::erase_size_size:
case StringIds::substr_size_size:
rw_asnprintf (&buf, &bufsize,
"%{+} (%zu, %zu)", pcase->off, pcase->size);
break;
case StringIds::erase_iter:
rw_asnprintf (&buf, &bufsize,
"%{+} (begin()%{?} + %zu%{;})",
0 != pcase->off, pcase->off);
break;
case StringIds::erase_iter_iter:
rw_asnprintf (&buf, &bufsize,
"%{+} (begin()%{?} + %zu%{;}, begin()%{?} + %zu%{;})",
0 != pcase->off, pcase->off,
0 != range1_end, range1_end);
break;
case StringIds::op_plus_cptr_cstr:
case StringIds::op_equal_cptr_cstr:
case StringIds::op_not_equal_cptr_cstr:
case StringIds::op_less_cptr_cstr:
case StringIds::op_less_equal_cptr_cstr:
case StringIds::op_greater_cptr_cstr:
case StringIds::op_greater_equal_cptr_cstr:
// format zero ptr argument without size as arg.c_str()
rw_asnprintf (&buf, &bufsize,
"%{+} (%{?}arg2.c_str()%{:}%{#*s}%{;}, "
"%{$CLASS}(%{#*s}))",
0 == str, int (str_len), str, int (arg_len), arg);
break;
case StringIds::op_plus_cstr_cptr:
case StringIds::op_equal_cstr_cptr:
case StringIds::op_not_equal_cstr_cptr:
case StringIds::op_less_cstr_cptr:
case StringIds::op_less_equal_cstr_cptr:
case StringIds::op_greater_cstr_cptr:
case StringIds::op_greater_equal_cstr_cptr:
// format zero ptr argument without size as arg.c_str()
rw_asnprintf (&buf, &bufsize,
"%{+} (%{$CLASS}(%{#*s}), "
"%{?}arg1.c_str()%{:}%{#*s}%{;})",
int (str_len), str, self, int (arg_len), arg);
break;
case StringIds::op_plus_cstr_cstr:
case StringIds::op_equal_cstr_cstr:
case StringIds::op_not_equal_cstr_cstr:
case StringIds::op_less_cstr_cstr:
case StringIds::op_less_equal_cstr_cstr:
case StringIds::op_greater_cstr_cstr:
case StringIds::op_greater_equal_cstr_cstr:
// format zero str argument without size as arg
rw_asnprintf (&buf, &bufsize,
"%{+} (%{?}arg2%{:}%{$CLASS}(%{#*s})%{;}, "
"%{?}arg1%{:}%{$CLASS}(%{#*s})%{;})",
0 == str, int (str_len), str, self, int (arg_len), arg);
break;
case StringIds::op_plus_cstr_val:
rw_asnprintf (&buf, &bufsize,
"%{+} (%{$CLASS}(%{#*s}), %{#c})",
int (arg_len), arg, pcase->val);
break;
case StringIds::op_plus_val_cstr:
rw_asnprintf (&buf, &bufsize,
"%{+} (%{#c}, %{$CLASS}(%{#*s}))",
pcase->val, int (arg_len), arg);
break;
case StringIds::extractor_istream_str:
case StringIds::getline_istream_str:
rw_asnprintf (&buf, &bufsize,
"%{+} (%{$ISTREAM}&, %{$CLASS}(%{?}%{#*s}%{;}))",
0 < str_len, int (str_len), str);
break;
case StringIds::getline_istream_str_val:
rw_asnprintf (&buf, &bufsize,
"%{+} (%{$ISTREAM}&, %{$CLASS}(%{?}%{#*s}%{;}), %{#c})",
0 < str_len, int (str_len), str, pcase->val);
break;
case StringIds::inserter_ostream_cstr:
rw_asnprintf (&buf, &bufsize,
"%{+} (%{$OSTREAM}&, %{$CLASS}(%{?}%{#*s}%{;}))",
0 < str_len, int (str_len), str);
break;
case StringIds::resize_size_val:
rw_asnprintf (&buf, &bufsize,
"%{+} (%zu, %{#c})", pcase->size, pcase->val);
break;
case StringIds::resize_size:
case StringIds::reserve_size:
rw_asnprintf (&buf, &bufsize,
"%{+} (%zu)", pcase->size);
break;
default:
RW_ASSERT (!"test logic error: unknown overload");
}
rw_fprintf (0, "%{$FUNCALL!:*}", buf);
free (buf);
if (str != str_buf)
delete[] str;
if (arg != arg_buf)
delete[] arg;
}
/**************************************************************************/
// helper function to reverse substring in the resulting sequence
_RWSTD_INTERNAL StringTestCase
_rw_reverse_results (const StringTestCase &tsrc,
size_t off, size_t ext)
{
// expand expected results
size_t res_len = 0;
char* const new_res = rw_expand ((char*)0, tsrc.res, tsrc.nres, &res_len);
// reverse them
const size_t res_off = off;
const size_t res_ext = (ext < res_len ? ext : res_len) - 1;
char* beg = new_res + res_off;
char* end = beg + res_ext;
for (; beg < end; ++beg, --end) {
const char tmp = *beg;
*beg = *end;
*end = tmp;
}
// form new test case
const StringTestCase new_case = {
tsrc.line, tsrc.off, tsrc.size, tsrc.off2,
tsrc.size2, tsrc.val, tsrc.str, tsrc.str_len,
tsrc.arg, tsrc.arg_len, new_res, res_len, tsrc.bthrow
};
return new_case;
}
template <class charT, class Traits, class Allocator>
void
_rw_dispatch (charT*, Traits*, Allocator*,
VoidFunc* const *farray,
const StringFunc &func,
const StringTestCase &tcase)
{
typedef StringTestCaseData<charT> Data;
typedef void TestFunc (charT*, Traits*, Allocator*, const Data&);
const size_t inx = func.char_id_ * 4 + func.traits_id_ * 2 + func.alloc_id_;
TestFunc* const tfunc = _RWSTD_REINTERPRET_CAST (TestFunc*, farray [inx]);
if (0 == tfunc) {
rw_error (0, __FILE__, __LINE__,
"logic error: null test function for %{$FUNCSIG}");
return;
}
const bool reverse_iter =
StringIds::ReverseIterator == func.iter_id_
|| StringIds::ConstReverseIterator == func.iter_id_;
const Data tdata (func, tcase);
if (reverse_iter) {
// special processing for reverse iterators
const size_t func_id = StringIds::fid_mask & int (tdata.func_.which_);
const bool like_ctor = StringIds::fid_ctor == func_id
|| StringIds::fid_assign == func_id;
// ctor and assignment operator require the full string reverse
const size_t off = like_ctor ? 0 : tdata.off1_;
const size_t ext = like_ctor ? tdata.reslen_ : tdata.ext2_;
const StringTestCase rev_tcase =
::_rw_reverse_results (tcase, off, ext);
const Data rev_tdata (func, rev_tcase);
tfunc ((charT*)0, (Traits*)0, (Allocator*)0, rev_tdata);
// clean up allocated memory, if any
delete[] rev_tcase.res;
}
else
tfunc ((charT*)0, (Traits*)0, (Allocator*)0, tdata);
}
template <class charT, class Traits>
void
_rw_dispatch (charT*, Traits*,
VoidFunc* const *farray,
const StringFunc &func,
const StringTestCase &tcase)
{
if (StringIds::DefaultAlloc == func.alloc_id_) {
typedef std::allocator<charT> Alloc;
_rw_dispatch ((charT*)0, (Traits*)0, (Alloc*)0, farray, func, tcase);
}
else if (StringIds::UserAlloc == func.alloc_id_) {
typedef UserAlloc<charT> Alloc;
_rw_dispatch ((charT*)0, (Traits*)0, (Alloc*)0, farray, func, tcase);
}
else {
RW_ASSERT (!"logic error: unknown Allocator argument");
}
}
template <class charT>
void
_rw_dispatch (charT*,
VoidFunc* const *farray,
const StringFunc &func,
const StringTestCase &tcase)
{
if (StringIds::DefaultTraits == func.traits_id_) {
typedef std::char_traits<charT> Traits;
_rw_dispatch ((charT*)0, (Traits*)0, farray, func, tcase);
}
else if (StringIds::UserTraits == func.traits_id_) {
typedef UserTraits<charT> Traits;
_rw_dispatch ((charT*)0, (Traits*)0, farray, func, tcase);
}
else {
RW_ASSERT (!"logic error: unknown Traits argument");
}
}
static void
_rw_dispatch (VoidFunc* const *farray,
const StringFunc &func,
const StringTestCase &tcase)
{
if (StringIds::Char == func.char_id_) {
_rw_dispatch ((char*)0, farray, func, tcase);
}
else if (StringIds::WChar == func.char_id_) {
_rw_dispatch ((wchar_t*)0, farray, func, tcase);
}
else if (StringIds::UChar == func.char_id_) {
if (StringIds::DefaultTraits == func.traits_id_) {
RW_ASSERT (!"logic error: std::char_traits<UserChar> not allowed");
}
else if (StringIds::UserTraits == func.traits_id_) {
typedef UserTraits<UserChar> Traits;
_rw_dispatch ((UserChar*)0, (Traits*)0, farray, func, tcase);
}
}
else {
RW_ASSERT (!"logic error: unknown charT argument");
}
}
/**************************************************************************/
// exercise a single test case for the given function
static void
_rw_test_case (const StringFunc &func,
const StringTestCase &tcase,
StringTestFunc *test_callback,
VoidFunc* const *farray)
{
// check to see if this is an exception safety test case
// and avoid running it when exception safety has been
// disabled via a command line option
if (-1 == tcase.bthrow && _rw_opt_no_exception_safety) {
// issue only the first note
rw_note (1 < _rw_opt_no_exception_safety++, _rw_this_file, __LINE__,
"exception safety tests disabled");
return;
}
// check to see if this is a test case that involves the throwing
// of an exception and avoid running it when exceptions have been
// disabled
if (tcase.bthrow && _rw_opt_no_exceptions) {
// issue only the first note
rw_note (1 < _rw_opt_no_exceptions++, _rw_this_file, __LINE__,
"exception tests disabled");
return;
}
const bool self_ref = 0 == tcase.arg;
// check for tests exercising self-referential modifications
// (e.g., insert(1, *this))
if (_rw_opt_self_ref < 0 && self_ref) {
// issue only the first note
rw_note (0, _rw_this_file, tcase.line,
"self-referential test disabled");
return;
}
else if (0 < _rw_opt_self_ref && !self_ref) {
// issue only the first note
rw_note (0, _rw_this_file, tcase.line,
"non-self-referential test disabled");
return;
}
// check to see if the test case is enabled
if (rw_enabled (tcase.line)) {
// set the {FUNCALL} environment variable to describe
// the function call specified by this test case
rw_setvars (func, &tcase);
if (test_callback) {
// invoke the test callback function
test_callback (func, tcase);
}
else {
_rw_dispatch (farray, func, tcase);
}
}
else
rw_note (0, _rw_this_file, tcase.line,
"test on line %d disabled", tcase.line);
}
/**************************************************************************/
static StringTestFunc*
_rw_test_callback;
static VoidFunc* const*
_rw_func_array;
// exercise all test cases defined for the given function
static void
_rw_run_cases (const StringFunc &func,
const StringTest &test)
{
// set the {CLASS}, {FUNC}, and {FUNCSIG} environment
// variable to the name of the basic_string specializaton
// and the string function being exercised
rw_setvars (func);
// determine whether the function is a member function
const bool is_member = 0 != (StringIds::bit_member & int (test.which));
// compute the function overload's 0-based index
const size_t siginx = _rw_get_func_inx (test.which);
// check if tests of the function overload
// have been disabled
if (0 == rw_note (0 <= _rw_opt_func [siginx], _rw_this_file, __LINE__,
"%{?}%{$CLASS}::%{;}%{$FUNCSIG} tests disabled",
is_member))
return;
rw_info (0, 0, 0, "%{?}%{$CLASS}::%{;}%{$FUNCSIG}", is_member);
const size_t case_count = test.case_count;
// iterate over all test cases for this function
// overload invoking the test case handler for each
// in turn
for (size_t n = 0; n != case_count; ++n) {
const StringTestCase& tcase = test.cases [n];
_rw_test_case (func, tcase, _rw_test_callback, _rw_func_array);
}
}
/**************************************************************************/
static void
_rw_toggle_options (int *opts, size_t count)
{
for (size_t i = 0; i != count; ++i) {
if (0 < opts [i]) {
// if one or more options has been explicitly enabled
// treat all those that haven't been as if they had
// been disabled
for (i = 0; i != count; ++i) {
if (0 == opts [i])
opts [i] = -1;
}
break;
}
}
}
static int
_rw_run_test (int, char*[])
{
#ifdef _RWSTD_NO_EXCEPTIONS
rw_note (0, 0, 0, "exception tests disabled (macro "
"_RWSTD_NO_EXCEPTIONS #defined)");
// disable all exception tests and avoid further notes
_rw_no_exceptions = 2;
_rw_no_exception_safety = 2;
#endif // _RWSTD_NO_EXCEPTIONS
#ifdef _RWSTD_NO_WCHAR_T
rw_note (0, 0, 0, "wchar_t tests disabled (macro "
"_RWSTD_NO_WCHAR_T #defined)");
// disable wchar_t tests and avoid further notes
_rw_opt_char_types [StringIds::WChar] = -2;
#endif // _RWSTD_NO_WCHAR_T
// see if any option controlling a string function has been
// explicitly enabled and if so disable all those that haven't
// been (i.e., so that --enable-foo-size will have the effect
// of specifying --disable-foo-val and --disable-foo-range,
// given the three overloads of foo)
const size_t nopts = sizeof _rw_opt_func / sizeof *_rw_opt_func;
_rw_toggle_options (_rw_opt_func, nopts);
static const StringIds::CharId char_types[] = {
StringIds::Char, StringIds::WChar, StringIds::UChar
};
static const StringIds::TraitsId traits_types[] = {
StringIds::DefaultTraits, StringIds::UserTraits
};
static const StringIds::AllocId alloc_types[] = {
StringIds::DefaultAlloc, StringIds::UserAlloc
};
static const StringIds::IteratorId iter_types[] = {
StringIds::Input, StringIds::Forward,
StringIds::Bidir, StringIds::Random,
StringIds::Pointer, StringIds::ConstPointer,
StringIds::Iterator, StringIds::ConstIterator,
StringIds::ReverseIterator, StringIds::ConstReverseIterator
};
const size_t n_char_types = sizeof char_types / sizeof *char_types;
const size_t n_traits_types = sizeof traits_types / sizeof *traits_types;
const size_t n_alloc_types = sizeof alloc_types / sizeof *alloc_types;
const size_t n_iter_types = sizeof iter_types / sizeof *iter_types;
// see if any option controlling the basic_string template arguments
// explicitly enabled and if so disable all those that haven't been
_rw_toggle_options (_rw_opt_char_types, n_char_types);
_rw_toggle_options (_rw_opt_traits_types, n_traits_types);
_rw_toggle_options (_rw_opt_alloc_types, n_alloc_types);
_rw_toggle_options (_rw_opt_iter_types, n_iter_types);
// exercise different charT specializations last
for (size_t i = 0; i != n_char_types; ++i) {
if (_rw_opt_char_types [i] < 0) {
// issue only the first note
rw_note (-1 > _rw_opt_char_types [i]--,
_rw_this_file, __LINE__,
"%s tests disabled", _rw_char_names [i]);
continue;
}
// exercise all specializations on Traits before those on charT
for (size_t j = 0; j != n_traits_types; ++j) {
if (0 == j && StringIds::UChar == char_types [i]) {
// std::char_traits can only be instantiated on
// char and wchar_t, only UserTraits may be used
// with UserChar
continue;
}
if (_rw_opt_traits_types [j] < 0) {
// issue only the first note
rw_note (-1 > _rw_opt_traits_types [j]--,
_rw_this_file, __LINE__,
"%s tests disabled", _rw_traits_names [j]);
continue;
}
for (size_t k = 0; k != n_alloc_types; ++k) {
if (_rw_opt_alloc_types [k] < 0) {
// issue only the first note
rw_note (-1 > _rw_opt_alloc_types [k]--,
_rw_this_file, __LINE__,
"%s tests disabled", _rw_alloc_names [k]);
continue;
}
for (size_t m = 0; m != _rw_string_test_count; ++m) {
const StringTest& test = _rw_string_tests [m];
// create an object uniquely identifying the overload
// of the string function exercised by the set of test
// cases defined to exercise it
StringFunc func = {
char_types [i],
traits_types [j],
alloc_types [k],
StringIds::None,
test.which
};
// determine whether the function is a template
if (-1 < _rw_argno (test.which, StringIds::arg_range)) {
// iterate over the standard iterator categories
// and iterator types the template might perhaps
// be specialized on
for (size_t l = 0; l != n_iter_types; ++l) {
if (_rw_opt_iter_types [l] < 0) {
// issue only the first note
rw_note (-1 > _rw_opt_iter_types [l]--,
_rw_this_file, __LINE__,
"%s tests disabled",
_rw_iter_names [l]);
continue;
}
func.iter_id_ = iter_types [l];
// exercise all test cases defined for
// the function template
_rw_run_cases (func, test);
}
}
else {
// exercise all test cases defined for the ordinary
// (i.e., non-template) function
_rw_run_cases (func, test);
}
}
}
}
}
return 0;
}
/**************************************************************************/
// add a bunch of toggle-type command line options based on the names array
static void
_rw_add_toggles (char **pbuf, size_t *pbufsize,
const char* const names[], size_t count)
{
for (size_t i = 0; i != count; ++i) {
rw_asnprintf (pbuf, pbufsize, "%{+}|-%s~ ", names [i]);
}
}
static int
_rw_run_test (int argc,
char *argv [],
const char *file,
const char *clause,
StringTestFunc *test_callback,
VoidFunc* const *func_array,
const StringTest *tests,
size_t test_count)
{
// set the global variables accessed in _rw_run_test
_rw_test_callback = test_callback;
_rw_func_array = func_array,
_rw_string_tests = tests;
_rw_string_test_count = test_count;
// put together a command line option specification with options
// to enable and disable tests exercising functions for all known
// specializations of the functions specified by the test array
char *optbuf = 0;
size_t optbufsize = 0;
rw_asnprintf (&optbuf, &optbufsize,
"|-no-exceptions# "
"|-no-exception-safety# "
"|-self-ref~ ");
const size_t n_chars = sizeof _rw_char_names / sizeof *_rw_char_names;
const size_t n_traits = sizeof _rw_traits_names / sizeof *_rw_traits_names;
const size_t n_allocs = sizeof _rw_alloc_names / sizeof *_rw_alloc_names;
const size_t n_iters = sizeof _rw_iter_names / sizeof *_rw_iter_names;
// see if any option has been explicitly enabled and if so,
// uncodnitionally disable all those that have not been
_rw_add_toggles (&optbuf, &optbufsize, _rw_char_names, n_chars);
_rw_add_toggles (&optbuf, &optbufsize, _rw_traits_names, n_traits);
_rw_add_toggles (&optbuf, &optbufsize, _rw_alloc_names, n_allocs);
_rw_add_toggles (&optbuf, &optbufsize, _rw_iter_names + 1, n_iters - 1);
for (size_t i = 0; i != test_count; ++i) {
// for each function append a command line option specification
// to allow to enable or disable it
rw_asnprintf (&optbuf, &optbufsize, "%{+}|-");
_rw_sigcat (&optbuf, &optbufsize, 0, tests [i].which);
rw_asnprintf (&optbuf, &optbufsize, "%{+}~ ");
}
RW_ASSERT (test_count <= 32);
RW_ASSERT (test_count <= MAX_OVERLOADS);
// process command line arguments run tests
const int status =
rw_test (argc, argv, file, clause,
0, // comment
_rw_run_test, // test callback
optbuf, // option specification
// handlers controlling exceptions
&_rw_opt_no_exceptions,
&_rw_opt_no_exception_safety,
// handler controlling self-referential modifiers
&_rw_opt_self_ref,
// handlers controlling specializations of the template
// ...on the charT template parameter
_rw_opt_char_types + 0,
_rw_opt_char_types + 1,
_rw_opt_char_types + 2,
// ...on the Traits template parameter
_rw_opt_traits_types + 0,
_rw_opt_traits_types + 1,
// ...on the Allocator template parameter
_rw_opt_alloc_types + 0,
_rw_opt_alloc_types + 1,
// FIXME: add handlers (and options) only for tests
// that exercise member templates
// handlers controlling specializations of the member
// template (if this is one) on the InputIterator
// template parameter
_rw_opt_iter_types + 0,
_rw_opt_iter_types + 1,
_rw_opt_iter_types + 2,
_rw_opt_iter_types + 3,
_rw_opt_iter_types + 4,
_rw_opt_iter_types + 5,
_rw_opt_iter_types + 6,
_rw_opt_iter_types + 7,
_rw_opt_iter_types + 8,
_rw_opt_iter_types + 9,
// FIXME: install exactly as many handlers (and options)
// as there are distinct functions being exercised
// handlers for up to 32 overloads
_rw_opt_func + 0,
_rw_opt_func + 1,
_rw_opt_func + 2,
_rw_opt_func + 3,
_rw_opt_func + 4,
_rw_opt_func + 5,
_rw_opt_func + 6,
_rw_opt_func + 7,
_rw_opt_func + 8,
_rw_opt_func + 9,
_rw_opt_func + 10,
_rw_opt_func + 11,
_rw_opt_func + 12,
_rw_opt_func + 13,
_rw_opt_func + 14,
_rw_opt_func + 15,
_rw_opt_func + 16,
_rw_opt_func + 17,
_rw_opt_func + 18,
_rw_opt_func + 19,
_rw_opt_func + 20,
_rw_opt_func + 21,
_rw_opt_func + 22,
_rw_opt_func + 23,
_rw_opt_func + 24,
_rw_opt_func + 25,
_rw_opt_func + 26,
_rw_opt_func + 27,
_rw_opt_func + 28,
_rw_opt_func + 29,
_rw_opt_func + 30,
_rw_opt_func + 31,
// sentinel
(void*)0);
// free storage allocated for the option specification
free (optbuf);
return status;
}
_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)
{
return _rw_run_test (argc, argv, file, clause, callback, 0, tests, count);
}
_TEST_EXPORT int
rw_run_string_test (int argc,
char *argv [],
const char *file,
const char *clause,
VoidFunc* const *farray,
const StringTest *tests,
size_t count)
{
return _rw_run_test (argc, argv, file, clause, 0, farray, tests, count);
}