summaryrefslogtreecommitdiff
path: root/tests/test.cpp
blob: 6347984f5e502d787ae3aa073e68b6a3993e77f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
#define _SCL_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_DEPRECATE

#include "test.hpp"

#include "writer_string.hpp"

#include <math.h>
#include <float.h>
#include <string.h>
#include <wchar.h>

#include <algorithm>
#include <vector>

#ifndef PUGIXML_NO_XPATH
static void build_document_order(std::vector<pugi::xpath_node>& result, pugi::xml_node root)
{
	result.push_back(pugi::xpath_node());

	pugi::xml_node cur = root;

	for (;;)
	{
		result.push_back(cur);

		for (pugi::xml_attribute a = cur.first_attribute(); a; a = a.next_attribute())
			result.push_back(pugi::xpath_node(a, cur));

		if (cur.first_child())
			cur = cur.first_child();
		else if (cur.next_sibling())
			cur = cur.next_sibling();
		else
		{
			while (cur && !cur.next_sibling()) cur = cur.parent();
			cur = cur.next_sibling();

			if (!cur) break;
		}
	}
}
#endif

bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs)
{
	return (!lhs || !rhs) ? lhs == rhs :
	#ifdef PUGIXML_WCHAR_MODE
		wcscmp(lhs, rhs) == 0;
	#else
		strcmp(lhs, rhs) == 0;
	#endif
}

bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags)
{
	xml_writer_string writer;

	node.print(writer, indent, flags, get_native_encoding());

	return writer.as_string() == contents;
}

bool test_double_nan(double value)
{
#if defined(_MSC_VER) || defined(__BORLANDC__)
	return _isnan(value) != 0;
#else
	return value != value;
#endif
}

#ifndef PUGIXML_NO_XPATH
static size_t strlength(const pugi::char_t* s)
{
#ifdef PUGIXML_WCHAR_MODE
	return wcslen(s);
#else
	return strlen(s);
#endif
}

bool test_xpath_string(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, const pugi::char_t* expected)
{
	pugi::xpath_query q(query, variables);
	if (!q) return false;

	const size_t capacity = 64;
	pugi::char_t result[capacity];

	size_t size = q.evaluate_string(result, capacity, node);

	if (size != strlength(expected) + 1)
		return false;

	if (size <= capacity)
		return test_string_equal(result, expected);

	std::basic_string<pugi::char_t> buffer(size, ' ');

	return q.evaluate_string(&buffer[0], size, node) == size && test_string_equal(buffer.c_str(), expected);
}

bool test_xpath_boolean(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, bool expected)
{
	pugi::xpath_query q(query, variables);
	if (!q) return false;

	return q.evaluate_boolean(node) == expected;
}

bool test_xpath_number(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, double expected)
{
	pugi::xpath_query q(query, variables);
	if (!q) return false;

	double value = q.evaluate_number(node);
	double absolute_error = fabs(value - expected);

	const double tolerance = 1e-15f;
	return absolute_error < tolerance || absolute_error < fabs(expected) * tolerance;
}

bool test_xpath_number_nan(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables)
{
	pugi::xpath_query q(query, variables);
	if (!q) return false;

	return test_double_nan(q.evaluate_number(node));
}

bool test_xpath_fail_compile(const pugi::char_t* query, pugi::xpath_variable_set* variables)
{
#ifdef PUGIXML_NO_EXCEPTIONS
	return !pugi::xpath_query(query, variables);
#else
	try
	{
		pugi::xpath_query q(query, variables);
		return false;
	}
	catch (const pugi::xpath_exception&)
	{
		return true;
	}
#endif
}

void xpath_node_set_tester::check(bool condition)
{
	if (!condition)
	{
		test_runner::_failure_message = message;
		longjmp(test_runner::_failure_buffer, 1);
	}
}

xpath_node_set_tester::xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message_): last(0), message(message_)
{
	result = set;

	// only sort unsorted sets so that we're able to verify reverse order for some axes
	if (result.type() == pugi::xpath_node_set::type_unsorted) result.sort();

	if (result.empty())
	{
		document_order = 0;
		document_size = 0;
	}
	else
	{
		std::vector<pugi::xpath_node> order;
		build_document_order(order, (result[0].attribute() ? result[0].parent() : result[0].node()).root());

		document_order = new pugi::xpath_node[order.size()];
		std::copy(order.begin(), order.end(), document_order);

		document_size = order.size();
	}
}

xpath_node_set_tester::~xpath_node_set_tester()
{
	// check that we processed everything
	check(last == result.size());

	delete[] document_order;
}

xpath_node_set_tester& xpath_node_set_tester::operator%(unsigned int expected)
{
	// check element count
	check(last < result.size());

	// check document order
	check(expected < document_size);
	check(result.begin()[last] == document_order[expected]);

	// continue to the next element
	last++;

	return *this;
}

#endif

bool is_little_endian()
{
	unsigned int ui = 1;
	return *reinterpret_cast<char*>(&ui) == 1;
}

pugi::xml_encoding get_native_encoding()
{
#ifdef PUGIXML_WCHAR_MODE
	return pugi::encoding_wchar;
#else
	return pugi::encoding_utf8;
#endif
}