In case a test sets memory-management functions to perform custom testing and fails midway, all subsequent tests that rely on custom memory handling (i.e. threshold) can fail unexpectedly. Setting up the functions before every test fixes this, making all tests self-contained. git-svn-id: https://pugixml.googlecode.com/svn/trunk@976 99668b35-9821-0410-8761-19e4c4f06640
169 lines
3.6 KiB
C++
169 lines
3.6 KiB
C++
#include "test.hpp"
|
|
#include "allocator.hpp"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <float.h>
|
|
#include <assert.h>
|
|
|
|
#ifndef PUGIXML_NO_EXCEPTIONS
|
|
# include <exception>
|
|
#endif
|
|
|
|
#ifdef _WIN32_WCE
|
|
# undef DebugBreak
|
|
# pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union
|
|
# include <windows.h>
|
|
#endif
|
|
|
|
test_runner* test_runner::_tests = 0;
|
|
size_t test_runner::_memory_fail_threshold = 0;
|
|
jmp_buf test_runner::_failure_buffer;
|
|
const char* test_runner::_failure_message;
|
|
|
|
static size_t g_memory_total_size = 0;
|
|
static size_t g_memory_total_count = 0;
|
|
|
|
static void* custom_allocate(size_t size)
|
|
{
|
|
if (test_runner::_memory_fail_threshold > 0 && test_runner::_memory_fail_threshold < g_memory_total_size + size)
|
|
return 0;
|
|
else
|
|
{
|
|
void* ptr = memory_allocate(size);
|
|
|
|
g_memory_total_size += memory_size(ptr);
|
|
g_memory_total_count++;
|
|
|
|
return ptr;
|
|
}
|
|
}
|
|
|
|
static void custom_deallocate(void* ptr)
|
|
{
|
|
assert(ptr);
|
|
|
|
g_memory_total_size -= memory_size(ptr);
|
|
g_memory_total_count--;
|
|
|
|
memory_deallocate(ptr);
|
|
}
|
|
|
|
static void replace_memory_management()
|
|
{
|
|
// create some document to touch original functions
|
|
{
|
|
pugi::xml_document doc;
|
|
doc.append_child().set_name(STR("node"));
|
|
}
|
|
|
|
// replace functions
|
|
pugi::set_memory_management_functions(custom_allocate, custom_deallocate);
|
|
}
|
|
|
|
#if defined(_MSC_VER) && _MSC_VER > 1200 && _MSC_VER < 1400 && !defined(__INTEL_COMPILER) && !defined(__DMC__)
|
|
#include <exception>
|
|
|
|
namespace std
|
|
{
|
|
_CRTIMP2 _Prhand _Raise_handler;
|
|
_CRTIMP2 void __cdecl _Throw(const exception&) {}
|
|
}
|
|
#endif
|
|
|
|
static bool run_test(test_runner* test)
|
|
{
|
|
#ifndef PUGIXML_NO_EXCEPTIONS
|
|
try
|
|
{
|
|
#endif
|
|
g_memory_total_size = 0;
|
|
g_memory_total_count = 0;
|
|
test_runner::_memory_fail_threshold = 0;
|
|
|
|
pugi::set_memory_management_functions(custom_allocate, custom_deallocate);
|
|
|
|
#ifdef _MSC_VER
|
|
# pragma warning(push)
|
|
# pragma warning(disable: 4611) // interaction between _setjmp and C++ object destruction is non-portable
|
|
# pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
|
|
#endif
|
|
|
|
volatile int result = setjmp(test_runner::_failure_buffer);
|
|
|
|
#ifdef _MSC_VER
|
|
# pragma warning(pop)
|
|
#endif
|
|
|
|
if (result)
|
|
{
|
|
printf("Test %s failed: %s\n", test->_name, test_runner::_failure_message);
|
|
return false;
|
|
}
|
|
|
|
test->run();
|
|
|
|
if (g_memory_total_size != 0 || g_memory_total_count != 0)
|
|
{
|
|
printf("Test %s failed: memory leaks found (%u bytes in %u allocations)\n", test->_name, static_cast<unsigned int>(g_memory_total_size), static_cast<unsigned int>(g_memory_total_count));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
#ifndef PUGIXML_NO_EXCEPTIONS
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
printf("Test %s failed: exception %s\n", test->_name, e.what());
|
|
return false;
|
|
}
|
|
catch (...)
|
|
{
|
|
printf("Test %s failed for unknown reason\n", test->_name);
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if defined(__CELLOS_LV2__) && defined(PUGIXML_NO_EXCEPTIONS) && !defined(__SNC__)
|
|
#include <exception>
|
|
|
|
void std::exception::_Raise() const
|
|
{
|
|
abort();
|
|
}
|
|
#endif
|
|
|
|
#ifdef _WIN32_WCE
|
|
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
|
#else
|
|
int main()
|
|
#endif
|
|
{
|
|
#ifdef __BORLANDC__
|
|
_control87(MCW_EM | PC_53, MCW_EM | MCW_PC);
|
|
#endif
|
|
|
|
replace_memory_management();
|
|
|
|
unsigned int total = 0;
|
|
unsigned int passed = 0;
|
|
|
|
test_runner* test = 0; // gcc3 "variable might be used uninitialized in this function" bug workaround
|
|
|
|
for (test = test_runner::_tests; test; test = test->_next)
|
|
{
|
|
total++;
|
|
passed += run_test(test);
|
|
}
|
|
|
|
unsigned int failed = total - passed;
|
|
|
|
if (failed != 0)
|
|
printf("FAILURE: %u out of %u tests failed.\n", failed, total);
|
|
else
|
|
printf("Success: %u tests passed.\n", total);
|
|
|
|
return failed;
|
|
}
|