mirror of
https://github.com/zeux/pugixml.git
synced 2024-12-26 21:04:25 +08:00
c40fd364ce
New tests try to load a folder as an XML document, and a device. Both are intended to exercise some otherwise non-hittable error paths in load_file implementation.
219 lines
4.9 KiB
C++
219 lines
4.9 KiB
C++
#include "test.hpp"
|
|
#include "allocator.hpp"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <float.h>
|
|
#include <assert.h>
|
|
|
|
#include <string>
|
|
|
|
#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;
|
|
bool test_runner::_memory_fail_triggered = false;
|
|
jmp_buf test_runner::_failure_buffer;
|
|
const char* test_runner::_failure_message;
|
|
const char* test_runner::_temp_path;
|
|
|
|
static size_t g_memory_total_size = 0;
|
|
static size_t g_memory_total_count = 0;
|
|
static size_t g_memory_fail_triggered = false;
|
|
|
|
static void* custom_allocate(size_t size)
|
|
{
|
|
if (test_runner::_memory_fail_threshold > 0 && test_runner::_memory_fail_threshold < g_memory_total_size + size)
|
|
{
|
|
g_memory_fail_triggered = true;
|
|
test_runner::_memory_fail_triggered = true;
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
void* ptr = memory_allocate(size);
|
|
if (!ptr) return 0;
|
|
|
|
g_memory_total_size += memory_size(ptr);
|
|
g_memory_total_count++;
|
|
|
|
return ptr;
|
|
}
|
|
}
|
|
|
|
#ifndef PUGIXML_NO_EXCEPTIONS
|
|
static void* custom_allocate_throw(size_t size)
|
|
{
|
|
void* result = custom_allocate(size);
|
|
|
|
if (!result)
|
|
throw std::bad_alloc();
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
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, const char* test_name, pugi::allocation_function allocate)
|
|
{
|
|
#ifndef PUGIXML_NO_EXCEPTIONS
|
|
try
|
|
{
|
|
#endif
|
|
g_memory_total_size = 0;
|
|
g_memory_total_count = 0;
|
|
g_memory_fail_triggered = false;
|
|
test_runner::_memory_fail_threshold = 0;
|
|
test_runner::_memory_fail_triggered = false;
|
|
|
|
pugi::set_memory_management_functions(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 (test_runner::_memory_fail_triggered)
|
|
{
|
|
printf("Test %s failed: unguarded memory fail triggered\n", test_name);
|
|
return false;
|
|
}
|
|
|
|
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
|
|
|
|
int main(int, char** argv)
|
|
{
|
|
#ifdef __BORLANDC__
|
|
_control87(MCW_EM | PC_53, MCW_EM | MCW_PC);
|
|
#endif
|
|
|
|
// setup temp path as the executable folder
|
|
std::string temp = argv[0];
|
|
std::string::size_type slash = temp.find_last_of("\\/");
|
|
temp.erase((slash != std::string::npos) ? slash + 1 : 0);
|
|
|
|
test_runner::_temp_path = temp.c_str();
|
|
|
|
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, test->_name, custom_allocate);
|
|
|
|
if (g_memory_fail_triggered)
|
|
{
|
|
// run tests that trigger memory failures twice - with an allocator that returns NULL and with an allocator that throws
|
|
#ifndef PUGIXML_NO_EXCEPTIONS
|
|
total++;
|
|
passed += run_test(test, (test->_name + std::string(" (throw)")).c_str(), custom_allocate_throw);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
#ifdef _WIN32_WCE
|
|
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
|
{
|
|
return main(0, NULL);
|
|
}
|
|
#endif
|