The test is comitted here:
http://svn.apache.org/viewcvs?rev=386577&view=rev

Oops, I forgot to set properties. Here is the corrected version:
http://svn.apache.org/viewcvs?rev=386584&view=rev
Sorry about that.

I modified it according to your notes below. The patch is attached. Here
is the ChangeLog:

2006-03-17  Anton Pevtsov  <[EMAIL PROTECTED]>

        * 21.string.replace.cpp (ReplaceData): Removed as obsolete
        (TestCase): New structure to store a test case
        (test_cases): Static array of the test cases
        (test_replace): Functions updated to use TestCase and
        test_cases[] instead of ReplaceData.


Martin Sebor wrote:

I agree that trying to allocate huge amounts of memory is not a good way to test the class.
[...]

A more reliable way to do almost the same thing is to exercise the template on a user-defined traits or allocator type. The allocator
approach is better since basic_string::max_size() uses its
allocator_type::max_size(). The (theoretical) downside to this is that
if basic_string were explicitly specialized on char and wchar_t in the
library (as opposed to being explicitly instantiated as it is
now) the technique won't exercise the same same code in the char and
wchar_t case.

I think it would be useful to exercise the string class using our custom
allocator in any case.

Thanks,
Anton Pevtsov


-----Original Message-----
From: Martin Sebor [mailto:[EMAIL PROTECTED] Sent: Friday, March 17, 2006 05:42
To: [email protected]
Subject: Re: test for 21.string::replace


Anton Pevtsov wrote:

The attached file contains new version of the test for
string::replace.

Excellent!


You might want to add tests cases to be sure that the test covers all
possible cases.

I'll look into it. I will definitely want to enhance the tests with long
strings, maybe even generate a few. This is the most important function
in all of basic_string.



And there are two issues with this test:

1. It contains workaround for empty strings with UserChars formatting
output. The cause is in the implementation of the %{#*S} directive: it

tries to cast basic_string<UserChar, ... > to string<char, ...> then gets incorrect string size and finally fails. As a stub it is possible

to ignore "unknown" strings, but some callback for this case will be more useful. What do you think about it?

I'm hoping to come up with a generic formatting directive that can be
used with all three types of strings: char*, wchar_t*, and UserChar*.
Something along the lines of the _rw_fmtxarrayv() function in
alg_test.cpp that does the formatting of arrays of X, but a little bit
more generic (i.e., with an additional argument telling the function if
it's dealing with char*, wchar_t*, or UserChar*).



2. There is no test case which results in the length_error exception
thrown by replace. The possible way to test this case requires the huge string with length about SIZE_MAX / 2 and I think this not good idea. I think we can try to use our own "string" class with modified size() method to emulate this case, but will this be the appropriate test?

I agree that trying to allocate huge amounts of memory is not a good way
to test the class. We can (and should), however, emulate low memory
conditions by setting a lower memory limit by calling setrlimit():
http://www.opengroup.org/onlinepubs/009695399/functions/getrlimit.html
That's something different than what you're talking about, though, as
that will induce a bad_alloc exception and not length_error.

It might be possible to explicitly specialize a member function of
basic_string (such as max_size) in the test to try to induce an
exception sooner. I believe some of our tests actually do that (I have
written them). Unfortunately, this technique is not safe since the
template is already instantiated in the library (both explicitly as well
as implicitly by virtue of being used in locale). Doing so violates the
One Definition Rule (one definition of the function is in the library
and another in the test) and may be detected by some compilers (e.g.,
EDG eccp detects it in "export" mode).

A more reliable way to do almost the same thing is to exercise the
template on a user-defined traits or allocator type. The allocator
approach is better since basic_string::max_size() uses its
allocator_type::max_size(). The (theoretical) downside to this is that
if basic_string were explicitly specialized on char and wchar_t in the
library (as opposed to being explicitly instantiated as it is
now) the technique won't exercise the same same code in the char and
wchar_t case.

Please go ahead and commit it as it is and let's make improvements
(including those below) as the second pass.

One minor thing I'd like to adjust is the format of some of the
diagnostics. Instead of

# TEXT: line 354. std::basic_string<char, char_traits<char>, allocator<char>>("abc").replace (0, 2, "cc") == "ccdefgc", "ccdefgc"
expected

I would prefer to see

# TEXT: line 354. std::basic_string<char, char_traits<char>, allocator<char>>("abc").replace (0, 2, "cc") == "ccdefgc", got "ccdefgc"

I.e., the string on the right hand side of == should be the expected
result, with the actual result to follow after ", got"

I also think that it might be more space efficient (in terms of a
significantly reduced number of function calls) in this case to create a
data structure for each test case and build an array of them to store
them all and then simply iterate over the array one element at a time.
It should be easy to make this change and see how much of a space
difference it made.

Here's what I have in mind:

    static const struct {
        int line;
        const char *str;
        int         pos1;
        int         num1;
        const char* src;
        int         pos2;
        int         num2;
        int         cnt;
        int         ch;
        const char* res;
        int         it_res;
        int         bthrow;
    } test_cases[] = {
#define TEST(str, pos1, num1, src, pos2, num2, cnt, \
            ch, res, it_res, bthrow) \
     { __LINE__, str, pos1, num1, src, pos2, num2, cnt,  \
       ch, res, it_res, bthrow }

        TEST ("ab",  0, 1, "c", 0, 1, 2, 'c', "cb", "cb", 0);
        ...
    };

    static void test_replace () {
        //...
        const std::size_t ncases =
            sizeof test_cases / sizeof *test_cases;

        for (std::size_t i = 0; i != ncases; ++i)
            test_replace (pfid, tets_case [i].line, which, ...);
    }

Thanks
Martin

Index: 21.string.replace.cpp
===================================================================
--- 21.string.replace.cpp       (revision 386635)
+++ 21.string.replace.cpp       (working copy)
@@ -1,6 +1,6 @@
 /***************************************************************************
  *
- * string.replace.cpp - string test exercising [lib.string::replace]
+ * 21.string.replace.cpp - string test exercising [lib.string::replace]
  *
  * $Id$ 
  *
@@ -61,48 +61,175 @@
 static const int long_string_len = 4096;
 static char long_string [long_string_len];
 
+static const int long_parity_len = (long_string_len - 1) & 0x01 ? 
+           (long_string_len - 1) / 2 : (long_string_len - 2) / 2;
+
 static const char* exp_exceptions[] = 
     { "unknown exception", "out_of_range", "length_error" };
 
 /**************************************************************************/
 
-struct ReplaceData
-{
-    ReplaceData (char* str, std::size_t str_len, int pos1, int num1, 
-                 char* src, std::size_t src_len, int pos2, int num2, 
-                 int cnt, char ch, char* res, std::size_t res_len,
-                 char* it_res, std::size_t it_res_len) :
-        pos1_ (pos1), num1_ (num1), pos2_ (pos2), num2_ (num2),
-        cnt_ (cnt), ch_ (ch), str_ (str), str_len_ (str_len), src_ (src), 
-        src_len_ (src_len), res_ (res), res_len_ (res_len), it_res_ (it_res), 
-        it_res_len_ (it_res_len) {
-    }
+static const struct TestCase {
 
-    int pos1_;
-    int num1_;
-    int pos2_;
-    int num2_;
-    int cnt_;
-    char ch_;
+    int  line;
 
-    char* str_;
-    std::size_t str_len_;
+    int  pos1;
+    int  num1;
+    int  pos2;
+    int  num2;
+    int  cnt;
+    char ch;
 
-    char* src_;
-    std::size_t src_len_;
+    char* str;
+    std::size_t str_len;
 
-    char* res_;
-    std::size_t res_len_;
+    char* src;
+    std::size_t src_len;
 
-    char* it_res_;
-    std::size_t it_res_len_;
+    char* res;
+    std::size_t res_len;
+
+    char* it_res;
+    std::size_t it_res_len;
+
+    int bthrow;
+
+} test_cases [] = {
+
+#undef TEST
+#define TEST(str, pos1, num1, src, pos2, num2, cnt, ch, res, it_res, bthrow) \
+    { __LINE__, pos1, num1, pos2, num2, cnt, ch, (char*) str,                \
+      sizeof str - 1, (char*) src, sizeof src - 1, (char*) res,              \
+      sizeof res - 1, (char*) it_res, sizeof it_res - 1, bthrow }
+
+    //    +----------------------------------------- controlled sequence
+    //    |      +---------------------------------- replace() pos1 argument
+    //    |      |  +------------------------------- replace() n1 argument
+    //    |      |  |  +---------------------------- replace with sequence
+    //    |      |  |  |          +----------------- replace() pos2 argument 
+    //    |      |  |  |          |  +-------------- replace() n2 argument 
+    //    |      |  |  |          |  |  +----------- replace() count argument 
+    //    |      |  |  |          |  |  |  +-------- replace() with character
+    //    |      |  |  |          |  |  |  |    +--- expected result sequence
+    //    |      |  |  |          |  |  |  |    |  + expected result sequence 
+    //    |      |  |  |          |  |  |  |    |  | for iterators
+    //    |      |  |  |          |  |  |  |    |  |    exception info ----+ 
+    //    |      |  |  |          |  |  |  |    |  |    0 - no exception   |   
+    //    |      |  |  |          |  |  |  |    |  |    1,2 - out_of_range |   
+    //    |      |  |  |          |  |  |  |    |  |    3 - length_error   |   
+    //    |      |  |  |          |  |  |  |    |  |                       |
+    //    |      |  |  |          |  |  |  |    |  +----------+            |
+    //    V      V  V  V          V  V  V  V    V             V            V
+    TEST ("ab",  0, 1, "c",       0, 1, 2, 'c', "cb",         "cb",        0),
+
+    TEST ("",    0, 0, "",        0, 0, 0, 'c', "",           "",          0),
+    TEST ("",    0, 0, "abc",     0, 3, 3, 'c', "abc",        "abc",       0),
+
+    TEST ("ab",  0, 2, "",        0, 0, 0, 'c', "",           "",          0),
+    TEST ("ab",  0, 1, "",        0, 0, 0, 'c', "b",          "b",         0),
+
+    TEST ("\0",  0, 1, "",        0, 0, 0, ' ', "",           "",          0),
+    TEST ("\0",  0, 1, "a",       0, 1, 1, 'a', "a",          "a",         0),
+    TEST ("\0",  0, 1, "\0\0",    1, 1, 1, '\0', "\0",        "\0",        0),
+    TEST ("\0",  0, 1, "\0\0",    0, 2, 2, '\0', "\0\0",      "\0\0",      0),
+
+    TEST ("ah",  0, 1, "bcdefg",  0, 3, 1, 'c',  "bcdh",      "bcdefgh",   0),
+    TEST ("ah",  1, 1, "bcdefg",  0, 3, 1, 'c',  "abcd",      "abcdefg",   0),
+    TEST ("ah",  0, 1, "bcdefg",  1, 3, 4, 'c',  "cdeh",      "bcdefgh",   0),
+    TEST ("ah",  1, 1, "bcdefg",  1, 3, 4, 'c',  "acde",      "abcdefg",   0),
+    TEST ("ah",  0, 1, "bcdefg",  0, 6, 1, 'c',  "bcdefgh",   "bcdefgh",   0),
+    TEST ("ah",  1, 1, "bcdefg",  0, 6, 1, 'c',  "abcdefg",   "abcdefg",   0),
+
+    TEST ("abc", 0, 2, "cc",      0, 2, 2, 'c',  "ccc",       "ccc",       0),
+    TEST ("abc", 1, 2, "cc",      0, 2, 2, 'c',  "acc",       "acc",       0),
+
+    TEST ("abc", 0, 3, "d",       0, 1, 1, 'c',  "d",         "d",         0),
+    TEST ("abc", 0, 3, "def",     0, 3, 3, 'c',  "def",       "def",       0),
+    TEST ("abc", 0, 3, "defgh",   0, 5, 5, 'c',  "defgh",     "defgh",     0),
+    TEST ("abc", 2, 1, "defgh",   4, 1, 1, 'c',  "abh",       "abdefgh",   0),
+    TEST ("abc", 2, 1, "de\0gh",  2, 1, 1, 'c',  "ab\0",      "abde\0gh",  0),
+    TEST ("abc", 2, 1, "",        0, 0, 0, 'c',  "ab",        "ab",        0),
+
+    TEST ("abc", 1, 1, "defgh",   1, 2, 5, 'c',  "aefc",      "adefghc",   0),
+    TEST ("abc", 0, 0, "ee",      0, 2, 2, 'c',  "eeab",      "eeab",      0),
+    TEST ("abc", 0, 0, "\0\0e\0", 0, 4, 4, '\0', "\0\0e\0ab", "\0\0e\0ab", 0),
+    TEST ("abc", 2, 0, "ee",      0, 2, 2, 'c',  "abee",      "abee",      0),
+    TEST ("abc", 2, 0, "\0e\0\0", 0, 4, 4, '\0', "ab\0e\0\0", "ab\0e\0\0", 0),
+    TEST ("abc", 1, 0, "ee",      0, 2, 2, 'c',  "aeebc",     "aeebc",     0),
+
+    TEST ("abc", 1, 0, "\0e\0\0", 0, 4, 4, '\0', "a\0e\0\0bc", 
+                                                             "a\0e\0\0bc", 0),
+
+    TEST ("a\0b\0\0c", 0, 3, "",    0, 0, 1, '\0', "\0\0c",    "\0\0c",    0),
+    TEST ("\0ab\0\0c", 0, 3, "",    0, 0, 1, '\0', "\0\0c",    "\0\0c",    0),
+    TEST ("a\0b\0\0c", 0, 3, "\0e", 0, 2, 1, '\0', "\0e\0\0c", "\0e\0\0c", 0),
+
+    TEST ("a\0b\0\0c", 2, 3, "\0e", 0, 2, 1, '\0', "a\0\0ec",  "a\0\0ec",  0),
+    TEST ("a\0b\0\0c", 2, 3, "\0e", 1, 1, 1, '\0', "a\0ec",    "a\0\0ec",  0),
+    TEST ("\0ab\0\0c", 2, 3, "\0e", 0, 2, 1, '\0', "\0a\0ec",  "\0a\0ec",  0),
+    TEST ("\0ab\0\0c", 2, 3, "\0e\0\0", 
+                                    1, 3, 5, '\0', "\0ae\0\0c", 
+                                                            "\0a\0e\0\0c", 0),
+
+    TEST ("a\0b\0\0c", 0, 6, "\0e", 0, 2, 2, '\0', "\0e",      "\0e",      0),
+    TEST ("a\0b\0\0c", 0, 6, "\0e", 0, 1, 2, '\0', "\0",       "\0e",      0),
+
+    TEST ("\0ab\0\0c", 0, 0, "\0e", 0, 2, 2, '\0', "\0e\0ab\0\0c", 
+                                                           "\0e\0ab\0\0c", 0),
+    TEST ("a\0b\0c\0", 6, 0, "e\0", 0, 2, 2, '\0', "a\0b\0c\0e\0", 
+                                                           "a\0b\0c\0e\0", 0),
+    TEST ("\0ab\0\0c", 5, 0, "\0e", 0, 2, 2, '\0', "\0ab\0\0\0ec", 
+                                                           "\0ab\0\0\0ec", 0),
+
+    TEST (long_string, 0, long_string_len - 1, "ab", 
+                                      0, 2, 2, 'a',  "ab",      "ab",      0),
+    TEST (long_string, 1, long_string_len - 2, "ab", 
+                                      0, 2, 2, 'a',  "xab",     "xab",     0),
+    TEST (long_string, 0, long_string_len - 2, "ab", 
+                                      0, 2, 2, 'a',  "abx",     "abx",     0),
+    TEST (long_string, 1, long_string_len - 3, "", 
+                                      0, 0, 0, 'a',  "xx",      "xx",      0),
+    TEST (long_string, 1, long_string_len - 4, "\0\0", 
+                                      0, 2, 1, '\0', "x\0\0xx", "x\0\0xx", 0),
+
+    TEST ("a", 0, 1, long_string, 0, long_string_len - 1, long_string_len - 1, 
+                                            'a', long_string, long_string, 0),
+
+    TEST (long_string, 0, long_string_len - 1, long_string, 0, 
+                                 long_string_len - 1, long_string_len - 1, 
+                                            'a', long_string, long_string, 0),
+
+    TEST (long_string, 0, long_parity_len, long_string, 0, 
+                                 long_parity_len, long_parity_len, 
+                                            'a', long_string, long_string, 0),
+
+    TEST (long_string, long_parity_len, long_string_len - 1 - long_parity_len, 
+       long_string, 0, long_string_len - 1 - long_parity_len, 
+                       long_string_len - 1 - long_parity_len, 
+                                            'a', long_string, long_string, 0),
+
+#ifndef _RWSTD_NO_EXCEPTIONS
+
+    TEST ("\0",        2, 0, "",    0, 0, 0, ' ',  "",        "",          1),
+    TEST ("\0",        0, 0, "\0",  2, 0, 0, ' ',  "",        "",          2),
+
+    TEST ("a",        10, 0, "",    0, 0, 0, ' ',  "",        "",          1),
+    TEST ("a",         0, 0, "a",  10, 0, 0, ' ',  "",        "",          2),
+
+    TEST (long_string, long_string_len + 10, 0, "", 0, 0, 0,  ' ', "", "", 1),
+    TEST (long_string, 0, 0, long_string, long_string_len + 10, 
+                                                       0, 0,  ' ', "", "", 2),
+
+#endif   // _RWSTD_NO_EXCEPTIONS
+
+    TEST ("last",  0, 4, "test",    0, 4, 4, 't',  "test",    "test",      0)
 };
 
 /**************************************************************************/
 
 template <class String>
 String& test_replace (int                          which,
-                      const ReplaceData           &rd, 
+                      const TestCase              &cs,
                       String                      &str, 
                       typename String::value_type *wsrc, 
                       bool                         test,
@@ -113,54 +240,51 @@
     if (!test && (4 == which || 7 == which))
         return str;
 
-    const String& ref_src = String (wsrc, rd.src_len_);
+    const String& ref_src = String (wsrc, cs.src_len);
 
     // construct iterators
-    int first = std::size_t (rd.pos1_) > str.size () ? 0 : rd.pos1_;
-    int last  = rd.pos1_ + rd.num1_;
+    int first = std::size_t (cs.pos1) > str.size () ? 0 : cs.pos1;
+    int last  = cs.pos1 + cs.num1;
 
     typename String::iterator it_first (str.begin () + first);
 
-    typename String::iterator it_last (std::size_t (last) >= rd.str_len_ ?
+    typename String::iterator it_last (std::size_t (last) >= cs.str_len ?
         str.end () : str.begin () + last);
 
     switch (which) {
         case 1: {
             if (test)
-                return str.replace (rd.pos1_, rd.num1_, wsrc);
+                return str.replace (cs.pos1, cs.num1, wsrc);
             else
-                return str.replace (rd.pos1_, rd.num1_, 
-                                    String (wsrc));
+                return str.replace (cs.pos1, cs.num1, String (wsrc));
         }
         case 2: {
             if (test)
-                return str.replace (rd.pos1_, rd.num1_, ref_src);
+                return str.replace (cs.pos1, cs.num1, ref_src);
             else
-                return str.replace (rd.pos1_, rd.num1_, ref_src, 
+                return str.replace (cs.pos1, cs.num1, ref_src, 
                                     0, String::npos);
         }
         case 3: {
             if (test)
-                return str.replace (rd.pos1_, rd.num1_, wsrc, rd.num2_);
+                return str.replace (cs.pos1, cs.num1, wsrc, cs.num2);
             else
-                return str.replace (rd.pos1_, rd.num1_, 
-                                    String (wsrc, rd.num2_));
+                return str.replace (cs.pos1, cs.num1, String (wsrc, cs.num2));
         }
         case 4: {
             if (test)
-                return str.replace (rd.pos1_, rd.num1_, ref_src, 
-                                    rd.pos2_, rd.num2_);
+                return str.replace (cs.pos1, cs.num1, ref_src, 
+                                    cs.pos2, cs.num2);
             else
                 return str;
         }
         case 5: {
             if (test)
-                return str.replace (rd.pos1_, rd.num1_, rd.cnt_, 
-                                    make_char (rd.ch_, 
-                                    (typename  String::value_type*)0)); 
+                return str.replace (cs.pos1, cs.num1, cs.cnt, make_char (
+                                    cs.ch, (typename  String::value_type*)0));
             else
-                return str.replace (rd.pos1_, rd.num1_, 
-                                    String (rd.cnt_, make_char (rd.ch_, 
+                return str.replace (cs.pos1, cs.num1, 
+                                    String (cs.cnt, make_char (cs.ch, 
                                     (typename String::value_type*)0)));
         }
         case 6: {
@@ -182,36 +306,36 @@
                 return str;
         }
         case 8: {
-            *exp_len = str.length () + rd.num2_ - (it_last - it_first);
+            *exp_len = str.length () + cs.num2 - (it_last - it_first);
 
             if (test)
-                return str.replace (it_first, it_last, wsrc, rd.num2_);
+                return str.replace (it_first, it_last, wsrc, cs.num2);
             else
                 return str.replace (it_first, it_last, 
-                                    String (wsrc, rd.num2_));
+                                    String (wsrc, cs.num2));
         }
         case 9: {
-            *exp_len = str.length () + rd.cnt_ - (it_last - it_first);
+            *exp_len = str.length () + cs.cnt - (it_last - it_first);
 
             if (test)
-                return str.replace (it_first, it_last, rd.cnt_, 
-                                    make_char (rd.ch_, 
+                return str.replace (it_first, it_last, cs.cnt, 
+                                    make_char (cs.ch, 
                                     (typename String::value_type*)0));
             else
                 return str.replace (it_first, it_last, 
-                                    String (rd.cnt_, make_char (rd.ch_, 
+                                    String (cs.cnt, make_char (cs.ch, 
                                     (typename String::value_type*)0)));
         }
         case 10: {
             // construct iterators
-            int last2 = rd.pos2_ + rd.num2_;
+            int last2 = cs.pos2 + cs.num2;
 
             InputIter<typename String::value_type> src_first = 
-                make_iter (wsrc + rd.pos2_, wsrc + rd.pos2_, wsrc + last2, 
+                make_iter (wsrc + cs.pos2, wsrc + cs.pos2, wsrc + last2, 
                         InputIter<typename String::value_type> (0, 0, 0));
 
             InputIter<typename String::value_type> src_last  = 
-                make_iter (wsrc + last2, wsrc + rd.pos2_, wsrc + last2, 
+                make_iter (wsrc + last2, wsrc + cs.pos2, wsrc + last2, 
                         InputIter<typename String::value_type> (0, 0, 0));
 
             *exp_len = str.length () + (src_last.cur_ - src_first.cur_) - 
@@ -232,11 +356,9 @@
 
 template <class charT, class Traits>
 void test_replace (charT, Traits*, 
-                   int                line,
-                   int                which,
-                   MemFun            *pfid, 
-                   const ReplaceData &rd,
-                   int                should_throw)
+                   int             which,
+                   MemFun         *pfid, 
+                   const TestCase &cs)
 {
     typedef std::basic_string <charT, Traits, 
                                std::allocator<charT> > TestString;
@@ -250,19 +372,19 @@
     bool use_iters = (6 <= which);
 
     char* pstrres = use_res ? 
-        use_iters ? rd.it_res_ : rd.res_ 
-      : rd.str_;
+        use_iters ? cs.it_res : cs.res 
+      : cs.str;
 
     std::size_t res_len = use_res ? 
-        use_iters ? rd.it_res_len_ : rd.res_len_ 
-      : rd.str_len_;
+        use_iters ? cs.it_res_len : cs.res_len 
+      : cs.str_len;
 
-    rw_widen (wstr, rd.str_, rd.str_len_);
-    rw_widen (wsrc, rd.src_, rd.src_len_);
+    rw_widen (wstr, cs.str, cs.str_len);
+    rw_widen (wsrc, cs.src, cs.src_len);
     rw_widen (wres, pstrres, res_len);
 
-    TestString s_str (wstr, rd.str_len_);
-    TestString s_src (wsrc, rd.src_len_);
+    TestString s_str (wstr, cs.str_len);
+    TestString s_src (wsrc, cs.src_len);
     TestString s_res (wres, res_len);
 
     // used to workaround the problem with empty UserChar strings output
@@ -272,20 +394,20 @@
     bool src_use_empty = 
         0 == s_src.size () && sizeof (charT) > sizeof (wchar_t);
 
-    int first1_off = rd.pos1_;
-    int last1_off  = rd.pos1_ + rd.num1_; 
+    int first1_off = cs.pos1;
+    int last1_off  = cs.pos1 + cs.num1; 
 
-    int first2_off = rd.pos2_;
-    int last2_off  = rd.pos2_ + rd.num2_;
+    int first2_off = cs.pos2;
+    int last2_off  = cs.pos2 + cs.num2;
 
 #ifndef _RWSTD_NO_EXCEPTIONS
 
     // is some exception expected ?
     const char* expected = 0;
     if (!use_iters) {
-        if (1 == should_throw || 2 == should_throw && 4 == which)
+        if (1 == cs.bthrow || 2 == cs.bthrow && 4 == which)
             expected = exp_exceptions[1];
-        else if (3 == should_throw)
+        else if (3 == cs.bthrow)
             expected = exp_exceptions[2];
     }
 
@@ -300,9 +422,9 @@
     std::size_t dummy_len = 0;
 
     TestString& res_str = 
-        test_replace (which, rd, s_str, wsrc, true, &exp_len);
+        test_replace (which, cs, s_str, wsrc, true, &exp_len);
     TestString& ctl_str = 
-        test_replace (which, rd, s_res, wsrc, false, &dummy_len);
+        test_replace (which, cs, s_res, wsrc, false, &dummy_len);
 
 #define CALLFMAT                                                             \
     "line %d. std::basic_string<%s, %s<%2$s>, %s<%2$s>>(%{#*s})."            \
@@ -314,21 +436,21 @@
     "%{?}, begin + %zu%{;}%{?}, begin + %zu%{;})"
 
 #define CALLARGS                                                             \
-    __LINE__, pfid->cname_, pfid->tname_, pfid->aname_, int (rd.str_len_),   \
-    rd.str_, 5 >= which, rd.pos1_, 6 <= which, first1_off,                   \
-    5 >= which, rd.num1_, 6 <= which, last1_off,                             \
+    __LINE__, pfid->cname_, pfid->tname_, pfid->aname_, int (cs.str_len),    \
+    cs.str, 5 >= which, cs.pos1, 6 <= which, first1_off,                     \
+    5 >= which, cs.num1, 6 <= which, last1_off,                              \
     1 == which || 3 == which || 6 == which || 8 == which,                    \
-    int (rd.src_len_), rd.src_, 2 == which || 4 == which || 7 == which,      \
+    int (cs.src_len), cs.src, 2 == which || 4 == which || 7 == which,        \
     int (sizeof (charT)), src_use_empty ? &s_empty : &s_src,                 \
-    5 == which || 9 == which, rd.cnt_, 4 == which, rd.pos2_,                 \
-    3 == which || 4 == which || 8 == which, rd.num2_,                        \
-    5 == which || 9 == which, rd.ch_, 10 == which, first2_off,               \
+    5 == which || 9 == which, cs.cnt, 4 == which, cs.pos2,                   \
+    3 == which || 4 == which || 8 == which, cs.num2,                         \
+    5 == which || 9 == which, cs.ch, 10 == which, first2_off,                \
     10 == which, last2_off
 
     // verify the results
     if (4 == which || 7 == which) {
         // verify the returned value
-        rw_assert (&res_str == &s_str, 0, line,
+        rw_assert (&res_str == &s_str, 0, cs.line,
                    CALLFMAT " : the returned reference is invalid", CALLARGS);
     }
 
@@ -336,7 +458,7 @@
     if (use_iters) {
         // verify the length
         std::size_t len = res_str.length ();
-        rw_assert (len == exp_len, 0, line,
+        rw_assert (len == exp_len, 0, cs.line,
                    CALLFMAT " : result length is %zu, %zu expected",
                    CALLARGS, len, exp_len);
     }
@@ -350,10 +472,10 @@
     bool use_empty_ctl = 
         0 == ctl_str.size () && sizeof (charT) > sizeof (wchar_t);
 
-    rw_assert (success, 0, line,
-               CALLFMAT " == %{#*S}, %{#*S} expected", CALLARGS, 
-               int (sizeof (charT)), use_empty_res ? &s_empty : &res_str, 
-               int (sizeof (charT)), use_empty_ctl ? &s_empty : &ctl_str);
+    rw_assert (success, 0, cs.line,
+               CALLFMAT " == %{#*S}, got %{#*S}", CALLARGS, 
+               int (sizeof (charT)), use_empty_ctl ? &s_empty : &ctl_str,
+               int (sizeof (charT)), use_empty_res ? &s_empty : &res_str);
 
 #ifndef _RWSTD_NO_EXCEPTIONS
 
@@ -372,7 +494,7 @@
     _RWSTD_UNUSED (should_throw);
 #endif   // _RWSTD_NO_EXCEPTIONS
 
-    rw_assert (caught == expected, 0, line,
+    rw_assert (caught == expected, 0, cs.line,
                CALLFMAT " %{?}expected %s, caught %s"
                "%{:}unexpectedly caught %s%{;}",
                CALLARGS, 0 != expected, expected, caught, caught);
@@ -380,47 +502,6 @@
 
 /**************************************************************************/
 
-void test_replace (MemFun            *pfid,
-                   int                line,
-                   int                which,
-                   const ReplaceData &rd,
-                   int                should_throw)
-{
-#undef TEST
-#define TEST(charT, Traits)     \
-    test_replace (charT(), (Traits*)0, line, which, pfid, rd, should_throw)
-
-    if (!rw_enabled (line)) {
-        rw_note (0, 0, __LINE__, "test on line %d disabled", line);
-        return;
-    }
-
-    if (MemFun:: DefaultTraits == pfid->tid_) {
-        if (MemFun::Char == pfid->cid_)
-            TEST (char, std::char_traits<char>);
-
-#ifndef _RWSTD_NO_WCHAR_T
-        else
-            TEST (wchar_t, std::char_traits<wchar_t>);
-#endif   // _RWSTD_NO_WCHAR_T
-
-    }
-    else {
-        if (MemFun::Char == pfid->cid_)
-            TEST (char, UserTraits<char>);
-
-#ifndef _RWSTD_NO_WCHAR_T
-        else if (MemFun::WChar == pfid->cid_)
-            TEST (wchar_t, UserTraits<wchar_t>);
-#endif   // _RWSTD_NO_WCHAR_T
-
-        else
-            TEST (UserChar, UserTraits<UserChar>);
-    }
-}
-
-/**************************************************************************/
-
 static int rw_opt_no_char_traits;              // for --no-char_traits
 static int rw_opt_no_user_traits;              // for --no-user_traits
 
@@ -440,7 +521,9 @@
 
 /**************************************************************************/
 
-void test_replace (MemFun* pfid, int which)
+static void 
+test_replace (MemFun *pfid,
+              int     which)
 {
     rw_info (0, 0, 0, "std::basic_string<%s, %s<%1$s>, %s<%1$s>>::"
              "replace (%{?}size_type pos1%{;}%{?}iterator i1%{;}"
@@ -456,138 +539,47 @@
              4 == which, 3 == which || 4 == which || 8 == which,
              5 == which || 9 == which, 10 == which, 10 == which);
 
-    std::size_t long_parity_len = (long_string_len - 1) & 0x01 ? 
-        (long_string_len - 1) / 2 : (long_string_len - 2) / 2;
-
 #undef TEST
-#define TEST(str, pos1, num1, src, pos2, num2, cnt, ch, res, it_res, bthrow)   
\
-    test_replace (pfid, __LINE__, which, ReplaceData ((char*) str,             
\
-                  sizeof str - 1, pos1, num1, (char*) src,                     
\
-                  sizeof src - 1, pos2, num2, cnt, ch, (char*) res,            
\
-                  sizeof res - 1, (char*) it_res, sizeof it_res - 1), bthrow)  
                     
+#define TEST(charT, Traits, cs)                                    \
+    test_replace (charT(), (Traits*)0, which, pfid, cs)
 
-    //    +----------------------------------------- controlled sequence
-    //    |      +---------------------------------- replace() pos1 argument
-    //    |      |  +------------------------------- replace() n1 argument
-    //    |      |  |  +---------------------------- replace with sequence
-    //    |      |  |  |          +----------------- replace() pos2 argument 
-    //    |      |  |  |          |  +-------------- replace() n2 argument 
-    //    |      |  |  |          |  |  +----------- replace() count argument 
-    //    |      |  |  |          |  |  |  +-------- replace() with character
-    //    |      |  |  |          |  |  |  |    +--- expected result sequence
-    //    |      |  |  |          |  |  |  |    |  + expected result sequence 
-    //    |      |  |  |          |  |  |  |    |  | for iterators
-    //    |      |  |  |          |  |  |  |    |  |    exception info ----+ 
-    //    |      |  |  |          |  |  |  |    |  |    0 - no exception   |   
-    //    |      |  |  |          |  |  |  |    |  |    1,2 - out_of_range |   
-    //    |      |  |  |          |  |  |  |    |  |    3 - length_error   |   
-    //    |      |  |  |          |  |  |  |    |  |                       |
-    //    |      |  |  |          |  |  |  |    |  +----------+            |
-    //    V      V  V  V          V  V  V  V    V             V            V
-    TEST ("ab",  0, 1, "c",       0, 1, 2, 'c', "cb",         "cb",        0);
+    static const std::size_t ncases = sizeof test_cases / sizeof *test_cases;
 
-    TEST ("",    0, 0, "",        0, 0, 0, 'c', "",           "",          0);
-    TEST ("",    0, 0, "abc",     0, 3, 3, 'c', "abc",        "abc",       0);
+    for (std::size_t i = 0; i != ncases; ++i) {
 
-    TEST ("ab",  0, 2, "",        0, 0, 0, 'c', "",           "",          0);
-    TEST ("ab",  0, 1, "",        0, 0, 0, 'c', "b",          "b",         0);
+        if (!rw_enabled (test_cases[i].line)) {
+            rw_note (0, 0, __LINE__, 
+                     "test on line %d disabled", test_cases[i].line);
+            continue;
+        }
 
-    TEST ("\0",  0, 1, "",        0, 0, 0, ' ', "",           "",          0);
-    TEST ("\0",  0, 1, "a",       0, 1, 1, 'a', "a",          "a",         0);
-    TEST ("\0",  0, 1, "\0\0",    1, 1, 1, '\0', "\0",        "\0",        0);
-    TEST ("\0",  0, 1, "\0\0",    0, 2, 2, '\0', "\0\0",      "\0\0",      0);
+        // do not exercise exceptions if they were disabled
+        if (0 != rw_opt_no_exceptions && 0 != test_cases[i].bthrow)
+            continue;
 
-    TEST ("ah",  0, 1, "bcdefg",  0, 3, 1, 'c',  "bcdh",      "bcdefgh",   0);
-    TEST ("ah",  1, 1, "bcdefg",  0, 3, 1, 'c',  "abcd",      "abcdefg",   0);
-    TEST ("ah",  0, 1, "bcdefg",  1, 3, 4, 'c',  "cdeh",      "bcdefgh",   0);
-    TEST ("ah",  1, 1, "bcdefg",  1, 3, 4, 'c',  "acde",      "abcdefg",   0);
-    TEST ("ah",  0, 1, "bcdefg",  0, 6, 1, 'c',  "bcdefgh",   "bcdefgh",   0);
-    TEST ("ah",  1, 1, "bcdefg",  0, 6, 1, 'c',  "abcdefg",   "abcdefg",   0);
+        if (MemFun:: DefaultTraits == pfid->tid_) {
+            if (MemFun::Char == pfid->cid_)
+                TEST (char, std::char_traits<char>, test_cases[i]);
 
-    TEST ("abc", 0, 2, "cc",      0, 2, 2, 'c',  "ccc",       "ccc",       0);
-    TEST ("abc", 1, 2, "cc",      0, 2, 2, 'c',  "acc",       "acc",       0);
+    #ifndef _RWSTD_NO_WCHAR_T
+            else
+                TEST (wchar_t, std::char_traits<wchar_t>, test_cases[i]);
+    #endif   // _RWSTD_NO_WCHAR_T
 
-    TEST ("abc", 0, 3, "d",       0, 1, 1, 'c',  "d",         "d",         0);
-    TEST ("abc", 0, 3, "def",     0, 3, 3, 'c',  "def",       "def",       0);
-    TEST ("abc", 0, 3, "defgh",   0, 5, 5, 'c',  "defgh",     "defgh",     0);
-    TEST ("abc", 2, 1, "defgh",   4, 1, 1, 'c',  "abh",       "abdefgh",   0);
-    TEST ("abc", 2, 1, "de\0gh",  2, 1, 1, 'c',  "ab\0",      "abde\0gh",  0);
-    TEST ("abc", 2, 1, "",        0, 0, 0, 'c',  "ab",        "ab",        0);
+        }
+        else {
+            if (MemFun::Char == pfid->cid_)
+                TEST (char, UserTraits<char>, test_cases[i]);
 
-    TEST ("abc", 1, 1, "defgh",   1, 2, 5, 'c',  "aefc",      "adefghc",   0);
-    TEST ("abc", 0, 0, "ee",      0, 2, 2, 'c',  "eeab",      "eeab",      0);
-    TEST ("abc", 0, 0, "\0\0e\0", 0, 4, 4, '\0', "\0\0e\0ab", "\0\0e\0ab", 0);
-    TEST ("abc", 2, 0, "ee",      0, 2, 2, 'c',  "abee",      "abee",      0);
-    TEST ("abc", 2, 0, "\0e\0\0", 0, 4, 4, '\0', "ab\0e\0\0", "ab\0e\0\0", 0);
-    TEST ("abc", 1, 0, "ee",      0, 2, 2, 'c',  "aeebc",     "aeebc",     0);
+    #ifndef _RWSTD_NO_WCHAR_T
+            else if (MemFun::WChar == pfid->cid_)
+                TEST (wchar_t, UserTraits<wchar_t>, test_cases[i]);
+    #endif   // _RWSTD_NO_WCHAR_T
 
-    TEST ("abc", 1, 0, "\0e\0\0", 0, 4, 4, '\0', "a\0e\0\0bc", 
-                                                             "a\0e\0\0bc", 0);
-
-    TEST ("a\0b\0\0c", 0, 3, "",    0, 0, 1, '\0', "\0\0c",    "\0\0c",    0);
-    TEST ("\0ab\0\0c", 0, 3, "",    0, 0, 1, '\0', "\0\0c",    "\0\0c",    0);
-    TEST ("a\0b\0\0c", 0, 3, "\0e", 0, 2, 1, '\0', "\0e\0\0c", "\0e\0\0c", 0);
-
-    TEST ("a\0b\0\0c", 2, 3, "\0e", 0, 2, 1, '\0', "a\0\0ec",  "a\0\0ec",  0);
-    TEST ("a\0b\0\0c", 2, 3, "\0e", 1, 1, 1, '\0', "a\0ec",    "a\0\0ec",  0);
-    TEST ("\0ab\0\0c", 2, 3, "\0e", 0, 2, 1, '\0', "\0a\0ec",  "\0a\0ec",  0);
-    TEST ("\0ab\0\0c", 2, 3, "\0e\0\0", 
-                                    1, 3, 5, '\0', "\0ae\0\0c", 
-                                                            "\0a\0e\0\0c", 0);
-
-    TEST ("a\0b\0\0c", 0, 6, "\0e", 0, 2, 2, '\0', "\0e",      "\0e",      0);
-    TEST ("a\0b\0\0c", 0, 6, "\0e", 0, 1, 2, '\0', "\0",       "\0e",      0);
-
-    TEST ("\0ab\0\0c", 0, 0, "\0e", 0, 2, 2, '\0', "\0e\0ab\0\0c", 
-                                                           "\0e\0ab\0\0c", 0);
-    TEST ("a\0b\0c\0", 6, 0, "e\0", 0, 2, 2, '\0', "a\0b\0c\0e\0", 
-                                                           "a\0b\0c\0e\0", 0);
-    TEST ("\0ab\0\0c", 5, 0, "\0e", 0, 2, 2, '\0', "\0ab\0\0\0ec", 
-                                                           "\0ab\0\0\0ec", 0);
-
-    TEST (long_string, 0, long_string_len - 1, "ab", 
-                                      0, 2, 2, 'a',  "ab",      "ab",      0);
-    TEST (long_string, 1, long_string_len - 2, "ab", 
-                                      0, 2, 2, 'a',  "xab",     "xab",     0);
-    TEST (long_string, 0, long_string_len - 2, "ab", 
-                                      0, 2, 2, 'a',  "abx",     "abx",     0);
-    TEST (long_string, 1, long_string_len - 3, "", 
-                                      0, 0, 0, 'a',  "xx",      "xx",      0);
-    TEST (long_string, 1, long_string_len - 4, "\0\0", 
-                                      0, 2, 1, '\0', "x\0\0xx", "x\0\0xx", 0);
-
-    TEST ("a", 0, 1, long_string, 0, long_string_len - 1, long_string_len - 1, 
-                                            'a', long_string, long_string, 0);
-
-    TEST (long_string, 0, long_string_len - 1, long_string, 0, 
-                                 long_string_len - 1, long_string_len - 1, 
-                                            'a', long_string, long_string, 0);
-
-    TEST (long_string, 0, long_parity_len, long_string, 0, 
-                                 long_parity_len, long_parity_len, 
-                                            'a', long_string, long_string, 0);
-
-    TEST (long_string, long_parity_len, long_string_len - 1 - long_parity_len, 
-       long_string, 0, long_string_len - 1 - long_parity_len, 
-                       long_string_len - 1 - long_parity_len, 
-                                            'a', long_string, long_string, 0);
-
-#ifndef _RWSTD_NO_EXCEPTIONS
-
-    if (! rw_opt_no_exceptions) {
-        TEST ("\0", 2, 0, "",   0, 0, 0, ' ', "", "", 1);
-        TEST ("\0", 0, 0, "\0", 2, 0, 0, ' ', "", "", 2);
-
-        TEST ("a", 10, 0, "",   0, 0, 0, ' ', "", "", 1);
-        TEST ("a",  0, 0, "a", 10, 0, 0, ' ', "", "", 2);
-
-        TEST (long_string, long_string_len + 10, 0, "",
-                                0, 0, 0, ' ', "", "", 1);
-        TEST (long_string, 0, 0, long_string, long_string_len + 10, 
-                                   0, 0, ' ', "", "", 2);
+            else
+                TEST (UserChar, UserTraits<UserChar>, test_cases[i]);
+        }
     }
-
-#endif   // _RWSTD_NO_EXCEPTIONS
 }
 
 /**************************************************************************/

Reply via email to