The attached file contains the updated version of the test for
21.string.capacity.
I modified the code and pass the tested string length to the widen
function and basic_string ctor to avoid the bug with strings containing
embedded NULs.
But I suspect a bug in the rw_assert formatting output for {#*S}.
The wchar string "abc" is displayed as "a\0b" (maybe the function
dumps each byte, not symbol here).

Btw., maybe it would be useful to move the widen function to rw_char
header (or some another place in the test driver).


With best wishes,
Anton Pevtsov


-----Original Message-----
From: Martin Sebor [mailto:[EMAIL PROTECTED]
Sent: Sunday, March 05, 2006 01:07
To: [email protected]
Subject: Re: test for 21.strings.capacity


Anton Pevtsov wrote:

>> The attached file contains the test for the basic_string methods
>> described in 21.strings.capacity. Here the same to
>> 27.stringbuf.virtuals schema is used. But I think we need to implement


>> our own allocator class for the test purposes to strictly test some
>> methods (max_size, capacity). Also may be useful to develop some
>> analogue of the algorithms tests X class to be used instead of char
>> and wchar_t (according to the standard here may be any POD type).
>> Martin, what do you think about this?


I agree. Exercising the template with user-defined template arguments in
addition to the default ones is important. The header file named
mychar.h contains a user-defined character type and traits class that
was designed for this purpose. The header myallocator.h defines a custom
allocator that we could use. We need to port these headers to the new
driver first (it should be pretty easy). I also want to rename them to
follow the rw_xxx.h convention.

I made a few improvements to the test and committed it here:
http://svn.apache.org/viewcvs?rev=383204&view=rev

My comments are below.

Btw., I noticed a bug in the test I decided not to fix and let you do it
:)  The hardocded strings containing embedded NULs do not always seem to
be handled correctly (with my changes in place you will see it if you
run the test with the --trace option). The string object needs to be
initialized using the two-argument ctor.


>>

[...]


>>
>> int traits_eof = -1;


This shouldn't be necessary. AFAIK, basic_string doesn't use EOF for
anything.


>>
>> template <class charT>
>> struct CharTraits: std::char_traits<charT>
>> {
>>     typedef std::char_traits<charT> Base;
>>     typedef typename Base::int_type int_type;


I think it would be useful to change the int_type here from the default,
say to short or something unusual.


>>
>>     // override eof() to detect bad assumptions
>>     static int_type eof () { return traits_eof; }
>>     static int_type not_eof (int_type c) {
>>         return c == eof () ? int_type (!c) : c;
>>     }


This shouldn't be necessary. As I mentioned above, basic_string doesn't
make use of these functions (they're good for I/O).


>> };
>>
>> /*********************************************************************
>> *****/
>>
>> struct VFun
>> {
>>     enum charT { Char, WChar };
>>     enum Traits { DefaultTraits, UserTraits };
>>     enum VirtualTag {
>>         // which virtual function to exercise


Since (unlike basic_stringbuf) basic_string has no virtual functions I
changed the name of the class and of the tag to make more sense.


>>         size, resize, length, reserve, capacity, max_size, clear,

empty

>>     };
>>

[...]

>> template <class charT>
>> void widen (charT *buf, const char *str)


This function will need to take an additional argument -- the length of
string -- to correctly handle embedded NULs.

[...]

>>     rw_assert (should_throw == ex_thrown, 0, line,
>>                "line %d. basic_string<%s, %s, %s>.resize(%zu%{?},

%#c%{;}) "

>>                "on \"%s\" should throw == %b, was thrown == %b",
>>                __LINE__, pfid->cname_, pfid->tname_, "std::allocator",
>>                nparam, resize2args, chart_param, 0 != str ? str :

"<empty>",

>>                should_throw, ex_thrown);


I changed this and the other statements to use the %{#*S} directive
designed for the formatting of generic basic_string objects. Check it
out, it's quite handy (so handy, in fact, that it exposed the bug I
mentioned above).

[...]

>>     // check the results
>>     static charT wstr_tmp [long_string_len];
>>     widen (wstr_tmp, str);


When str contains embedded NULs they are not handled.

[...]

>> void test_size (VFun *pfid)
>> {
>>     rw_info (0, 0, 0, "basic_string<%s, %s, %s>::size ()",
>>              pfid->cname_, pfid->tname_, "std::allocator");
>>
>>     pfid->vfun_ = VFun::size;


I decided to move this assignment up to the caller for simplicity.


>>
>> #define TEST(str, size)

\

>>     test_string_capacity (pfid, __LINE__, str, sizeof str - 1,

\

>>                           0, 0, size, false)
>>

[...]

I think it's better (less error-prone) to #undef the macro just before
#defining it so I moved the #undef directives immediately above the
#defines.

Martin

/***************************************************************************
 *
 * 21.string.capacity.cpp - test exercising [lib.string.capacity]
 *
 * $Id:
 *
 ***************************************************************************
 *
 * Copyright 2006 The Apache Software Foundation or its licensors,
 * as applicable.
 *
 * Copyright 2006 Rogue Wave Software.
 *
 * Licensed 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.
 *
 **************************************************************************/

#include <string>
#include <cstddef>
#include <stdexcept>

#include <cmdopt.h>
#include <driver.h>

/**************************************************************************/

int traits_eof = -1;

template <class charT>
struct CharTraits: std::char_traits<charT>
{
    typedef std::char_traits<charT> Base;
    typedef typename Base::int_type int_type;

    // override eof() to detect bad assumptions
    static int_type eof () { return traits_eof; }
    static int_type not_eof (int_type c) {
        return c == eof () ? int_type (!c) : c;
    }
};

/**************************************************************************/

struct MemFun
{
    enum charT { Char, WChar };
    enum Traits { DefaultTraits, UserTraits };
    enum FunTag {
        // which member function to exercise
        size, resize, length, reserve, capacity, max_size, clear, empty
    };

    MemFun (charT cid, const char *cname,
          Traits tid, const char *tname)
        : cid_ (cid), tid_ (tid), mfun_ (),
          cname_ (cname), tname_ (tname), aname_ ("allocator"),
          fname_ (0),
          max_size_ (0) { /* empty */ }

    charT       cid_;     // character type id (char or wchar_t)
    Traits      tid_;     // traits type id (default or user-defined)
    FunTag      mfun_;    // member function id
    const char *cname_;   // character type name
    const char *tname_;   // traits name
    const char *aname_;   // allocator name
    const char *fname_;   // function name

    unsigned int max_size_;
};

/**************************************************************************/

static const int long_string_len = 4096;
static char long_string [long_string_len];

/**************************************************************************/

template <class charT>
void widen (charT *buf, const char *str, const std::size_t str_len)
{
    typedef unsigned char UChar;

    buf[0] = charT (UChar ('\0'));
    RW_ASSERT (str_len < sizeof long_string);

    if (str) {
        for (std::size_t i = 0; i < str_len; i++)
            buf[i] = charT (UChar (str[i]));
    }
}

/**************************************************************************/

template <class charT, class String>
void test_resize (charT, const MemFun *pfid,
                  int         line,         // line number
                  String     *pstr,         // pointer string object
                  const char *str,          // source string argument
                  std::size_t str_len,      // the string length
                  std::size_t nparam,       // method parameter
                  char        cparam,       // method parameter char
                  bool        should_throw) // if true the method should throw
{
    typedef unsigned char UChar;
    charT chart_param = charT (UChar (cparam));
    charT chart_eof = charT (UChar ('\0'));

    bool resize2args = charT (UChar (-1)) != chart_param;

#ifndef _RWSTD_NO_EXCEPTIONS

    bool ex_thrown = false;
    try {

#endif    // _RWSTD_NO_EXCEPTIONS

    if (resize2args)
        pstr->resize (nparam, chart_param);
    else
        pstr->resize (nparam);

#ifndef _RWSTD_NO_EXCEPTIONS

    }
    catch (std::length_error e) {
        _RWSTD_UNUSED(e);
        ex_thrown = true;
    }

    rw_assert (should_throw == ex_thrown, 0, line,
               "line %d. basic_string<%s, %s<%2$s>, %s<%2$s>>(%{#*S})"
               ".resize(%zu%{?}, %#c%{;}) "
               "should throw == %b, was thrown == %b",
               __LINE__, pfid->cname_, pfid->tname_, pfid->aname_,
               int (sizeof (charT)), pstr, nparam,
               resize2args, chart_param, should_throw, ex_thrown);

    if (ex_thrown)
        return;

#else   // _RWSTD_NO_EXCEPTIONS

    _RWSTD_UNUSED (should_throw);

#endif

    // check the results
    static charT wstr_tmp [long_string_len];
    widen (wstr_tmp, str, str_len);

    std::size_t ubound = nparam < str_len ? nparam : str_len;
    bool success = true;
    std::size_t i = 0;
    for (; i < ubound; i++) {
        success = wstr_tmp[i] == pstr->c_str()[i];
        if (!success)
            break;
    }

    if (0 < ubound) {
        // to avoid errors in --trace mode
        i = i < ubound ? i : ubound - 1;

        rw_assert (success, 0, line,
                   "line %d. basic_string<%s, %s<%2$s>, %s<%2$s>>(%{#*S})"
                   ".resize(%zu%{?}, %#c%{;}): got %#c at %zu, expected %#c",
                   __LINE__, pfid->cname_, pfid->tname_, pfid->aname_,
                   int (sizeof (charT)), pstr, nparam, resize2args, chart_param,
                   pstr->c_str()[i], i + 1, wstr_tmp[i]);
    }

    if (resize2args) {
        i = ubound;
        ubound = str_len < nparam ? nparam : 0;
        for (; i < ubound; i++) {
            success = chart_param == pstr->c_str()[i];
            if (!success)
                break;
        }

        if (0 < ubound) {
            // to avoid errors in --trace mode
            i = i < ubound ? i : ubound - 1;

            rw_assert (success, 0, line,
                       "line %d. basic_string<%s, %s<%2$s, %s<%2$s>>(%{#*S})."
                       "resize(%zu, %#c): got %{?}%#c%{;}%{?}'%s'%{;} "
                       "at %zu, expected %#c",
                       __LINE__, pfid->cname_, pfid->tname_, pfid->aname_,
                       int (sizeof (charT)), pstr, nparam, cparam,
                       chart_eof != pstr->c_str()[i], pstr->c_str()[i],
                       chart_eof == pstr->c_str()[i], "eof", i + 1,
                       chart_param);
        }
    }
    else {
        const std::string::size_type sz_tmp = pstr->size ();
        rw_assert (nparam == sz_tmp, 0, line,
                   "line %d. basic_string<%s, %s<%2$s>, %s<%2$s>>(%{#*S})"
                   ".resize(%zu): size() == %5$zu, got %zu",
                   __LINE__, pfid->cname_, pfid->tname_, pfid->aname_,
                   int (sizeof (charT)), pstr, nparam, sz_tmp);
    }
}

/**************************************************************************/

template <class charT, class Traits>
void test_string_capacity (charT, Traits, const MemFun *pfid,
                           int         line,         // line number
                           const char *str,          // string argument
                           std::size_t str_len,      // the string length
                           std::size_t nparam,       // method parameter
                           char        cparam,       // method parameter char
                           std::size_t res,          // method expected result
                           bool        should_throw) // the method should throw
{
    typedef std::allocator<charT>                       Allocator;
    typedef std::basic_string<charT, Traits, Allocator> TestString;

    if (!rw_enabled (line)) {
        rw_note (0, 0, 0, "test on line %d disabled", line);
        return;
    }

    // widen the source sequence into the (possibly wide) character buffer
    static charT wstr [long_string_len];
    0 == str ? widen (wstr, "a", 1) : widen (wstr, str, str_len);

    TestString str_ob (wstr, str_len);
    TestString str_def;

    TestString* const pstr = 0 != str ? &str_ob : &str_def;

    if (MemFun::resize == pfid->mfun_)
        return test_resize (charT (), pfid, line, pstr, str, str_len,
                            nparam, cparam, should_throw);

    std::string::size_type ret     = 0;
    std::string::size_type exp_ret = res;

#ifndef _RWSTD_NO_EXCEPTIONS

    const char* const expected = should_throw ? "length_error" : 0;
    const char*       caught   = 0;

    try {

#endif   // _RWSTD_NO_EXCEPTIONS

    // invoke the virtual function with the expected argument (if any)
    switch (pfid->mfun_) {
    case MemFun::size:
        ret = pstr->size ();
        break;

    case MemFun::length:
        ret     = pstr->length ();
        exp_ret = pstr->size ();
        break;

    case MemFun::resize:
        // do nothing, handled above
        break;

    case MemFun::reserve:
        0 == nparam ? pstr->reserve () : pstr->reserve (nparam);
        break;

    case MemFun::capacity:
        ret = pstr->capacity ();
        break;

    case MemFun::max_size:
        ret = pstr->max_size ();
        break;

    case MemFun::empty:
        ret     = pstr->empty () ? 1 : 0;
        exp_ret = 0 == pstr->size() ? 1 : 0;
        break;

    case MemFun::clear:
        pstr->clear ();
        break;
    }

#define CALLFMAT \
    "line %d. basic_string<%s, %s<%2$s>, %s<%2$s>>(%{?}%{#*S}%{;})" \
    ".%s(%{?}%zu%{;})"

#define CALLARGS \
    __LINE__, pfid->cname_, pfid->tname_, pfid->aname_, \
    0 != str, int (sizeof (charT)), pstr, pfid->fname_, \
    MemFun::reserve == pfid->mfun_, nparam

#ifndef _RWSTD_NO_EXCEPTIONS

    }
    catch (std::length_error e) {
        _RWSTD_UNUSED (e);
        caught = expected;
    }
    catch (...) {
        caught = "unknown exception";
    }

    rw_assert (caught == expected, 0, line,
              CALLFMAT " %{?}expected %s, caught %s"
               "%{:}unexpectedly caught %s%{;}",
               CALLARGS, 0 != expected, expected, caught, caught);

    if (should_throw || caught)
        return;

#else   // if defined (_RWSTD_NO_EXCEPTIONS)
    _RWSTD_UNUSED (should_throw);
#endif   // _RWSTD_NO_EXCEPTIONS

    // check the results
    if (MemFun::size == pfid->mfun_ || MemFun::length == pfid->mfun_ ||
        MemFun::empty == pfid->mfun_) {

        rw_assert (exp_ret == ret, 0, line,
                   CALLFMAT " == %zu, expected %zu",
                   CALLARGS, ret, exp_ret);

        return;
    }

    if (MemFun::capacity == pfid->mfun_) {
        std::string::size_type cur_sz = pstr->size();
        std::string::size_type max_sz = pstr->max_size();

        rw_assert (cur_sz <= ret && ret <= max_sz, 0, line,
                   CALLFMAT " == %zu, expected %zu < res < %zu%",
                   CALLARGS, ret, cur_sz, max_sz);
    }

    if (MemFun::max_size == pfid->mfun_) {
        std::string::size_type cur_sz = pstr->size();

        rw_assert (cur_sz <= ret, 0, line,
                   CALLFMAT " == %zu, expected res > %zu",
                   CALLARGS, ret, cur_sz);
    }

    if (MemFun::reserve == pfid->mfun_ ) {
        ret = pstr->capacity ();
        rw_assert (nparam <= ret, 0, line,
                   CALLFMAT ": capacity() >= %zu, got %zu",
                   CALLARGS, nparam, ret);
        return;
    }

    if (MemFun::clear == pfid->mfun_ ) {
        rw_assert (pstr->empty (), 0, line,
                   CALLFMAT ": string not empty", CALLARGS);
        return;
    }
}

/**************************************************************************/

void test_string_capacity (MemFun      *pfid,
                           int          line,
                           const char  *str,
                           std::size_t  str_len,
                           int          nparam,
                           char         cparam,
                           std::size_t  res,
                           bool         should_throw)
{
#undef TEST
#define TEST(charT, Traits)                                                 \
    test_string_capacity (charT (), Traits (), pfid, line,                  \
                          str, str_len, nparam, cparam, res, should_throw)

    static const char* const fnames[] = {
        "size", "resize", "length", "reserve", "capacity", "max_size",
        "clear", "empty"
    };

    if (!rw_enabled (line)) {
        rw_note (0, 0, __LINE__, "test on line %d disabled", line);
        return;
    }

    pfid->fname_ = fnames [pfid->mfun_];

    pfid->max_size_ = MemFun::Char == pfid->cid_ ?
        _RWSTD_SIZE_MAX / sizeof (char) - 1
      : _RWSTD_SIZE_MAX / sizeof (wchar_t) - 1;

    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, CharTraits<char>);

#ifndef _RWSTD_NO_WCHAR_T
        else
            TEST (wchar_t, CharTraits<wchar_t>);
#endif   // _RWSTD_NO_WCHAR_T

    }
}

/**************************************************************************/

void test_size (MemFun *pfid)
{
    rw_info (0, 0, 0, "std::basic_string<%s, %s<%1$s>, %s<%1$s>>::size ()",
             pfid->cname_, pfid->tname_, pfid->aname_);

#undef TEST
#define TEST(str, size)                                         \
    test_string_capacity (pfid, __LINE__, str, sizeof str - 1,  \
                          0, 0, size, false)

    TEST (0, 0);
    TEST ("", 0);

    TEST ("\0", 1);
    TEST ("a",  1);
    TEST (" ",  1);
    TEST ("ab", 2);
    TEST ("bc", 2);

    TEST ("test string", 11);
    TEST ("Test String", 11);

    TEST ("t\000 s", 4);
    TEST ("Test\0string", 11);
    TEST ("Test\000string", 11);

    TEST (long_string, long_string_len - 1);
}

/**************************************************************************/

void test_resize (MemFun *pfid)
{
    rw_info (0, 0, 0,
             "std::basic_string<%s, %s<%1$s>, %s<%1$s>>::resize "
             "(size_type, char_type)",
             pfid->cname_, pfid->tname_, pfid->aname_);

#undef TEST
#define TEST(str, len, nparam, cparam, ex_throw)                \
    test_string_capacity (pfid, __LINE__, str, len, nparam,     \
                          cparam, 0, ex_throw)

    TEST ("\0", 0,  0, 'a', false);
    TEST ("\0", 0, 10, 'a', false);

    TEST ("a", 1,  1, 'a', false);
    TEST ("a", 1,  0, 'a', false);
    TEST ("a", 1, 10, 'a', false);

    TEST ("ab", 2,  2, 'a', false);
    TEST ("ab", 2,  1, 'a', false);
    TEST ("ab", 2, 10, 'a', false);

    TEST ("t\000 s", 1, 6, 'a', false);
    TEST ("Test\0string", 4, 100, 'a', false);

    TEST ("bc", 2, long_string_len - 1, 'a', false);

    TEST (long_string, long_string_len - 1, 10, 'a', false);
    TEST (long_string, long_string_len - 1, long_string_len - 1, 'a', false);

#ifndef _RWSTD_NO_EXCEPTIONS

    if (_RWSTD_SIZE_MAX > pfid->max_size_) {
        TEST ("\0", 1, pfid->max_size_ + 1, 'a', true);
        TEST ("a",  1, pfid->max_size_ + 1, 'a', true);
        TEST (long_string, long_string_len - 1,
              pfid->max_size_ + 1, 'a', true);
    }

#endif   //_RWSTD_NO_EXCEPTIONS

    rw_info (0, 0, 0,
             "std::basic_string<%s, %s<%1$s>, %s<%1$s>>::resize (size_type)",
             pfid->cname_, pfid->tname_, pfid->aname_);

#undef TEST
#define TEST(str, nparam, ex_throw)                             \
    test_string_capacity (pfid, __LINE__, str, sizeof str - 1,  \
                          nparam, -1, 0, ex_throw)

    TEST ("\0", 0, false);
    TEST ("\0", 10, false);

    TEST ("a",   1, false);
    TEST ("a",   0, false);
    TEST ("a",  10, false);

    TEST ("ab",  2, false);
    TEST ("ab",  1, false);
    TEST ("ab", 10, false);

    TEST ("bc", long_string_len - 1, false);

    TEST (long_string, 10, false);
    TEST (long_string, long_string_len - 1, false);

#ifndef _RWSTD_NO_EXCEPTIONS

    if (_RWSTD_SIZE_MAX > pfid->max_size_) {
        TEST ("\0", pfid->max_size_ + 1, true);
        TEST ("a",  pfid->max_size_ + 1, true);
        TEST (long_string, pfid->max_size_ + 1, true);
    }

#endif   // _RWSTD_NO_EXCEPTIONS

}

/**************************************************************************/

void test_length (MemFun *pfid)
{
    rw_info (0, 0, 0, "std::basic_string<%s, %s<%1$s>, %s<%1$s>>::length ()",
             pfid->cname_, pfid->tname_, pfid->aname_);

#undef TEST
#define TEST(str, size)                                                    \
    test_string_capacity (pfid, __LINE__, str, sizeof str - 1,             \
                          0, 0, size, false)

    TEST (0, 0);
    TEST ("", 0);

    TEST ("\0", 1);
    TEST ("a",  1);
    TEST (" ",  1);
    TEST ("ab", 2);
    TEST ("bc", 2);

    TEST ("test string", 11);
    TEST ("Test String", 11);

    TEST ("t\000 s", 4);
    TEST ("Test\0string", 11);
    TEST ("Test\000string", 11);

    TEST (long_string, long_string_len - 1);

#undef TEST
}

/**************************************************************************/

void test_reserve (MemFun *pfid)
{
    rw_info (0, 0, 0,
             "std::basic_string<%s, %s<%1$s>, %s<%1$s>>::reserve (size_type)",
             pfid->cname_, pfid->tname_, pfid->aname_);

#define TEST(str, nparam, ex_throw)                                          \
    test_string_capacity (pfid, __LINE__, str, sizeof str - 1,               \
                          nparam, 0, 0, ex_throw)

    //    +--------------------------------------- controlled sequence
    //    |                +---------------------- reserve() argument
    //    |                |                   +-- exception expected?
    //    |                |                   |
    //    V                V                   V
    TEST (0,               0,                  false);
    TEST (0,              10,                  false);
    TEST (0,              long_string_len - 1, false);

    TEST ("\0",            0,                  false);
    TEST ("\0",           10,                  false);
    TEST ("\0",           long_string_len - 1, false);

    TEST ("abcd",          0,                  false);
    TEST ("abcd",          2,                  false);
    TEST ("abcd",          4,                  false);
    TEST ("abcd",         10,                  false);
    TEST ("abcd",         long_string_len - 1, false);

    TEST ("t\000 s",       1,                  false);
    TEST ("Test\0string",  4,                  false);

    TEST (long_string,    10,                  false);
    TEST (long_string,    long_string_len - 1, false);

#ifndef _RWSTD_NO_EXCEPTIONS

    if (_RWSTD_SIZE_MAX > pfid->max_size_) {
        TEST ("\0", pfid->max_size_ + 1, true);
        TEST ("a",  pfid->max_size_ + 1, true);
        TEST (long_string, pfid->max_size_ + 1, true);
    }

#endif   // _RWSTD_NO_EXCEPTIONS

}

/**************************************************************************/

void test_capacity (MemFun *pfid)
{
    rw_info (0, 0, 0, "std::basic_string<%s, %s<%1$s>, %s<%1$s>>::capacity ()",
             pfid->cname_, pfid->tname_, pfid->aname_);

#undef TEST
#define TEST(str, size)                                         \
    test_string_capacity (pfid, __LINE__, str, sizeof str - 1,  \
                          0, 0, size, false)

    TEST (0, 0);
    TEST ("\0", 0);

    TEST ("a",    128);
    TEST ("abcd", 128);

    TEST ("t\000 s", 128);
    TEST ("Test\0string", 128);

    TEST (long_string, long_string_len - 1);
}

/**************************************************************************/

void test_max_size (MemFun *pfid)
{
    rw_info (0, 0, 0, "std::basic_string<%s, %s<%1$s>, %s<%1$s>>::max_size ()",
             pfid->cname_, pfid->tname_, pfid->aname_);

#undef TEST
#define TEST(str)                                               \
    test_string_capacity (pfid, __LINE__, str, sizeof str - 1,  \
                          0, 0, 0, false)

    TEST (0);
    TEST ("\0");
    TEST ("abcd");
    TEST (long_string);
}

/**************************************************************************/

void test_clear (MemFun *pfid)
{
    rw_info (0, 0, 0, "std::basic_string<%s, %s<%1$s>, %s<%1$s>>::clear ()",
             pfid->cname_, pfid->tname_, pfid->aname_);

#undef TEST
#define TEST(str)                                               \
    test_string_capacity (pfid, __LINE__, str, sizeof str - 1,  \
                          0, 0, 0, false)

    TEST (0);
    TEST ("\0");
    TEST ("a");
    TEST ("ab");
    TEST ("abcde");

    TEST ("t\000 s");
    TEST ("Test\0string");

    TEST (long_string);
}

/**************************************************************************/

void test_empty (MemFun *pfid)
{
    rw_info (0, 0, 0, "std::basic_string<%s, %s<%1$s>, %s<%1$s>>::empty ()",
             pfid->cname_, pfid->tname_, pfid->aname_);

    pfid->mfun_ = MemFun::empty;

#undef TEST
#define TEST(str)                                               \
    test_string_capacity (pfid, __LINE__, str, sizeof str - 1,  \
                          0, 0, 0, false)

    TEST (0);
    TEST ("\0");
    TEST ("a");
    TEST ("ab");
    TEST ("abcde");

    TEST ("\000 s");
    TEST ("t\000 s");
    TEST ("Test\0string");

    TEST (long_string);

#undef TEST
}

/**************************************************************************/

static int rw_opt_no_size;          // for --no-size
static int rw_opt_no_resize;        // for --no-resize
static int rw_opt_no_length;        // for --no-length
static int rw_opt_no_reserve;       // for --no-reserve
static int rw_opt_no_capacity;      // for --no-capacity
static int rw_opt_no_max_size;      // for --no-max_size
static int rw_opt_no_clear;         // for --no-clear
static int rw_opt_no_empty;         // for --no-empty
static int rw_opt_no_char_traits;   // for --no-char_traits
static int rw_opt_no_user_traits;   // for --no-user_traits

/**************************************************************************/

static void
run_test (MemFun *pfid)
{

#undef TEST
#define TEST(function)                                  \
    if (rw_opt_no_ ## function)                         \
        rw_note (1 < rw_opt_no_ ## function++, 0, 0,    \
                 "%s test disabled", #function);        \
    else  {                                             \
        pfid->mfun_ = MemFun::function;                 \
        test_ ## function (pfid);                       \
    } (void)0

    if (pfid->tname_ && rw_opt_no_user_traits) {
        rw_note (1 < rw_opt_no_user_traits++, 0, 0,
                 "user defined traits test disabled");
    }
    else if (!pfid->tname_ && rw_opt_no_char_traits) {
        rw_note (1 < rw_opt_no_char_traits++, 0, 0,
                 "char_traits test disabled");
    }
    else {
        TEST (size);
        TEST (resize);
        TEST (length);
        TEST (reserve);
        TEST (capacity);
        TEST (max_size);
        TEST (clear);
        TEST (empty);        
    }
}

/**************************************************************************/

int run_test (int, char*[])
{
    if ('\0' == long_string [0]) {
        // initialize long_string
        for (std::size_t i = 0; i != sizeof long_string - 1; ++i)
            long_string [i] = 'x';
    }

    if (rw_enabled ("char")) {

        MemFun fid (MemFun::Char, "char", MemFun::DefaultTraits, 0);

        traits_eof = -1;
        fid.tname_ = "char_traits";

        run_test (&fid);

        fid.tid_   = MemFun::UserTraits;
        fid.tname_ = "UserTraits";
        traits_eof = '$';

        run_test (&fid);
    }
    else
        rw_note (0, 0, 0, "string.capacity char tests disabled");

    if (rw_enabled ("wchar_t")) {

        MemFun fid (MemFun::WChar, "wchar_t", MemFun::DefaultTraits, 0);

        traits_eof = -1;
        fid.tname_ = "char_traits";

        run_test (&fid);

        fid.tid_   = MemFun::UserTraits;
        fid.tname_ = "UserTraits";
        traits_eof = '$';

        run_test (&fid);
    }
    else
        rw_note (0, 0, 0, "string.capacity wchar tests disabled");

    return 0;

}

/**************************************************************************/

int main (int argc, char** argv)
{
    return rw_test (argc, argv, __FILE__,
                    "lib.string.capacity",
                    0 /* no comment */, run_test,
                    "|-no-size# "
                    "|-no-resize# "
                    "|-no-length# "
                    "|-no-reserve# "
                    "|-no-capacity# "
                    "|-no-max_size# "
                    "|-no-clear# "
                    "|-no-empty# "
                    "|-no-char_traits# "
                    "|-no-user_traits",
                    &rw_opt_no_size,
                    &rw_opt_no_resize,
                    &rw_opt_no_length,
                    &rw_opt_no_reserve,
                    &rw_opt_no_capacity,
                    &rw_opt_no_max_size,
                    &rw_opt_no_clear,
                    &rw_opt_no_empty,
                    &rw_opt_no_char_traits,
                    &rw_opt_no_user_traits);
}

Reply via email to