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