1 #define _SCL_SECURE_NO_WARNINGS
2 #define _SCL_SECURE_NO_DEPRECATE
3 
4 #include "test.hpp"
5 
6 #include "writer_string.hpp"
7 
8 #include <math.h>
9 #include <float.h>
10 #include <string.h>
11 #include <wchar.h>
12 
13 #include <algorithm>
14 #include <vector>
15 
16 #ifndef PUGIXML_NO_XPATH
build_document_order(std::vector<pugi::xpath_node> & result,pugi::xml_node root)17 static void build_document_order(std::vector<pugi::xpath_node>& result, pugi::xml_node root)
18 {
19 	result.push_back(pugi::xpath_node());
20 
21 	pugi::xml_node cur = root;
22 
23 	for (;;)
24 	{
25 		result.push_back(cur);
26 
27 		for (pugi::xml_attribute a = cur.first_attribute(); a; a = a.next_attribute())
28 			result.push_back(pugi::xpath_node(a, cur));
29 
30 		if (cur.first_child())
31 			cur = cur.first_child();
32 		else if (cur.next_sibling())
33 			cur = cur.next_sibling();
34 		else
35 		{
36 			while (cur && !cur.next_sibling()) cur = cur.parent();
37 			cur = cur.next_sibling();
38 
39 			if (!cur) break;
40 		}
41 	}
42 }
43 #endif
44 
test_string_equal(const pugi::char_t * lhs,const pugi::char_t * rhs)45 bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs)
46 {
47 	return (!lhs || !rhs) ? lhs == rhs :
48 	#ifdef PUGIXML_WCHAR_MODE
49 		wcscmp(lhs, rhs) == 0;
50 	#else
51 		strcmp(lhs, rhs) == 0;
52 	#endif
53 }
54 
test_node(const pugi::xml_node & node,const pugi::char_t * contents,const pugi::char_t * indent,unsigned int flags)55 bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags)
56 {
57 	xml_writer_string writer;
58 
59 	node.print(writer, indent, flags, get_native_encoding());
60 
61 	return writer.as_string() == contents;
62 }
63 
test_double_nan(double value)64 bool test_double_nan(double value)
65 {
66 #if defined(_MSC_VER) || defined(__BORLANDC__)
67 	return _isnan(value) != 0;
68 #else
69 	return value != value;
70 #endif
71 }
72 
73 #ifndef PUGIXML_NO_XPATH
strlength(const pugi::char_t * s)74 static size_t strlength(const pugi::char_t* s)
75 {
76 #ifdef PUGIXML_WCHAR_MODE
77 	return wcslen(s);
78 #else
79 	return strlen(s);
80 #endif
81 }
82 
test_xpath_string(const pugi::xpath_node & node,const pugi::char_t * query,pugi::xpath_variable_set * variables,const pugi::char_t * expected)83 bool test_xpath_string(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, const pugi::char_t* expected)
84 {
85 	pugi::xpath_query q(query, variables);
86 	if (!q) return false;
87 
88 	const size_t capacity = 64;
89 	pugi::char_t result[capacity];
90 
91 	size_t size = q.evaluate_string(result, capacity, node);
92 
93 	if (size != strlength(expected) + 1)
94 		return false;
95 
96 	if (size <= capacity)
97 		return test_string_equal(result, expected);
98 
99 	std::basic_string<pugi::char_t> buffer(size, ' ');
100 
101 	return q.evaluate_string(&buffer[0], size, node) == size && test_string_equal(buffer.c_str(), expected);
102 }
103 
test_xpath_boolean(const pugi::xpath_node & node,const pugi::char_t * query,pugi::xpath_variable_set * variables,bool expected)104 bool test_xpath_boolean(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, bool expected)
105 {
106 	pugi::xpath_query q(query, variables);
107 	if (!q) return false;
108 
109 	return q.evaluate_boolean(node) == expected;
110 }
111 
test_xpath_number(const pugi::xpath_node & node,const pugi::char_t * query,pugi::xpath_variable_set * variables,double expected)112 bool test_xpath_number(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables, double expected)
113 {
114 	pugi::xpath_query q(query, variables);
115 	if (!q) return false;
116 
117 	double value = q.evaluate_number(node);
118 	double absolute_error = fabs(value - expected);
119 
120 	const double tolerance = 1e-15f;
121 	return absolute_error < tolerance || absolute_error < fabs(expected) * tolerance;
122 }
123 
test_xpath_number_nan(const pugi::xpath_node & node,const pugi::char_t * query,pugi::xpath_variable_set * variables)124 bool test_xpath_number_nan(const pugi::xpath_node& node, const pugi::char_t* query, pugi::xpath_variable_set* variables)
125 {
126 	pugi::xpath_query q(query, variables);
127 	if (!q) return false;
128 
129 	return test_double_nan(q.evaluate_number(node));
130 }
131 
test_xpath_fail_compile(const pugi::char_t * query,pugi::xpath_variable_set * variables)132 bool test_xpath_fail_compile(const pugi::char_t* query, pugi::xpath_variable_set* variables)
133 {
134 #ifdef PUGIXML_NO_EXCEPTIONS
135 	return !pugi::xpath_query(query, variables);
136 #else
137 	try
138 	{
139 		pugi::xpath_query q(query, variables);
140 		return false;
141 	}
142 	catch (const pugi::xpath_exception&)
143 	{
144 		return true;
145 	}
146 #endif
147 }
148 
check(bool condition)149 void xpath_node_set_tester::check(bool condition)
150 {
151 	if (!condition)
152 	{
153 		test_runner::_failure_message = message;
154 		longjmp(test_runner::_failure_buffer, 1);
155 	}
156 }
157 
xpath_node_set_tester(const pugi::xpath_node_set & set,const char * message_)158 xpath_node_set_tester::xpath_node_set_tester(const pugi::xpath_node_set& set, const char* message_): last(0), message(message_)
159 {
160 	result = set;
161 
162 	// only sort unsorted sets so that we're able to verify reverse order for some axes
163 	if (result.type() == pugi::xpath_node_set::type_unsorted) result.sort();
164 
165 	if (result.empty())
166 	{
167 		document_order = 0;
168 		document_size = 0;
169 	}
170 	else
171 	{
172 		std::vector<pugi::xpath_node> order;
173 		build_document_order(order, (result[0].attribute() ? result[0].parent() : result[0].node()).root());
174 
175 		document_order = new pugi::xpath_node[order.size()];
176 		std::copy(order.begin(), order.end(), document_order);
177 
178 		document_size = order.size();
179 	}
180 }
181 
~xpath_node_set_tester()182 xpath_node_set_tester::~xpath_node_set_tester()
183 {
184 	// check that we processed everything
185 	check(last == result.size());
186 
187 	delete[] document_order;
188 }
189 
operator %(unsigned int expected)190 xpath_node_set_tester& xpath_node_set_tester::operator%(unsigned int expected)
191 {
192 	// check element count
193 	check(last < result.size());
194 
195 	// check document order
196 	check(expected < document_size);
197 	check(result.begin()[last] == document_order[expected]);
198 
199 	// continue to the next element
200 	last++;
201 
202 	return *this;
203 }
204 
205 #endif
206 
is_little_endian()207 bool is_little_endian()
208 {
209 	unsigned int ui = 1;
210 	return *reinterpret_cast<char*>(&ui) == 1;
211 }
212 
get_native_encoding()213 pugi::xml_encoding get_native_encoding()
214 {
215 #ifdef PUGIXML_WCHAR_MODE
216 	return pugi::encoding_wchar;
217 #else
218 	return pugi::encoding_utf8;
219 #endif
220 }
221