From 5edeaf67658a3ab27e9ace87ccff37aba8352607 Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Sun, 12 Apr 2015 21:27:12 -0700
Subject: [PATCH] tests: Add more out of memory tests

Also add tests that verify save_file for absence of FILE leaks.
---
 tests/test.hpp          |  4 ++--
 tests/test_document.cpp | 37 +++++++++++++++++++++++++++++++++++--
 tests/test_parse.cpp    | 25 +++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/tests/test.hpp b/tests/test.hpp
index 46c33306..d0fd0ca1 100644
--- a/tests/test.hpp
+++ b/tests/test.hpp
@@ -143,9 +143,9 @@ struct dummy_fixture {};
 #endif
 
 #ifdef PUGIXML_NO_EXCEPTIONS
-#define CHECK_ALLOC_FAIL(code) CHECK(!test_runner::_memory_fail_triggered); code; CHECK(test_runner::_memory_fail_triggered); test_runner::_memory_fail_triggered = false
+#define CHECK_ALLOC_FAIL(code) do { CHECK(!test_runner::_memory_fail_triggered); code; CHECK(test_runner::_memory_fail_triggered); test_runner::_memory_fail_triggered = false; } while (test_runner::_memory_fail_triggered)
 #else
-#define CHECK_ALLOC_FAIL(code) CHECK(!test_runner::_memory_fail_triggered); try { code; } catch (std::bad_alloc&) {} CHECK(test_runner::_memory_fail_triggered); test_runner::_memory_fail_triggered = false
+#define CHECK_ALLOC_FAIL(code) do { CHECK(!test_runner::_memory_fail_triggered); try { code; } catch (std::bad_alloc&) {} CHECK(test_runner::_memory_fail_triggered); test_runner::_memory_fail_triggered = false; } while (test_runner::_memory_fail_triggered)
 #endif
 
 #define STR(text) PUGIXML_TEXT(text)
diff --git a/tests/test_document.cpp b/tests/test_document.cpp
index 1545e19b..9c8c8604 100644
--- a/tests/test_document.cpp
+++ b/tests/test_document.cpp
@@ -319,9 +319,7 @@ TEST(document_load_file_out_of_memory_file_leak)
 	pugi::xml_document doc;
 
 	for (int i = 0; i < 256; ++i)
-	{
 		CHECK_ALLOC_FAIL(CHECK(doc.load_file("tests/data/small.xml").status == status_out_of_memory));
-	}
 
 	test_runner::_memory_fail_threshold = 0;
 
@@ -329,6 +327,21 @@ TEST(document_load_file_out_of_memory_file_leak)
 	CHECK_NODE(doc, STR("<node />"));
 }
 
+TEST(document_load_file_wide_out_of_memory_file_leak)
+{
+	test_runner::_memory_fail_threshold = 256;
+
+	pugi::xml_document doc;
+
+	for (int i = 0; i < 256; ++i)
+		CHECK_ALLOC_FAIL(CHECK(doc.load_file(L"tests/data/small.xml").status == status_out_of_memory));
+
+	test_runner::_memory_fail_threshold = 0;
+
+	CHECK(doc.load_file(L"tests/data/small.xml"));
+	CHECK_NODE(doc, STR("<node />"));
+}
+
 TEST(document_load_file_error_previous)
 {
 	pugi::xml_document doc;
@@ -556,6 +569,26 @@ TEST_XML(document_save_file_wide_text, "<node/>")
     CHECK(test_file_contents(f.path, "<node />\n", 9));
 }
 
+TEST_XML(document_save_file_leak, "<node/>")
+{
+	temp_file f;
+
+	for (int i = 0; i < 256; ++i)
+		CHECK(doc.save_file(f.path));
+}
+
+TEST_XML(document_save_file_wide_leak, "<node/>")
+{
+	temp_file f;
+
+	// widen the path
+	wchar_t wpath[sizeof(f.path)];
+	std::copy(f.path, f.path + strlen(f.path) + 1, wpath + 0);
+
+	for (int i = 0; i < 256; ++i)
+		CHECK(doc.save_file(wpath));
+}
+
 TEST(document_load_buffer)
 {
 	const pugi::char_t text[] = STR("<?xml?><node/>");
diff --git a/tests/test_parse.cpp b/tests/test_parse.cpp
index 08ddee44..393e14ce 100644
--- a/tests/test_parse.cpp
+++ b/tests/test_parse.cpp
@@ -935,6 +935,31 @@ TEST(parse_out_of_memory_conversion)
 	CHECK(!doc.first_child());
 }
 
+TEST(parse_out_of_memory_allocator_state_sync)
+{
+	const unsigned int count = 10000;
+	static char_t text[count * 4];
+
+	for (unsigned int i = 0; i < count; ++i)
+	{
+		text[4*i + 0] = '<';
+		text[4*i + 1] = 'n';
+		text[4*i + 2] = '/';
+		text[4*i + 3] = '>';
+	}
+
+	test_runner::_memory_fail_threshold = 65536;
+
+	xml_document doc;
+	CHECK_ALLOC_FAIL(CHECK(doc.load_buffer_inplace(text, count * 4).status == status_out_of_memory));
+	CHECK_NODE(doc.first_child(), STR("<n />"));
+
+	test_runner::_memory_fail_threshold = 0;
+
+	for (unsigned int i = 0; i < count; ++i)
+		CHECK(doc.append_child(STR("n")));
+}
+
 static bool test_offset(const char_t* contents, unsigned int options, pugi::xml_parse_status status, ptrdiff_t offset)
 {
 	xml_document doc;
-- 
GitLab