Author: vitek Date: Mon Apr 7 18:05:14 2008 New Revision: 645750 URL: http://svn.apache.org/viewvc?rev=645750&view=rev Log:
2008-04-07 Travis Vitek <[EMAIL PROTECTED]> * tests/support/18.support.dynamic.cpp: New test exercising functions and types for dynamic storage management. * tests/support/18.support.rtti.cpp: New test exercising types for dynamic type information support. * tests/diagnostics/19.std.exceptions.cpp: New test exercising standard exception types. Added: stdcxx/trunk/tests/diagnostics/19.std.exceptions.cpp (with props) stdcxx/trunk/tests/support/18.support.dynamic.cpp (with props) stdcxx/trunk/tests/support/18.support.rtti.cpp (with props) Added: stdcxx/trunk/tests/diagnostics/19.std.exceptions.cpp URL: http://svn.apache.org/viewvc/stdcxx/trunk/tests/diagnostics/19.std.exceptions.cpp?rev=645750&view=auto ============================================================================== --- stdcxx/trunk/tests/diagnostics/19.std.exceptions.cpp (added) +++ stdcxx/trunk/tests/diagnostics/19.std.exceptions.cpp Mon Apr 7 18:05:14 2008 @@ -0,0 +1,458 @@ +/*************************************************************************** + * + * 19.std.exceptions.cpp - test exercising [lib.std.exceptions] + * + * $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. + * + * Copyright 2001-2008 Rogue Wave Software. + * + **************************************************************************/ + +#include <stdexcept> + +/**************************************************************************/ + + +template <class Exception> +int test_ex_spec (Exception*, const char *str) +{ +#ifndef _RWSTD_NO_EXCEPTIONS + + try { + // also tests that exception objects can be constructed + // from a const char* argument w/o <string> having been + // explicitly #included first + Exception e (str); + (void)&e; + } + catch (...) { + return 1; + } + +#else // if defined (_RWSTD_NO_EXCEPTIONS); + + _RWSTD_UNUSED (str); + +#endif // _RWSTD_NO_EXCEPTIONS + + return 0; +} + +/**************************************************************************/ + +#include <string> + +/**************************************************************************/ + + +// helpers to verify that each exception's ctor is explicit +// not defined since they must not be referenced if test is successful +void is_explicit (const std::logic_error&); +void is_explicit (const std::domain_error&); +void is_explicit (const std::invalid_argument&); +void is_explicit (const std::length_error&); +void is_explicit (const std::out_of_range&); +void is_explicit (const std::runtime_error&); +void is_explicit (const std::range_error&); +void is_explicit (const std::overflow_error&); +void is_explicit (const std::underflow_error&); + +struct bogus_exception +{ + // also verifies that std::string is declared + bogus_exception (const std::string&) { } + bogus_exception (const char*) { } +}; + +// calls to the overoaded is_explicit (std::string ()) must resolve +// to this function since there must be no implicit conversion from +// std::string to any of the exception classes +void is_explicit (const bogus_exception&) { } + +// exercise the ability to construct exception objects w/o +// explicitly #including <string> first; std::string must still +// be declared (but not necessarily defined) + +#if !defined (_RWSTD_NO_NAMESPACE) && !defined (_RWSTD_NO_HONOR_STD) + // declare a global function with the same name as exception +# define TEST_NAMESPACE_DEF(T) void T () +#else +# define TEST_NAMESPACE_DEF(ignore) (void)0 +#endif // !_RWSTD_NO_NAMESPACE && !_RWSTD_NO_HONOR_STD + + +#ifndef _RWSTD_NO_PTR_EXCEPTION_SPEC +# define _PTR_THROWS(spec) _THROWS (spec) +#else // if defined (_RWSTD_NO_PTR_EXCEPTION_SPEC) + // throw specs on pointers to functions not implemented... +# define _PTR_THROWS(ignore) +#endif // _RWSTD_NO_PTR_EXCEPTION_SPEC + + +// verify that each name is declared in namespace std +// w/o polluting the global namespace +#define TEST_DEF(T) \ + typedef std::T T ## _type; \ + TEST_NAMESPACE_DEF (T); \ + /* construct an object */ \ + std::T obj_ ## T ("std::" _RWSTD_STR (T)); \ + /* assign the address of object to std::exception* */ \ + e = &obj_ ## T; \ + /* verify that assignment can't throw */ \ + std::T& (std::T::*p_assign_ ## T)(const std::T&) \ + _PTR_THROWS(()) = &std::T::operator=; \ + _RWSTD_UNUSED (p_assign_ ## T); \ + /* verify that what() can't throw */ \ + const char* (std::T::*p_what_ ## T)() const \ + _PTR_THROWS(()) = &std::T::what; \ + _RWSTD_UNUSED (p_what_ ## T); \ + /* verify ctor postcondition */ \ + result = result << 1 | cmp (obj_ ## T.what (), \ + "std::" _RWSTD_STR (T)) + + +int cmp (const char *s1, const char *s2) +{ + for (; *s1 && *s1 == *s2; ++s1, ++s2); + return *s2 - *s1; +} + + +// returns 0 on success; on failure returns a bitmap with one bit set +// for every exception that failed its ctor postcondition +static int test_exception_defs () +{ + int result = 0; + + // used below to verify public inheritance from std::exception + std::exception *e = 0; + + TEST_DEF (logic_error); + TEST_DEF (domain_error); + TEST_DEF (invalid_argument); + TEST_DEF (length_error); + TEST_DEF (out_of_range); + TEST_DEF (runtime_error); + TEST_DEF (range_error); + TEST_DEF (overflow_error); + TEST_DEF (underflow_error); + + _RWSTD_UNUSED (e); + +#ifndef _RWSTD_NO_EXPLICIT + + // verify that each exceptions converting ctor is explicit + // use a pointer since std::string need not be a complete class + const char s[40] = ""; + const std::string *ps = _RWSTD_REINTERPRET_CAST (const std::string*, s); + is_explicit (*ps); + + // verify that each exceptions converting ctor from const char* + // (if one exists) is also explicit + is_explicit (s); + +#endif // _RWSTD_NO_EXPLICIT + + return result; +} + +#undef _PTR_THROWS + +/**************************************************************************/ + +#include <rw_new.h> +#include <driver.h> +#include <cstddef> + +/**************************************************************************/ + + +template <class Exception> +int test_throw (Exception*, const char *str) +{ +#ifndef _RWSTD_NO_EXCEPTIONS + + ////////////////////////////////////////////////////////////////// + + try { + throw Exception (str); + } + catch (const Exception &e) { + // caught by const reference + rw_assert (e.what () && !cmp (e.what (), str), + 0, __LINE__, + "caught by const reference; %s::what() == %#s", + str, str); + } + catch (...) { + rw_assert (false, 0, __LINE__, + "threw %s, caught an unknown exception", str); + } + + ////////////////////////////////////////////////////////////////// + + try { + throw Exception (str); + } + catch (Exception e) { + // caught by value + rw_assert (e.what () && !cmp (e.what (), str), + 0, __LINE__, + "caught by value; %s::what() == %#s", + str, str); + } + catch (...) { + rw_assert (false, 0, __LINE__, + "threw %s, caught an unknown exception", str); + } + + ////////////////////////////////////////////////////////////////// + + const Exception ex (str); + + try { + throw ex; + } + catch (Exception e) { + // caught copy by value + rw_assert (e.what () && !cmp (e.what (), str), + 0, __LINE__, + "caught copy by value; %s::what() == %#s", + str, str); + } + catch (...) { + rw_assert (false, 0, __LINE__, + "threw %s, caught an unknown exception", str); + } + + ////////////////////////////////////////////////////////////////// + + try { + throw ex; + } + catch (std::exception &e) { + // caught by non-const reference to a base class + rw_assert (e.what () && !cmp (e.what (), str), + 0, __LINE__, + "caught by non-const reference to base; %s::what() == %#s", + str, str); + } + catch (...) { + rw_assert (false, 0, __LINE__, + "threw %s, caught an unknown exception", str); + } + + ////////////////////////////////////////////////////////////////// + + try { + try { + throw Exception (str); + } + catch (...) { + // rethrown + throw; + } + } + catch (Exception e) { + // rethrown object caught by value + rw_assert (e.what () && !cmp (e.what (), str), + 0, __LINE__, + "caught rethrown by value; %s::what() == %#s", str, str); + } + catch (...) { + rw_assert (false, 0, __LINE__, + "threw %s, caught an unknown exception", str); + } + + ////////////////////////////////////////////////////////////////// + + try { + try { + throw Exception (str); + } + catch (Exception e) { + rw_assert (e.what () && !cmp (e.what (), str), + 0, __LINE__, + "caught by value; %s::what() == %#s", + str, str); + + // rethrown by value + throw e; + } + } + catch (Exception e) { + // rethrown object caught by value + rw_assert (e.what () && !cmp (e.what (), str), + 0, __LINE__, + "caught rethrown copy by value; %s::what() == %#s", + str, str); + } + catch (...) { + rw_assert (false, 0, __LINE__, + "threw %s, caught an unknown exception", str); + } + +#else // if defined (_RWSTD_NO_EXCEPTIONS); + + _RWSTD_UNUSED (t); + _RWSTD_UNUSED (str); + +#endif // _RWSTD_NO_EXCEPTIONS + + return 0; +} + +/**************************************************************************/ + + +static int +run_test (int, char* []) +{ + // verify that exception's (and its derivatives') ctor is explicit + is_explicit (std::string ()); + + const char* const names[] = { + "logic_error", "domain_error", "invalid_argument", "length_error", + "out_of_range", "runtime_error", "range_error", "overflow_error", + "underflow_error" + }; + + // if set, each bit corresponds to a failed exception assertion + const int failures = test_exception_defs (); + + for (unsigned i = 0; i != sizeof names / sizeof *names; ++i) { + rw_assert (!(failures & (1 << i)), 0, __LINE__, + "std::%s::%s (const std::string&) postcondition", + names [i]); + } + + + // have replacement operator new throw an exception + rwt_free_store* const pst = rwt_get_free_store (0); + *pst->throw_at_calls_ [0] = pst->new_calls_ [0] + 1; + + // create a very long string to guarantee that exception ctors + // try to dynamically allocate storage even if it otherwise + // use some clever scheme to avoid doing so + char long_str [0x10000]; + for (unsigned i = 0; i != sizeof long_str - 1; ++i) + long_str [i] = '*'; + + long_str [sizeof long_str - 1] = '\0'; + + int new_throws = 0; + + _TRY { + // see if replacement operator new throws an exception + // when called directly from the program + void *p = ::operator new (sizeof long_str); + ::operator delete (p); + new_throws = 0; + + rw_assert (false, 0, __LINE__, + "replacement ::operator new(std::size_t = %u) failed " + "to throw when called directly from a program", + sizeof long_str); + } + _CATCH (...) { + new_throws = 1; + } + + *pst->throw_at_calls_ [0] = pst->new_calls_ [0] + 1; + + _TRY { + // see if replacement operator new throws an exception + // when called indirectly, i.e., from the library binary + void* const p = _RW::__rw_allocate (sizeof long_str, 0); + _RW::__rw_deallocate (p, 0); + new_throws = 0; + +#ifdef _RWSTD_NO_REPLACEABLE_NEW_DELETE + + // MSVC and VAC++ don't reliably replace operators + // new and delete across shared librray boundaries + + rw_warn (false, 0, __LINE__, + "replacement ::operator new(std::size_t = %u) failed " + "to throw when called from the library: this is an " + "expected failure on this platform", + sizeof long_str); + +#else // if !defined (_RWSTD_NO_REPLACEABLE_NEW_DELETE) + + rw_assert (false, 0, __LINE__, + "replacement ::operator new(std::size_t = %u) " + "unexpectdly failed to throw when called from " + "the library", + sizeof long_str); + +#endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE + + } + _CATCH (...) { + new_throws = 1; + } + +// exercise exception specification on class ctors +// and the ability to throw and catch exception objects +#define TEST_EX_SPEC(T) do { \ + /* do not induce an exception from replacement operator new */ \ + *pst->throw_at_calls_ [0] = std::size_t (-1); \ + *pst->throw_at_calls_ [1] = std::size_t (-1); \ + /* verify that exception objects can be thrown, caught, and rethrown */\ + test_throw ((std:: T*)0, "std::" #T); \ + /* induce an exception from replacement operator new */ \ + *pst->throw_at_calls_ [0] = pst->new_calls_ [0] + 1; \ + *pst->throw_at_calls_ [1] = pst->new_calls_ [1] + 1; \ + /* verify that each exception ctor propagates the exception thrown */ \ + /* from operator new(); failure wil cause a call to terminate() */ \ + /* tests are expected to silently fail if (0 == new_throws) holds */ \ + const int threw = test_ex_spec ((std::T*)0, long_str); \ + rw_assert (threw == new_throws, 0, __LINE__, \ + "attempthing to construct a std::" #T " %s an exception", \ + new_throws ? "failed to rethrow" : "unexpectedly threw"); \ + } while (0) + + TEST_EX_SPEC (logic_error); + TEST_EX_SPEC (domain_error); + TEST_EX_SPEC (invalid_argument); + TEST_EX_SPEC (length_error); + TEST_EX_SPEC (out_of_range); + TEST_EX_SPEC (runtime_error); + TEST_EX_SPEC (range_error); + TEST_EX_SPEC (overflow_error); + TEST_EX_SPEC (underflow_error); + + return 0; +} + +/**************************************************************************/ + + +int main (int argc, char* argv []) +{ + return rw_test (argc, argv, __FILE__, + "lib.std.exceptions", + 0 /* no comment */, + run_test, + "", + (void*)0); +} Propchange: stdcxx/trunk/tests/diagnostics/19.std.exceptions.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: stdcxx/trunk/tests/diagnostics/19.std.exceptions.cpp ------------------------------------------------------------------------------ svn:keywords = Id Added: stdcxx/trunk/tests/support/18.support.dynamic.cpp URL: http://svn.apache.org/viewvc/stdcxx/trunk/tests/support/18.support.dynamic.cpp?rev=645750&view=auto ============================================================================== --- stdcxx/trunk/tests/support/18.support.dynamic.cpp (added) +++ stdcxx/trunk/tests/support/18.support.dynamic.cpp Mon Apr 7 18:05:14 2008 @@ -0,0 +1,478 @@ +/*************************************************************************** + * + * 18.support.dynamic.cpp - test exercising [lib.support.dynamic] + * + * $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. + * + * Copyright 2001-2008 Rogue Wave Software. + * + **************************************************************************/ + +#include <new> +#include <memory> +#include <driver.h> + +#include <rw/_defs.h> +#include <rw/_error.h> + +#include <cstdlib> // for malloc() and free() +#include <cstring> // for strlen() + + +#ifdef _MSC_VER + // verify that <new> et al can coexist with MSVC's <new.h> +# include <new.h> +#endif + +/**************************************************************************/ + +// detects recursive implementation of operator new (size_t, nothrow_t) +static int recursive_new_nothrow = 0; +static int recursive_delete_nothrow = 0; + +// MemoryAllocator is used to replace the global new and delete +// in order to test conformance of of the other operators that +// might be defined in <new> + +struct MemoryAllocator +{ + MemoryAllocator () { + init (); + } + + void* operatorNew (std::size_t n) _THROWS ((std::bad_alloc)) { + _allocPtr = 0; + _newCalled = true; + _bytesRequested = n; + if (_failAlloc) { + _failAlloc = false; + _THROW (std::bad_alloc ()); + } +#if !defined (_RWSTD_NO_EXT_OPERATOR_NEW) && \ + defined (_RWSTD_NO_OPERATOR_NEW_NOTHROW) + + // test our implementation of + // ::operator new(size_t, const std::nothrow) + // this operator must not be implemented in terms + // of ::operator new(size_t) to prevent recursion + + if (recursive_new_nothrow++) + _allocPtr = std::malloc (_bytesRequested); + else + _allocPtr = ::operator new (_bytesRequested, std::nothrow); + + --recursive_new_nothrow; + +#else + _allocPtr = std::malloc (_bytesRequested); +#endif + return _allocPtr; + } + + void operatorDelete (void* ptr) _THROWS (()) { + _deallocPtr = ptr; +#if !defined (_RWSTD_NO_EXT_OPERATOR_NEW) && \ + defined (_RWSTD_NO_OPERATOR_NEW_NOTHROW) + // memory allocated by our nothrow operator new() + if (recursive_delete_nothrow++ || recursive_new_nothrow) + std::free (ptr); + else + ::operator delete (ptr, std::nothrow); + + --recursive_delete_nothrow; +#else + std::free (ptr); +#endif + _deleteCalled = true; + } + + void init () { + _newCalled = _deleteCalled = _failAlloc = false; + _bytesRequested = 0; + _deallocPtr = _allocPtr = 0; + } + + bool newCalled () { + bool tmp = _newCalled; + _newCalled = 0; + return tmp; + } + + bool deleteCalled () { + bool tmp = _deleteCalled; + _deleteCalled = 0; + return tmp; + } + + std::size_t _bytesRequested; + bool _newCalled; + bool _deleteCalled; + bool _failAlloc; + void* _allocPtr; + void* _deallocPtr; +}; + + +// static instance of memory allocator +static MemoryAllocator alloc; + +/**************************************************************************/ + + +// replace the global operators with MemoryAllocator versions +void* operator new (std::size_t size) _THROWS ((std::bad_alloc)) +{ + return alloc.operatorNew (size); +} + +void operator delete (void* p) _THROWS (()) +{ + alloc.operatorDelete (p); +} + +/**************************************************************************/ + + +#define TEST_OP_THROWS(expr,cond,tag) \ + _TRY { \ + alloc._failAlloc = true; \ + expr; \ + rw_assert (cond, 0, __LINE__, tag); \ + } \ + _CATCH (std::bad_alloc) { \ + RW_ASSERT (!cond, 0, __LINE__, tag); \ + } \ + _CATCH (...) { \ + rw_assert (!cond, 0, __LINE__, tag); \ + } \ + (void)0 + +/**************************************************************************/ + + +// provide a handler for unexpected exceptions so that at least the +// test will log the event rather than just aborting +void my_unexpected_handler () +{ + rw_assert (false, 0, __LINE__, "caught an unexpected exception\n"); +} + +// used in exists_set_new_handler below +void my_new_handler () +{ +} + +// grab default throw procedure +void (*default_throw_proc)(int, char*) = _RW::__rw_throw_proc; + +bool my_throw_proc_called = false; + +// my_throw_proc just sets a global flag to indicate +// that it was called, and then dispatches the call +// to the default throw procedure +static void my_throw_proc (int id, char* what) +{ + my_throw_proc_called = true; + default_throw_proc (id, what); +} + +/**************************************************************************/ + + +static +int run_test (int, char* []) +{ + std::set_unexpected (&my_unexpected_handler); + + if (1) { + // exists_std_nothrow + const std::nothrow_t* p = &std::nothrow; + rw_assert (p != 0, 0, __LINE__, "std::nothrow defined"); + } + + if (1) { + // exists_bad_alloc + std::bad_alloc ba1; // default ctor + std::bad_alloc ba2 = ba1; // copy ctor + + std::exception* e = &ba1; // derived from exception + (void) &e; + ba1 = ba2; // assignment operator + + // verify that a member function is accessible and has the + // appropriate signature, including return type and exception + // specification + + std::bad_alloc& (std::bad_alloc::*p_op_assign) + (const std::bad_alloc&) _PTR_THROWS (()) + = &std::bad_alloc::operator=; + _RWSTD_UNUSED (p_op_assign); + + const char* + (std::bad_alloc::*p_what_fn)() const _PTR_THROWS (()) + = &std::bad_alloc::what; + _RWSTD_UNUSED (p_what_fn); + + const char* s = ba1.what (); + rw_assert (s && 0 != std::strlen (s), 0, __LINE__, + "std::bad_alloc::what() returned bad string"); + } + + if (1) { + // set_new_handler + typedef void (*new_handler_t) (); + + new_handler_t (*f) (new_handler_t) _PTR_THROWS (()); + f = &std::set_new_handler; + + rw_assert (f != 0, 0, __LINE__, + "std::set_new_handler() defined"); + + new_handler_t original_handler + = std::set_new_handler (my_new_handler); + +#if !defined (__EDG__) || __EDG_VERSION__ > 245 || defined (__DECCXX) + + // EDG eccp 2.45 standalone demo is known to fail + rw_assert (original_handler == 0, 0, __LINE__, + "std::set_new_handler() unexpectedly returned " + "installed handler"); + +#define _RWSTD_NO_EXT_OPERATOR_NEW + +#endif // !__EDG__ || __EDG_VERSION__ > 245 || __DECCXX + + new_handler_t replacement_handler + = std::set_new_handler (original_handler); + rw_assert (my_new_handler == replacement_handler, 0, __LINE__, + "std::set_new_handler() failed to return previously " + "installed handler"); + } + + // test all operators that we have provided definitions for + // in <new>; exercises the operators by setting the + // replacement allocator to fail, and asserting that an + // exception is thrown or not as appropriate for the operator + if (1) { + // operator new throws + void* ptr = 0; + _RWSTD_UNUSED (ptr); + + alloc.init (); // reset the allocator + +#ifdef _RWSTD_NO_OPERATOR_NEW_NOTHROW + + // verify that the nothrow version of operator new provided + // by our library doesn't call the ordinary operator new + // (if it did it would cause recursion if a replacement operator + // new were to be implemented in terms of the nothrow version) + + // also verify that it returns 0 on failure + + // force a failure by requesting too large a block of storage + // size_t (~0) alone isn't good enough since it causes annoying + // dialog boxes to be popped up by the MSVCRTD, the MSVC runtime + TEST_OP_THROWS ((ptr = operator new (~0U - 4096U, std::nothrow)), + (ptr == 0), + "operator new(size_t, nothrow_t) returns 0"); + + rw_assert (!alloc.newCalled (), 0, __LINE__, + "operator new called by operator new(size_t, nothrow)"); + +#endif // defined _RWSTD_NO_OPERATOR_NEW_NOTHROW + +#if defined (_RWSTD_NO_OPERATOR_DELETE_NOTHROW) && \ + !defined (_RWSTD_NO_PLACEMENT_DELETE) + + // verify that the nothrow version of operator delete provided + // by our library prevents exceptions from propagating + TEST_OP_THROWS ((operator delete (0, std::nothrow)), true, + "operator delete(void*, nothrow_t) doesn't throw"); + + // verify that the nothrow version of operator delete provided + // by our library doesn't call the ordinary operator delete + // (if it did it might cause recursion if a replacement operator + // delete were to be implemented in terms of the nothrow version) + rw_assert (!alloc.deleteCalled (), 0, __LINE__, + "operator delete(void*) called by " + "operator delete(void*, nothrow_t)"); + +#endif // _RWSTD_NO_OPERATOR_DELETE_NOTHROW && _RWSTD_NO_PLACEMENT_DELETE + +#ifdef _RWSTD_NO_OPERATOR_NEW_ARRAY + + // verify that the array form of operator new throws bad_alloc on + // failure + TEST_OP_THROWS ((operator new[] (1)), false, + "operator new[] (size_t) throws bad_alloc"); + + // verify that the array form of operator new provided by our + // library calls the ordinary operator new + rw_assert (alloc.newCalled (), 0, __LINE__, + "operator new called by operator new[](size_t)"); + +#endif // defined _RWSTD_NO_OPERATOR_NEW_ARRAY + +#ifdef _RWSTD_NO_OPERATOR_NEW_ARRAY_NOTHROW + + TEST_OP_THROWS ((ptr = operator new[](1, std::nothrow)), + (ptr == 0), + "operator new[] (size_t, nothrow_t) returns 0"); + + rw_assert (alloc.newCalled (), 0, __LINE__, + "operator new(size_t) called by " + "operator new[](size_t, nothrow_t)"); + +#endif // defined _RWSTD_NO_OPERATOR_NEW_ARRAY_NOTHROW + +#ifdef _RWSTD_NO_OPERATOR_DELETE_ARRAY + + TEST_OP_THROWS ((operator delete[] (0)), true, + "operator delete[] (void*) doesn't throw"); + + rw_assert (alloc.deleteCalled (), 0, __LINE__, + "operator delete called by operator delete[](void*)"); + +#endif // defined _RWSTD_NO_OPERATOR_DELETE_ARRAY + +#if defined (_RWSTD_NO_OPERATOR_DELETE_ARRAY_NOTHROW) && \ + !defined ( _RWSTD_NO_PLACEMENT_DELETE) + + TEST_OP_THROWS ((operator delete[] (0, std::nothrow)), true, + "operator delete[] (void*, nothrow_t) doesn't " + "throw"); + + rw_assert (alloc.deleteCalled (), 0, __LINE__, + "operator delete(void*) called by " + "operator delete[](void*, nothrow_t)"); + +#endif // _RWSTD_NO_OPERATOR_DELETE_ARRAY_NOTHROW && + // !_RWSTD_NO_PLACEMENT_DELETE + + // verify that the nothrow form of operator new provided by our + // library isn't recursively implemented in terms of the ordinary + // operator new + rw_assert (0 == recursive_new_nothrow, 0, __LINE__, + "operator new (size_t, nothrow_t) causes recursion"); + + rw_assert (0 == recursive_delete_nothrow, 0, __LINE__, + "operator delete (void*, nothrow_t) causes recursion"); + } + + // __rw_allocate() is like ::operator new() except that it calls + // __rw_throw() on failure (which may throw std::bad_alloc). + // This test checks that __rw_throw() is called, + // that it properly calls __rw_throw_proc(), and that bad_alloc + // is thrown. We'll use the replaced ::operator new() to + // control when a memory allocation request will fail. + +#ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE + + const bool test_rw_allocate = true; + +#else // if defined (_RWSTD_NO_REPLACEABLE_NEW_DELETE) + + // avoid tests that depend on the replacement operators new + // and delete on platforms like AIX or Win32 where they cannot + // be reliably replaced + const bool test_rw_allocate = false; + +#endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE + + if (test_rw_allocate) { + + alloc.init (); // reset the allocator + + _RW::__rw_throw_proc = my_throw_proc; // set the throw func + my_throw_proc_called = false; + + for (std::size_t i = 0; i < 10; ++i) { + + char* ptr = 0; + + const bool doFail = !!(i % 2); // prevent MSVC warning 4800 + if (doFail) + alloc._failAlloc = true; + + try { + // allocation + alloc._bytesRequested = ~i; // reset + + ptr = _RWSTD_STATIC_CAST (char*, _RW::__rw_allocate (i)); + rw_assert (alloc._bytesRequested == i, 0, __LINE__, + "__rw_allocate (%u) requested %u bytes", + i, alloc._bytesRequested); + + rw_assert (alloc.newCalled (), 0, __LINE__, + "operator new() called"); + rw_assert (!doFail, 0, __LINE__, + "allocation succeeded"); + rw_assert (my_throw_proc_called == false, + 0, __LINE__, + "my_throw_proc called"); + + // deallocation + _RW::__rw_deallocate (ptr, i); + + rw_assert (alloc.deleteCalled (), + 0, __LINE__, + "operator delete() called"); + rw_assert (alloc._deallocPtr == ptr, + 0, __LINE__, + "allocated memory deallocated"); + + } + catch (std::bad_alloc) { + rw_assert (doFail, 0, __LINE__, + "expected bad_alloc exception"); + + rw_assert (my_throw_proc_called == true, 0, __LINE__, + "my_throw_proc called"); + } + catch (...) { + rw_assert (false, 0, __LINE__, + "expected std::bad_alloc exception"); + } + + my_throw_proc_called = false; + } + } + else { + rw_warn (false, 0, __LINE__, + "__rw::__rw_allocate() not exercised: " + "_RWSTD_NO_REPLACEABLE_NEW_DELETE #defined"); + } + + return 0; +} + +/**************************************************************************/ + + +int main (int argc, char* argv []) +{ + return rw_test (argc, argv, __FILE__, + "lib.support.dynamic", + 0 /* no comment */, + run_test, + "", + (void*)0); +} Propchange: stdcxx/trunk/tests/support/18.support.dynamic.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: stdcxx/trunk/tests/support/18.support.dynamic.cpp ------------------------------------------------------------------------------ svn:keywords = Id Added: stdcxx/trunk/tests/support/18.support.rtti.cpp URL: http://svn.apache.org/viewvc/stdcxx/trunk/tests/support/18.support.rtti.cpp?rev=645750&view=auto ============================================================================== --- stdcxx/trunk/tests/support/18.support.rtti.cpp (added) +++ stdcxx/trunk/tests/support/18.support.rtti.cpp Mon Apr 7 18:05:14 2008 @@ -0,0 +1,439 @@ +/*************************************************************************** + * + * 18.support.rtti.cpp - test exercising 18.5 [lib.support.rtti] + * + * $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. + * + * Copyright 2001-2008 Rogue Wave Software. + * + **************************************************************************/ + +#include <rw/_defs.h> +#if defined (__IBMCPP__) && !defined (_RWSTD_NO_IMPLICIT_INCLUSION) +// Disable implicit inclusion to work around +// a limitation in IBM's VisualAge 5.0.2.0 (see PR#26959) + +# define _RWSTD_NO_IMPLICIT_INCLUSION +#endif + +/**************************************************************************/ + + +// verifies that typeid is correctly declared for MSVC (see PR #25603) +void foo () +{ + _THROW (0); // must appear before #include <typeinfo> +} + +/**************************************************************************/ + + +#include <typeinfo> +#include <driver.h> +#include <valcmp.h> + +// polymorphic classes (10.3, p1) used in tests below +struct B { virtual ~B () { } }; +struct D1: B { }; +struct D2: B { }; + +/**************************************************************************/ + +static int +run_test (int, char* []) +{ + if (1) { + // exercise 18.5, the synopsis of <typeinfo> + + std::type_info *ti = 0; + std::bad_cast *bc = 0; + std::bad_typeid *bt = 0; + + _RWSTD_UNUSED (ti); + _RWSTD_UNUSED (bc); + _RWSTD_UNUSED (bt); + } + + if (1) { + // exercise 18.5.1, class type_info interface + + // 18.5.1, p2 + bool (std::type_info::*p_op_eq)(const std::type_info&) const = + &std::type_info::operator==; + + // 18.5.1, p3 + bool (std::type_info::*p_op_neq)(const std::type_info&) const = + &std::type_info::operator!=; + + // 18.5.1, p5 + bool (std::type_info::*p_before)(const std::type_info&) const = + &std::type_info::before; + + // 18.5.1, p7 + const char* (std::type_info::*p_name)() const = &std::type_info::name; + + _RWSTD_UNUSED (p_op_eq); + _RWSTD_UNUSED (p_op_neq); + _RWSTD_UNUSED (p_before); + _RWSTD_UNUSED (p_name); + } + + if (1) { + // exercise 18.5.1, class type_info functionality + D1 d1; + D2 d2; + + const std::type_info &ti_D1 = typeid (D1); + const std::type_info &ti_D2 = typeid (D2); + + const std::type_info &ti_d1 = typeid (d1); + const std::type_info &ti_d2 = typeid (d2); + + + const char *D1_name = ti_D1.name () ? ti_D1.name () : "(D1 null)"; + const char *D2_name = ti_D2.name () ? ti_D2.name () : "(D2 null)"; + const char *d1_name = ti_d1.name () ? ti_d1.name () : "(d1 null)"; + const char *d2_name = ti_d2.name () ? ti_d2.name () : "(d2 null)"; + + // 18.5.1, p2 + rw_assert (ti_D1 == ti_D1, 0, __LINE__, + "std::type_info::operator==(): \"%s\" != \"%s\"", + D1_name, D1_name); + rw_assert (ti_D1 == ti_d1, 0, __LINE__, + "std::type_info::operator==(): \"%s\" != \"%s\"", + D1_name, d1_name); + rw_assert (!(ti_D1 == ti_D2), 0, __LINE__, + "std::type_info::operator==(): \"%s\" == \"%s\"", + D1_name, D2_name); + rw_assert (ti_d1 == ti_d1, 0, __LINE__, + "std::type_info::operator==(): \"%s\" != \"%s\"", + d1_name, d1_name); + rw_assert (ti_d1 == ti_D1, 0, __LINE__, + "std::type_info::operator==(): \"%s\" != \"%s\"", + d1_name, D1_name); + rw_assert (!(ti_d1 == ti_d2), 0, __LINE__, + "std::type_info::operator==(): \"%s\" == \"%s\"", + d1_name, d2_name); + + // 18.5.1, p3 + rw_assert (ti_D1 != ti_D2, 0, __LINE__, + "std::type_info::operator!=(): \"%s\" == \"%s\"", + D1_name, D2_name); + rw_assert (ti_D1 != ti_d2, 0, __LINE__, + "std::type_info::operator!=(): \"%s\" == \"%s\"", + D1_name, d2_name); + rw_assert (!(ti_D1 != ti_D1), 0, __LINE__, + "std::type_info::operator!=(): \"%s\" != \"%s\"", + D1_name, D1_name); + rw_assert (ti_d1 != ti_d2, 0, __LINE__, + "std::type_info::operator!=(): \"%s\" == \"%s\"", + d1_name, d2_name); + rw_assert (ti_d1 != ti_D2, 0, __LINE__, + "std::type_info::operator!=(): \"%s\" == \"%s\"", + d1_name, D2_name); + rw_assert (!(ti_d1 != ti_d1), 0, __LINE__, + "std::type_info::operator!=(): \"%s\" != \"%s\"", + d1_name, d1_name); + + // 18.5.1, p5 + rw_assert (!ti_D1.before (ti_D1) && !ti_D2.before (ti_D2), + 0, __LINE__, "std::type_info::before ()"); + rw_assert (ti_D1.before (ti_D2) || ti_D2.before (ti_D1), + 0, __LINE__, "std::type_info::before ()"); + rw_assert (ti_d1.before (ti_d2) || ti_d2.before (ti_d1), + 0, __LINE__, "std::type_info::before ()"); + rw_assert (!ti_d1.before (ti_d1) && !ti_d2.before (ti_d2), + 0, __LINE__, "std::type_info::before ()"); + + // 18.5.1, p7 + rw_assert (0 == rw_strncmp (D1_name, d1_name), 0, __LINE__, + "std::type_info::name (): \"%s\" != \"%s\"", + D1_name, d1_name); + rw_assert (0 != rw_strncmp (D1_name, D2_name), 0, __LINE__, + "std::type_info::name (): \"%s\" == \"%s\"", + D1_name, D2_name); + rw_assert (0 == rw_strncmp (D2_name, d2_name), 0, __LINE__, + "std::type_info::name (): \"%s\" != \"%s\"", + D2_name, d2_name); + rw_assert (0 != rw_strncmp (d1_name, d2_name), 0, __LINE__, + "std::type_info::name (): \"%s\" == \"%s\"", + d1_name, d2_name); + } + + if (1) { + // exercise 18.5.2, class bad_cast interface + + // std::bad_cast must publicly derive from std::exception + const std::bad_cast *pbc = 0; + const std::exception *pe = pbc; + + // 18.5.2, p2 + std::bad_cast bc; + + // 18.5.2, p4 - copy ctor + std::bad_cast bc2 (bc); + + // 18.5.2, p4 - assignment + std::bad_cast& (std::bad_cast::*p_op_assign)(const std::bad_cast&) + _PTR_THROWS (()) = &std::bad_cast::operator=; + + // 18.5.2, p5 + const char* (std::bad_cast::*p_what)() const _PTR_THROWS (()) = + &std::bad_cast::what; + + _RWSTD_UNUSED (pbc); + _RWSTD_UNUSED (pe); + _RWSTD_UNUSED (bc); + _RWSTD_UNUSED (bc2); + _RWSTD_UNUSED (p_op_assign); + _RWSTD_UNUSED (p_what); + } + + if (1) { + // exercise 18.5.2, class bad_cast functionality + +#ifndef _RWSTD_NO_EXCEPTIONS +# ifndef _RWSTD_NO_DYNAMIC_CAST + + const char *caught = "no exception"; + + D1 d1; + B &b = d1; + + try { + D2 &d2 = dynamic_cast<D2&>(b); + + _RWSTD_UNUSED (d2); + } + catch (const std::bad_cast &bc) { + caught = "std::bad_cast"; + + // 18.5.2, p2 + std::bad_cast bc2; + + // 18.5.2, p4 - copy ctor + std::bad_cast bc3 (bc); + + const char* const bc_what = bc.what (); + const char* bc2_what = bc2.what (); + const char* const bc3_what = bc3.what (); + + if (0 == bc2_what) + rw_assert (false, 0, __LINE__, "bad_cast().what() != 0"); + + if (0 == bc3_what) + rw_assert (false, 0, __LINE__, + "bad_cast::what() != 0 failed " + "for a copy of a caught exception object"); + + if (bc2_what && bc3_what) + rw_warn (0 == rw_strncmp (bc2_what, bc3_what), + 0, __LINE__, + "bad_cast::bad_cast (const bad_cast&): " + "\"%s\" != \"%s\"", bc_what, bc3_what); + + // 18.5.2, p4 - assignment + bc2 = bc; + + bc2_what = bc2.what (); + + if (0 == bc_what) + rw_assert (false, 0, __LINE__, + "bad_cast::what() != 0 failed " + "for a caught exception object"); + + if (0 == bc2_what) + rw_assert (false, 0, __LINE__, + "bad_cast::what() != 0 failed " + "for an assigned exception object"); + + if (bc_what && bc2_what) + rw_warn (0 == rw_strncmp (bc_what, bc2_what), + 0, __LINE__, + "bad_cast::operator=(const bad_cast&): " + "\"%s\" != \"%s\"", bc_what, bc2_what); + + // 18.5.2, p5 + if (bc_what) + rw_assert (0 == rw_strncmp (bc.what (), bc.what ()), + 0, __LINE__, + "bad_cast::what() const: \"%s\" != \"%s\"", + bc.what (), bc.what ()); + } + catch (const std::exception&) { + caught = "std::exception"; + } + catch (...) { + caught = "unknown exception"; + } + +#if !defined (_RWSTD_NO_STD_BAD_CAST) \ + || !defined (_RWSTD_NO_RUNTIME_IN_STD) + + const char expect[] = "std::bad_cast"; + +#else + + const char expect[] = "std::bad_cast (alias for ::bad_cast)"; + +#endif // !NO_STD_BAD_CAST || !NO_RUNTIME_IN_STD + + rw_assert (0 == rw_strncmp (caught, "std::bad_cast"), + 0, __LINE__, + "dynamic_cast<>() threw %s, expected %s; this suggests " + "that bad_cast might be defined in the wrong namespace", + caught, expect); + + _RWSTD_UNUSED (d1); + _RWSTD_UNUSED (b); + +# endif // _RWSTD_NO_DYNAMIC_CAST +#endif // _RWSTD_NO_EXCEPTIONS + } + + if (1) { + // exercise 18.5.3, class bad_typeid interface + + // std::bad_cast must publicly derive from std::exception + const std::bad_typeid *pbt = 0; + const std::exception *pe = pbt; + + // 18.5.2, p2 + std::bad_typeid bt; + + // 18.5.2, p4 - copy ctor + std::bad_typeid bt2 (bt); + + // 18.5.2, p4 - assignment + std::bad_typeid& (std::bad_typeid::*p_op_assign)(const std::bad_typeid&) + _PTR_THROWS (()) = &std::bad_typeid::operator=; + + // 18.5.2, p5 + const char* (std::bad_typeid::*p_what)() const _PTR_THROWS (()) = + &std::bad_typeid::what; + + _RWSTD_UNUSED (pbt); + _RWSTD_UNUSED (pe); + _RWSTD_UNUSED (bt); + _RWSTD_UNUSED (bt2); + _RWSTD_UNUSED (p_op_assign); + _RWSTD_UNUSED (p_what); + } + + if (1) { + // exercise 18.5.3, class bad_typeid functionality + +#ifndef _RWSTD_NO_EXCEPTIONS + + const char *caught = "no exception"; + + try { + +#if !defined (__GNUG__) || __GNUG__ > 2 + + B *b = 0; + + // 5.2.8, p2 - typeid(0) throws std::bad_typeid + const std::type_info &ti = typeid (*b); + + _RWSTD_UNUSED (b); + _RWSTD_UNUSED (ti); + +#else + + // working around a gcc 2.x bug + caught = "SIGSEGV (program dumps core)"; + +#endif // gcc < 3.0 + + } + catch (const std::bad_typeid &bt) { + caught = "std::bad_typeid"; + + // 18.5.2, p2 + std::bad_typeid bt2; + + // 18.5.2, p4 - copy ctor + std::bad_typeid bt3 (bt); + + // verify that what() returns the same string + // after copy construction + rw_warn (0 == rw_strncmp (bt.what (), bt3.what ()), + 0, __LINE__, + "std::bad_typeid::bad_typeid (const bad_typeid&): " + "\"%s\" != \"%s\"", bt.what (), bt3.what ()); + + // 18.5.2, p4 - assignment + bt2 = bt; + + // verify that what() returns the same string + // after assignment + rw_warn (0 == rw_strncmp (bt.what (), bt2.what ()), + 0, __LINE__, + "std::bad_typeid::operator=(const bad_typeid&): " + "\"%s\" != \"%s\"", bt.what (), bt2.what ()); + + // 18.5.2, p5 + rw_assert (0 == rw_strncmp (bt.what (), bt.what ()), + 0, __LINE__, + "std::bad_typeid::what() const: " + "\"%s\" != \"%s\"", bt.what (), bt.what ()); + } + catch (const std::exception&) { + caught = "std::exception"; + } + catch (...) { + caught = "unknown exception"; + } + +#if !defined (_RWSTD_NO_STD_BAD_TYPEID) \ + || !defined (_RWSTD_NO_RUNTIME_IN_STD) + + const char expect[] = "std::bad_typeid"; + +#else + + const char expect[] = "std::bad_typeid (alias for ::bad_typeid)"; + +#endif // !NO_STD_BAD_TYPEID || !NO_RUNTIME_IN_STD + + + rw_assert (0 == rw_strncmp (caught, "std::bad_typeid"), + 0, __LINE__, + "typeid ((T*)0) threw %s, expected %s; this suggests " + "that bad_typeid might be defined in the wrong namespace", + caught, expect); + +#endif // _RWSTD_NO_EXCEPTIONS + } + + return 0; +} + +int main (int argc, char* argv []) +{ + return rw_test (argc, argv, __FILE__, + "lib.support.rtti", + 0 /* no comment */, + run_test, + "", + (void*)0); +} Propchange: stdcxx/trunk/tests/support/18.support.rtti.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: stdcxx/trunk/tests/support/18.support.rtti.cpp ------------------------------------------------------------------------------ svn:keywords = Id