1 #define _CRT_SECURE_NO_WARNINGS
2 #define _SCL_SECURE_NO_WARNINGS
3 #define _SCL_SECURE_NO_DEPRECATE
4 #define _CRT_NONSTDC_NO_DEPRECATE 0
5
6 #include <string.h> // because Borland's STL is braindead, we have to include <string.h> _before_ <string> in order to get memcpy
7
8 #include "common.hpp"
9
10 #include "writer_string.hpp"
11
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 #include <fstream>
16 #include <sstream>
17
18 #include <string>
19 #include <algorithm>
20
21 #ifdef __MINGW32__
22 # include <io.h> // for unlink in C++0x mode
23 #endif
24
25 #if defined(__CELLOS_LV2__) || defined(ANDROID) || defined(_GLIBCXX_HAVE_UNISTD_H) || defined(__APPLE__)
26 # include <unistd.h> // for unlink
27 #endif
28
load_file_in_memory(const char * path,char * & data,size_t & size)29 static bool load_file_in_memory(const char* path, char*& data, size_t& size)
30 {
31 FILE* file = fopen(path, "rb");
32 if (!file) return false;
33
34 fseek(file, 0, SEEK_END);
35 long length = ftell(file);
36 fseek(file, 0, SEEK_SET);
37
38 CHECK(length >= 0);
39 size = static_cast<size_t>(length);
40 data = new char[size];
41
42 CHECK(fread(data, 1, size, file) == size);
43 fclose(file);
44
45 return true;
46 }
47
test_file_contents(const char * path,const char * data,size_t size)48 static bool test_file_contents(const char* path, const char* data, size_t size)
49 {
50 char* fdata;
51 size_t fsize;
52 if (!load_file_in_memory(path, fdata, fsize)) return false;
53
54 bool result = (size == fsize && memcmp(data, fdata, size) == 0);
55
56 delete[] fdata;
57
58 return result;
59 }
60
TEST(document_create_empty)61 TEST(document_create_empty)
62 {
63 pugi::xml_document doc;
64 CHECK_NODE(doc, STR(""));
65 }
66
TEST(document_create)67 TEST(document_create)
68 {
69 pugi::xml_document doc;
70 doc.append_child().set_name(STR("node"));
71 CHECK_NODE(doc, STR("<node/>"));
72 }
73
74 #ifndef PUGIXML_NO_STL
TEST(document_load_stream)75 TEST(document_load_stream)
76 {
77 pugi::xml_document doc;
78
79 std::istringstream iss("<node/>");
80 CHECK(doc.load(iss));
81 CHECK_NODE(doc, STR("<node/>"));
82 }
83
TEST(document_load_stream_offset)84 TEST(document_load_stream_offset)
85 {
86 pugi::xml_document doc;
87
88 std::istringstream iss("<foobar> <node/>");
89
90 std::string s;
91 iss >> s;
92
93 CHECK(doc.load(iss));
94 CHECK_NODE(doc, STR("<node/>"));
95 }
96
TEST(document_load_stream_text)97 TEST(document_load_stream_text)
98 {
99 pugi::xml_document doc;
100
101 std::ifstream iss("tests/data/multiline.xml");
102 CHECK(doc.load(iss));
103 CHECK_NODE(doc, STR("<node1/><node2/><node3/>"));
104 }
105
TEST(document_load_stream_error)106 TEST(document_load_stream_error)
107 {
108 pugi::xml_document doc;
109
110 std::ifstream fs("filedoesnotexist");
111 CHECK(doc.load(fs).status == status_io_error);
112
113 std::istringstream iss("<node/>");
114 test_runner::_memory_fail_threshold = 1;
115 CHECK_ALLOC_FAIL(CHECK(doc.load(iss).status == status_out_of_memory));
116 }
117
TEST(document_load_stream_empty)118 TEST(document_load_stream_empty)
119 {
120 std::istringstream iss;
121
122 pugi::xml_document doc;
123 doc.load(iss); // parse result depends on STL implementation
124 CHECK(!doc.first_child());
125 }
126
TEST(document_load_stream_wide)127 TEST(document_load_stream_wide)
128 {
129 pugi::xml_document doc;
130
131 std::basic_istringstream<wchar_t> iss(L"<node/>");
132 CHECK(doc.load(iss));
133 CHECK_NODE(doc, STR("<node/>"));
134 }
135
136 #ifndef PUGIXML_NO_EXCEPTIONS
TEST(document_load_stream_exceptions)137 TEST(document_load_stream_exceptions)
138 {
139 pugi::xml_document doc;
140
141 // Windows has newline translation for text-mode files, so reading from this stream reaches eof and sets fail|eof bits.
142 // This test does not cause stream to throw an exception on Linux - I have no idea how to get read() to fail except
143 // newline translation.
144 std::ifstream iss("tests/data/multiline.xml");
145 iss.exceptions(std::ios::eofbit | std::ios::badbit | std::ios::failbit);
146
147 try
148 {
149 doc.load(iss);
150
151 CHECK(iss.good()); // if the exception was not thrown, stream reading should succeed without errors
152 }
153 catch (const std::ios_base::failure&)
154 {
155 CHECK(!doc.first_child());
156 }
157 }
158 #endif
159
TEST(document_load_stream_error_previous)160 TEST(document_load_stream_error_previous)
161 {
162 pugi::xml_document doc;
163 CHECK(doc.load_string(STR("<node/>")));
164 CHECK(doc.first_child());
165
166 std::ifstream fs1("filedoesnotexist");
167 CHECK(doc.load(fs1).status == status_io_error);
168 CHECK(!doc.first_child());
169 }
170
TEST(document_load_stream_wide_error_previous)171 TEST(document_load_stream_wide_error_previous)
172 {
173 pugi::xml_document doc;
174 CHECK(doc.load_string(STR("<node/>")));
175 CHECK(doc.first_child());
176
177 std::basic_ifstream<wchar_t> fs1("filedoesnotexist");
178 CHECK(doc.load(fs1).status == status_io_error);
179 CHECK(!doc.first_child());
180 }
181
182 template <typename T> class char_array_buffer: public std::basic_streambuf<T>
183 {
184 public:
char_array_buffer(T * begin,T * end)185 char_array_buffer(T* begin, T* end)
186 {
187 this->setg(begin, begin, end);
188 }
189
underflow()190 typename std::basic_streambuf<T>::int_type underflow() PUGIXML_OVERRIDE
191 {
192 return this->gptr() == this->egptr() ? std::basic_streambuf<T>::traits_type::eof() : std::basic_streambuf<T>::traits_type::to_int_type(*this->gptr());
193 }
194 };
195
TEST(document_load_stream_nonseekable)196 TEST(document_load_stream_nonseekable)
197 {
198 char contents[] = "<node />";
199 char_array_buffer<char> buffer(contents, contents + sizeof(contents) / sizeof(contents[0]));
200 std::istream in(&buffer);
201
202 pugi::xml_document doc;
203 CHECK(doc.load(in));
204 CHECK_NODE(doc, STR("<node/>"));
205 }
206
TEST(document_load_stream_wide_nonseekable)207 TEST(document_load_stream_wide_nonseekable)
208 {
209 wchar_t contents[] = L"<node />";
210 char_array_buffer<wchar_t> buffer(contents, contents + sizeof(contents) / sizeof(contents[0]));
211 std::basic_istream<wchar_t> in(&buffer);
212
213 pugi::xml_document doc;
214 CHECK(doc.load(in));
215 CHECK_NODE(doc, STR("<node/>"));
216 }
217
TEST(document_load_stream_nonseekable_large)218 TEST(document_load_stream_nonseekable_large)
219 {
220 std::basic_string<pugi::char_t> str;
221 str += STR("<node>");
222 for (int i = 0; i < 10000; ++i) str += STR("<node/>");
223 str += STR("</node>");
224
225 char_array_buffer<pugi::char_t> buffer(&str[0], &str[0] + str.length());
226 std::basic_istream<pugi::char_t> in(&buffer);
227
228 pugi::xml_document doc;
229 CHECK(doc.load(in));
230 CHECK_NODE(doc, str.c_str());
231 }
232
TEST(document_load_stream_nonseekable_out_of_memory)233 TEST(document_load_stream_nonseekable_out_of_memory)
234 {
235 char contents[] = "<node />";
236 char_array_buffer<char> buffer(contents, contents + sizeof(contents) / sizeof(contents[0]));
237 std::istream in(&buffer);
238
239 test_runner::_memory_fail_threshold = 1;
240
241 pugi::xml_document doc;
242 CHECK_ALLOC_FAIL(CHECK(doc.load(in).status == status_out_of_memory));
243 }
244
TEST(document_load_stream_nonseekable_out_of_memory_large)245 TEST(document_load_stream_nonseekable_out_of_memory_large)
246 {
247 std::basic_string<pugi::char_t> str;
248 str += STR("<node>");
249 for (int i = 0; i < 10000; ++i) str += STR("<node />");
250 str += STR("</node>");
251
252 char_array_buffer<pugi::char_t> buffer(&str[0], &str[0] + str.length());
253 std::basic_istream<pugi::char_t> in(&buffer);
254
255 test_runner::_memory_fail_threshold = 10000 * 8 * 3 / 2;
256
257 pugi::xml_document doc;
258 CHECK_ALLOC_FAIL(CHECK(doc.load(in).status == status_out_of_memory));
259 }
260 #endif
261
TEST(document_load_string)262 TEST(document_load_string)
263 {
264 pugi::xml_document doc;
265
266 CHECK(doc.load_string(STR("<node/>")));
267 CHECK_NODE(doc, STR("<node/>"));
268 }
269
TEST(document_load_file)270 TEST(document_load_file)
271 {
272 pugi::xml_document doc;
273
274 CHECK(doc.load_file("tests/data/small.xml"));
275 CHECK_NODE(doc, STR("<node/>"));
276 }
277
TEST(document_load_file_empty)278 TEST(document_load_file_empty)
279 {
280 pugi::xml_document doc;
281
282 CHECK(doc.load_file("tests/data/empty.xml").status == status_no_document_element);
283 CHECK(!doc.first_child());
284 }
285
TEST(document_load_file_large)286 TEST(document_load_file_large)
287 {
288 pugi::xml_document doc;
289
290 CHECK(doc.load_file("tests/data/large.xml"));
291
292 std::basic_string<pugi::char_t> str;
293 str += STR("<node>");
294 for (int i = 0; i < 10000; ++i) str += STR("<node/>");
295 str += STR("</node>");
296
297 CHECK_NODE(doc, str.c_str());
298 }
299
TEST(document_load_file_error)300 TEST(document_load_file_error)
301 {
302 pugi::xml_document doc;
303
304 CHECK(doc.load_file("filedoesnotexist").status == status_file_not_found);
305 }
306
TEST(document_load_file_out_of_memory)307 TEST(document_load_file_out_of_memory)
308 {
309 test_runner::_memory_fail_threshold = 1;
310
311 pugi::xml_document doc;
312 CHECK_ALLOC_FAIL(CHECK(doc.load_file("tests/data/small.xml").status == status_out_of_memory));
313 }
314
TEST(document_load_file_out_of_memory_file_leak)315 TEST(document_load_file_out_of_memory_file_leak)
316 {
317 test_runner::_memory_fail_threshold = 1;
318
319 pugi::xml_document doc;
320
321 for (int i = 0; i < 256; ++i)
322 CHECK_ALLOC_FAIL(CHECK(doc.load_file("tests/data/small.xml").status == status_out_of_memory));
323
324 test_runner::_memory_fail_threshold = 0;
325
326 CHECK(doc.load_file("tests/data/small.xml"));
327 CHECK_NODE(doc, STR("<node/>"));
328 }
329
TEST(document_load_file_wide_out_of_memory_file_leak)330 TEST(document_load_file_wide_out_of_memory_file_leak)
331 {
332 test_runner::_memory_fail_threshold = 256;
333
334 pugi::xml_document doc;
335
336 for (int i = 0; i < 256; ++i)
337 CHECK_ALLOC_FAIL(CHECK(doc.load_file(L"tests/data/small.xml").status == status_out_of_memory));
338
339 test_runner::_memory_fail_threshold = 0;
340
341 CHECK(doc.load_file(L"tests/data/small.xml"));
342 CHECK_NODE(doc, STR("<node/>"));
343 }
344
TEST(document_load_file_error_previous)345 TEST(document_load_file_error_previous)
346 {
347 pugi::xml_document doc;
348 CHECK(doc.load_string(STR("<node/>")));
349 CHECK(doc.first_child());
350
351 CHECK(doc.load_file("filedoesnotexist").status == status_file_not_found);
352 CHECK(!doc.first_child());
353 }
354
TEST(document_load_file_wide_ascii)355 TEST(document_load_file_wide_ascii)
356 {
357 pugi::xml_document doc;
358
359 CHECK(doc.load_file(L"tests/data/small.xml"));
360 CHECK_NODE(doc, STR("<node/>"));
361 }
362
363 #if !defined(__DMC__) && !defined(__MWERKS__) && !(defined(__MINGW32__) && defined(__STRICT_ANSI__) && !defined(__MINGW64_VERSION_MAJOR)) && !defined(__BORLANDC__)
TEST(document_load_file_wide_unicode)364 TEST(document_load_file_wide_unicode)
365 {
366 pugi::xml_document doc;
367
368 CHECK(doc.load_file(L"tests/data/\x0442\x0435\x0441\x0442.xml"));
369 CHECK_NODE(doc, STR("<node/>"));
370 }
371 #endif
372
TEST(document_load_file_wide_out_of_memory)373 TEST(document_load_file_wide_out_of_memory)
374 {
375 test_runner::_memory_fail_threshold = 1;
376
377 pugi::xml_document doc;
378
379 pugi::xml_parse_result result;
380 result.status = status_out_of_memory;
381 CHECK_ALLOC_FAIL(result = doc.load_file(L"tests/data/small.xml"));
382
383 CHECK(result.status == status_out_of_memory || result.status == status_file_not_found);
384 }
385
386 TEST_XML(document_save, "<node/>")
387 {
388 xml_writer_string writer;
389
390 doc.save(writer, STR(""), pugi::format_no_declaration | pugi::format_raw, get_native_encoding());
391
392 CHECK(writer.as_string() == STR("<node/>"));
393 }
394
395 #ifndef PUGIXML_NO_STL
396 TEST_XML(document_save_stream, "<node/>")
397 {
398 std::ostringstream oss;
399
400 doc.save(oss, STR(""), pugi::format_no_declaration | pugi::format_raw);
401
402 CHECK(oss.str() == "<node/>");
403 }
404
405 TEST_XML(document_save_stream_wide, "<node/>")
406 {
407 std::basic_ostringstream<wchar_t> oss;
408
409 doc.save(oss, STR(""), pugi::format_no_declaration | pugi::format_raw);
410
411 CHECK(oss.str() == L"<node/>");
412 }
413 #endif
414
415 TEST_XML(document_save_bom, "<n/>")
416 {
417 unsigned int flags = format_no_declaration | format_raw | format_write_bom;
418
419 // specific encodings
420 CHECK(test_save_narrow(doc, flags, encoding_utf8, "\xef\xbb\xbf<n/>", 7));
421 CHECK(test_save_narrow(doc, flags, encoding_utf16_be, "\xfe\xff\x00<\x00n\x00/\x00>", 10));
422 CHECK(test_save_narrow(doc, flags, encoding_utf16_le, "\xff\xfe<\x00n\x00/\x00>\x00", 10));
423 CHECK(test_save_narrow(doc, flags, encoding_utf32_be, "\x00\x00\xfe\xff\x00\x00\x00<\x00\x00\x00n\x00\x00\x00/\x00\x00\x00>", 20));
424 CHECK(test_save_narrow(doc, flags, encoding_utf32_le, "\xff\xfe\x00\x00<\x00\x00\x00n\x00\x00\x00/\x00\x00\x00>\x00\x00\x00", 20));
425 CHECK(test_save_narrow(doc, flags, encoding_latin1, "<n/>", 4));
426
427 // encodings synonyms
428 CHECK(save_narrow(doc, flags, encoding_utf16) == save_narrow(doc, flags, (is_little_endian() ? encoding_utf16_le : encoding_utf16_be)));
429 CHECK(save_narrow(doc, flags, encoding_utf32) == save_narrow(doc, flags, (is_little_endian() ? encoding_utf32_le : encoding_utf32_be)));
430
431 size_t wcharsize = sizeof(wchar_t);
432 CHECK(save_narrow(doc, flags, encoding_wchar) == save_narrow(doc, flags, (wcharsize == 2 ? encoding_utf16 : encoding_utf32)));
433 }
434
435 TEST_XML(document_save_declaration, "<node/>")
436 {
437 xml_writer_string writer;
438
439 doc.save(writer, STR(""), pugi::format_default, get_native_encoding());
440
441 CHECK(writer.as_string() == STR("<?xml version=\"1.0\"?>\n<node />\n"));
442 }
443
TEST(document_save_declaration_empty)444 TEST(document_save_declaration_empty)
445 {
446 xml_document doc;
447
448 xml_writer_string writer;
449
450 doc.save(writer, STR(""), pugi::format_default, get_native_encoding());
451
452 CHECK(writer.as_string() == STR("<?xml version=\"1.0\"?>\n"));
453 }
454
455 TEST_XML(document_save_declaration_present_first, "<node/>")
456 {
457 doc.insert_child_before(node_declaration, doc.first_child()).append_attribute(STR("encoding")) = STR("utf8");
458
459 xml_writer_string writer;
460
461 doc.save(writer, STR(""), pugi::format_default, get_native_encoding());
462
463 CHECK(writer.as_string() == STR("<?xml encoding=\"utf8\"?>\n<node />\n"));
464 }
465
466 TEST_XML(document_save_declaration_present_second, "<node/>")
467 {
468 doc.insert_child_before(node_declaration, doc.first_child()).append_attribute(STR("encoding")) = STR("utf8");
469 doc.insert_child_before(node_comment, doc.first_child()).set_value(STR("text"));
470
471 xml_writer_string writer;
472
473 doc.save(writer, STR(""), pugi::format_default, get_native_encoding());
474
475 CHECK(writer.as_string() == STR("<!--text-->\n<?xml encoding=\"utf8\"?>\n<node />\n"));
476 }
477
478 TEST_XML(document_save_declaration_present_last, "<node/>")
479 {
480 doc.append_child(node_declaration).append_attribute(STR("encoding")) = STR("utf8");
481
482 xml_writer_string writer;
483
484 doc.save(writer, STR(""), pugi::format_default, get_native_encoding());
485
486 // node writer only looks for declaration before the first element child
487 CHECK(writer.as_string() == STR("<?xml version=\"1.0\"?>\n<node />\n<?xml encoding=\"utf8\"?>\n"));
488 }
489
490 TEST_XML(document_save_declaration_latin1, "<node/>")
491 {
492 xml_writer_string writer;
493
494 doc.save(writer, STR(""), pugi::format_default, encoding_latin1);
495
496 CHECK(writer.as_narrow() == "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<node />\n");
497 }
498
499 struct temp_file
500 {
501 char path[512];
502
temp_filetemp_file503 temp_file()
504 {
505 static int index = 0;
506 sprintf(path, "%stempfile%d", test_runner::_temp_path, index++);
507 }
508
~temp_filetemp_file509 ~temp_file()
510 {
511 #ifndef _WIN32_WCE
512 CHECK(unlink(path) == 0);
513 #endif
514 }
515 };
516
517 TEST_XML(document_save_file, "<node/>")
518 {
519 temp_file f;
520
521 CHECK(doc.save_file(f.path));
522
523 CHECK(doc.load_file(f.path, pugi::parse_default | pugi::parse_declaration));
524 CHECK_NODE(doc, STR("<?xml version=\"1.0\"?><node/>"));
525 }
526
527 TEST_XML(document_save_file_wide, "<node/>")
528 {
529 temp_file f;
530
531 // widen the path
532 wchar_t wpath[sizeof(f.path)];
533 std::copy(f.path, f.path + strlen(f.path) + 1, wpath + 0);
534
535 CHECK(doc.save_file(wpath));
536
537 CHECK(doc.load_file(f.path, pugi::parse_default | pugi::parse_declaration));
538 CHECK_NODE(doc, STR("<?xml version=\"1.0\"?><node/>"));
539 }
540
541 TEST_XML(document_save_file_error, "<node/>")
542 {
543 CHECK(!doc.save_file("tests/data/unknown/output.xml"));
544 }
545
546 TEST_XML(document_save_file_text, "<node/>")
547 {
548 temp_file f;
549
550 CHECK(doc.save_file(f.path, STR(""), pugi::format_no_declaration | pugi::format_save_file_text));
551 CHECK(test_file_contents(f.path, "<node />\n", 9) || test_file_contents(f.path, "<node />\r\n", 10));
552
553 CHECK(doc.save_file(f.path, STR(""), pugi::format_no_declaration));
554 CHECK(test_file_contents(f.path, "<node />\n", 9));
555 }
556
557 TEST_XML(document_save_file_wide_text, "<node/>")
558 {
559 temp_file f;
560
561 // widen the path
562 wchar_t wpath[sizeof(f.path)];
563 std::copy(f.path, f.path + strlen(f.path) + 1, wpath + 0);
564
565 CHECK(doc.save_file(wpath, STR(""), pugi::format_no_declaration | pugi::format_save_file_text));
566 CHECK(test_file_contents(f.path, "<node />\n", 9) || test_file_contents(f.path, "<node />\r\n", 10));
567
568 CHECK(doc.save_file(wpath, STR(""), pugi::format_no_declaration));
569 CHECK(test_file_contents(f.path, "<node />\n", 9));
570 }
571
572 TEST_XML(document_save_file_leak, "<node/>")
573 {
574 temp_file f;
575
576 for (int i = 0; i < 256; ++i)
577 CHECK(doc.save_file(f.path));
578 }
579
580 TEST_XML(document_save_file_wide_leak, "<node/>")
581 {
582 temp_file f;
583
584 // widen the path
585 wchar_t wpath[sizeof(f.path)];
586 std::copy(f.path, f.path + strlen(f.path) + 1, wpath + 0);
587
588 for (int i = 0; i < 256; ++i)
589 CHECK(doc.save_file(wpath));
590 }
591
TEST(document_load_buffer)592 TEST(document_load_buffer)
593 {
594 const pugi::char_t text[] = STR("<?xml?><node/>");
595
596 pugi::xml_document doc;
597
598 CHECK(doc.load_buffer(text, sizeof(text)));
599 CHECK_NODE(doc, STR("<node/>"));
600 }
601
TEST(document_load_buffer_inplace)602 TEST(document_load_buffer_inplace)
603 {
604 pugi::char_t text[] = STR("<?xml?><node/>");
605
606 pugi::xml_document doc;
607
608 CHECK(doc.load_buffer_inplace(text, sizeof(text)));
609 CHECK_NODE(doc, STR("<node/>"));
610 }
611
TEST(document_load_buffer_inplace_own)612 TEST(document_load_buffer_inplace_own)
613 {
614 allocation_function alloc = get_memory_allocation_function();
615
616 size_t size = strlen("<?xml?><node/>") * sizeof(pugi::char_t);
617
618 pugi::char_t* text = static_cast<pugi::char_t*>(alloc(size));
619 CHECK(text);
620
621 memcpy(text, STR("<?xml?><node/>"), size);
622
623 pugi::xml_document doc;
624
625 CHECK(doc.load_buffer_inplace_own(text, size));
626 CHECK_NODE(doc, STR("<node/>"));
627 }
628
TEST(document_parse_result_bool)629 TEST(document_parse_result_bool)
630 {
631 xml_parse_result result;
632
633 result.status = status_ok;
634 CHECK(result);
635 CHECK(!!result);
636 CHECK(result == true);
637
638 for (int i = 1; i < 20; ++i)
639 {
640 result.status = static_cast<xml_parse_status>(i);
641 CHECK(!result);
642 CHECK(result == false);
643 }
644 }
645
TEST(document_parse_result_description)646 TEST(document_parse_result_description)
647 {
648 xml_parse_result result;
649
650 for (int i = 0; i < 20; ++i)
651 {
652 result.status = static_cast<xml_parse_status>(i);
653
654 CHECK(result.description() != 0);
655 CHECK(result.description()[0] != 0);
656 }
657 }
658
TEST(document_load_fail)659 TEST(document_load_fail)
660 {
661 xml_document doc;
662 CHECK(!doc.load_string(STR("<foo><bar/>")));
663 CHECK(doc.child(STR("foo")).child(STR("bar")));
664 }
665
check_utftest_document(const xml_document & doc)666 inline void check_utftest_document(const xml_document& doc)
667 {
668 // ascii text
669 CHECK_STRING(doc.last_child().first_child().name(), STR("English"));
670
671 // check that we have parsed some non-ascii text
672 CHECK(static_cast<unsigned int>(doc.last_child().last_child().name()[0]) >= 0x80);
673
674 // check magic string
675 const pugi::char_t* v = doc.last_child().child(STR("Heavy")).previous_sibling().child_value();
676
677 #ifdef PUGIXML_WCHAR_MODE
678 CHECK(v[0] == 0x4e16 && v[1] == 0x754c && v[2] == 0x6709 && v[3] == 0x5f88 && v[4] == 0x591a && v[5] == wchar_cast(0x8bed) && v[6] == wchar_cast(0x8a00));
679
680 // last character is a surrogate pair
681 size_t wcharsize = sizeof(wchar_t);
682
683 CHECK(wcharsize == 2 ? (v[7] == wchar_cast(0xd852) && v[8] == wchar_cast(0xdf62)) : (v[7] == wchar_cast(0x24b62)));
684 #else
685 // unicode string
686 CHECK_STRING(v, "\xe4\xb8\x96\xe7\x95\x8c\xe6\x9c\x89\xe5\xbe\x88\xe5\xa4\x9a\xe8\xaf\xad\xe8\xa8\x80\xf0\xa4\xad\xa2");
687 #endif
688 }
689
TEST(document_load_file_convert_auto)690 TEST(document_load_file_convert_auto)
691 {
692 const char* files[] =
693 {
694 "tests/data/utftest_utf16_be.xml",
695 "tests/data/utftest_utf16_be_bom.xml",
696 "tests/data/utftest_utf16_be_nodecl.xml",
697 "tests/data/utftest_utf16_le.xml",
698 "tests/data/utftest_utf16_le_bom.xml",
699 "tests/data/utftest_utf16_le_nodecl.xml",
700 "tests/data/utftest_utf32_be.xml",
701 "tests/data/utftest_utf32_be_bom.xml",
702 "tests/data/utftest_utf32_be_nodecl.xml",
703 "tests/data/utftest_utf32_le.xml",
704 "tests/data/utftest_utf32_le_bom.xml",
705 "tests/data/utftest_utf32_le_nodecl.xml",
706 "tests/data/utftest_utf8.xml",
707 "tests/data/utftest_utf8_bom.xml",
708 "tests/data/utftest_utf8_nodecl.xml"
709 };
710
711 xml_encoding encodings[] =
712 {
713 encoding_utf16_be, encoding_utf16_be, encoding_utf16_be,
714 encoding_utf16_le, encoding_utf16_le, encoding_utf16_le,
715 encoding_utf32_be, encoding_utf32_be, encoding_utf32_be,
716 encoding_utf32_le, encoding_utf32_le, encoding_utf32_le,
717 encoding_utf8, encoding_utf8, encoding_utf8
718 };
719
720 for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
721 {
722 xml_document doc;
723 xml_parse_result res = doc.load_file(files[i]);
724
725 CHECK(res);
726 CHECK(res.encoding == encodings[i]);
727 check_utftest_document(doc);
728 }
729 }
730
TEST(document_load_file_convert_specific)731 TEST(document_load_file_convert_specific)
732 {
733 const char* files[] =
734 {
735 "tests/data/utftest_utf16_be.xml",
736 "tests/data/utftest_utf16_be_bom.xml",
737 "tests/data/utftest_utf16_be_nodecl.xml",
738 "tests/data/utftest_utf16_le.xml",
739 "tests/data/utftest_utf16_le_bom.xml",
740 "tests/data/utftest_utf16_le_nodecl.xml",
741 "tests/data/utftest_utf32_be.xml",
742 "tests/data/utftest_utf32_be_bom.xml",
743 "tests/data/utftest_utf32_be_nodecl.xml",
744 "tests/data/utftest_utf32_le.xml",
745 "tests/data/utftest_utf32_le_bom.xml",
746 "tests/data/utftest_utf32_le_nodecl.xml",
747 "tests/data/utftest_utf8.xml",
748 "tests/data/utftest_utf8_bom.xml",
749 "tests/data/utftest_utf8_nodecl.xml"
750 };
751
752 xml_encoding encodings[] =
753 {
754 encoding_utf16_be, encoding_utf16_be, encoding_utf16_be,
755 encoding_utf16_le, encoding_utf16_le, encoding_utf16_le,
756 encoding_utf32_be, encoding_utf32_be, encoding_utf32_be,
757 encoding_utf32_le, encoding_utf32_le, encoding_utf32_le,
758 encoding_utf8, encoding_utf8, encoding_utf8
759 };
760
761 for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
762 {
763 for (unsigned int j = 0; j < sizeof(files) / sizeof(files[0]); ++j)
764 {
765 xml_encoding encoding = encodings[j];
766
767 xml_document doc;
768 xml_parse_result res = doc.load_file(files[i], parse_default, encoding);
769
770 if (encoding == encodings[i])
771 {
772 CHECK(res);
773 CHECK(res.encoding == encoding);
774 check_utftest_document(doc);
775 }
776 else
777 {
778 // should not get past first tag
779 CHECK(!doc.first_child());
780 }
781 }
782 }
783 }
784
TEST(document_load_file_convert_native_endianness)785 TEST(document_load_file_convert_native_endianness)
786 {
787 const char* files[2][6] =
788 {
789 {
790 "tests/data/utftest_utf16_be.xml",
791 "tests/data/utftest_utf16_be_bom.xml",
792 "tests/data/utftest_utf16_be_nodecl.xml",
793 "tests/data/utftest_utf32_be.xml",
794 "tests/data/utftest_utf32_be_bom.xml",
795 "tests/data/utftest_utf32_be_nodecl.xml",
796 },
797 {
798 "tests/data/utftest_utf16_le.xml",
799 "tests/data/utftest_utf16_le_bom.xml",
800 "tests/data/utftest_utf16_le_nodecl.xml",
801 "tests/data/utftest_utf32_le.xml",
802 "tests/data/utftest_utf32_le_bom.xml",
803 "tests/data/utftest_utf32_le_nodecl.xml",
804 }
805 };
806
807 xml_encoding encodings[] =
808 {
809 encoding_utf16, encoding_utf16, encoding_utf16,
810 encoding_utf32, encoding_utf32, encoding_utf32
811 };
812
813 for (unsigned int i = 0; i < sizeof(files[0]) / sizeof(files[0][0]); ++i)
814 {
815 const char* right_file = files[is_little_endian()][i];
816 const char* wrong_file = files[!is_little_endian()][i];
817
818 for (unsigned int j = 0; j < sizeof(encodings) / sizeof(encodings[0]); ++j)
819 {
820 xml_encoding encoding = encodings[j];
821
822 // check file with right endianness
823 {
824 xml_document doc;
825 xml_parse_result res = doc.load_file(right_file, parse_default, encoding);
826
827 if (encoding == encodings[i])
828 {
829 CHECK(res);
830 check_utftest_document(doc);
831 }
832 else
833 {
834 // should not get past first tag
835 CHECK(!doc.first_child());
836 }
837 }
838
839 // check file with wrong endianness
840 {
841 xml_document doc;
842 doc.load_file(wrong_file, parse_default, encoding);
843 CHECK(!doc.first_child());
844 }
845 }
846 }
847 }
848
849 struct file_data_t
850 {
851 const char* path;
852 xml_encoding encoding;
853
854 char* data;
855 size_t size;
856 };
857
858
TEST(document_contents_preserve)859 TEST(document_contents_preserve)
860 {
861 file_data_t files[] =
862 {
863 {"tests/data/utftest_utf16_be_clean.xml", encoding_utf16_be, 0, 0},
864 {"tests/data/utftest_utf16_le_clean.xml", encoding_utf16_le, 0, 0},
865 {"tests/data/utftest_utf32_be_clean.xml", encoding_utf32_be, 0, 0},
866 {"tests/data/utftest_utf32_le_clean.xml", encoding_utf32_le, 0, 0},
867 {"tests/data/utftest_utf8_clean.xml", encoding_utf8, 0, 0}
868 };
869
870 // load files in memory
871 for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
872 {
873 CHECK(load_file_in_memory(files[i].path, files[i].data, files[i].size));
874 }
875
876 // convert each file to each format and compare bitwise
877 for (unsigned int src = 0; src < sizeof(files) / sizeof(files[0]); ++src)
878 {
879 for (unsigned int dst = 0; dst < sizeof(files) / sizeof(files[0]); ++dst)
880 {
881 // parse into document (preserve comments, declaration and whitespace pcdata)
882 xml_document doc;
883 CHECK(doc.load_buffer(files[src].data, files[src].size, parse_default | parse_ws_pcdata | parse_declaration | parse_comments));
884
885 // compare saved document with the original (raw formatting, without extra declaration, write bom if it was in original file)
886 CHECK(test_save_narrow(doc, format_raw | format_no_declaration | format_write_bom, files[dst].encoding, files[dst].data, files[dst].size));
887 }
888 }
889
890 // cleanup
891 for (unsigned int j = 0; j < sizeof(files) / sizeof(files[0]); ++j)
892 {
893 delete[] files[j].data;
894 }
895 }
896
TEST(document_contents_preserve_latin1)897 TEST(document_contents_preserve_latin1)
898 {
899 file_data_t files[] =
900 {
901 {"tests/data/latintest_utf8.xml", encoding_utf8, 0, 0},
902 {"tests/data/latintest_latin1.xml", encoding_latin1, 0, 0}
903 };
904
905 // load files in memory
906 for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
907 {
908 CHECK(load_file_in_memory(files[i].path, files[i].data, files[i].size));
909 }
910
911 // convert each file to each format and compare bitwise
912 for (unsigned int src = 0; src < sizeof(files) / sizeof(files[0]); ++src)
913 {
914 for (unsigned int dst = 0; dst < sizeof(files) / sizeof(files[0]); ++dst)
915 {
916 // parse into document (preserve comments, declaration and whitespace pcdata)
917 xml_document doc;
918 CHECK(doc.load_buffer(files[src].data, files[src].size, parse_default | parse_ws_pcdata | parse_declaration | parse_comments));
919
920 // compare saved document with the original (raw formatting, without extra declaration, write bom if it was in original file)
921 CHECK(test_save_narrow(doc, format_raw | format_no_declaration | format_write_bom, files[dst].encoding, files[dst].data, files[dst].size));
922 }
923 }
924
925 // cleanup
926 for (unsigned int j = 0; j < sizeof(files) / sizeof(files[0]); ++j)
927 {
928 delete[] files[j].data;
929 }
930 }
931
test_parse_fail(const void * buffer,size_t size,xml_encoding encoding=encoding_utf8)932 static bool test_parse_fail(const void* buffer, size_t size, xml_encoding encoding = encoding_utf8)
933 {
934 // copy buffer to heap (to enable out-of-bounds checks)
935 void* temp = malloc(size);
936 memcpy(temp, buffer, size);
937
938 // check that this parses without buffer overflows (yielding an error)
939 xml_document doc;
940 bool result = doc.load_buffer_inplace(temp, size, parse_default, encoding);
941
942 free(temp);
943
944 return !result;
945 }
946
TEST(document_convert_invalid_utf8)947 TEST(document_convert_invalid_utf8)
948 {
949 // invalid 1-byte input
950 CHECK(test_parse_fail("<\xb0", 2));
951
952 // invalid 2-byte input
953 CHECK(test_parse_fail("<\xc0", 2));
954 CHECK(test_parse_fail("<\xd0", 2));
955
956 // invalid 3-byte input
957 CHECK(test_parse_fail("<\xe2\x80", 3));
958 CHECK(test_parse_fail("<\xe2", 2));
959
960 // invalid 4-byte input
961 CHECK(test_parse_fail("<\xf2\x97\x98", 4));
962 CHECK(test_parse_fail("<\xf2\x97", 3));
963 CHECK(test_parse_fail("<\xf2", 2));
964
965 // invalid 5-byte input
966 CHECK(test_parse_fail("<\xf8", 2));
967 }
968
TEST(document_convert_invalid_utf16)969 TEST(document_convert_invalid_utf16)
970 {
971 // check non-terminated degenerate handling
972 CHECK(test_parse_fail("\x00<\xda\x1d", 4, encoding_utf16_be));
973 CHECK(test_parse_fail("<\x00\x1d\xda", 4, encoding_utf16_le));
974
975 // check incorrect leading code
976 CHECK(test_parse_fail("\x00<\xde\x24", 4, encoding_utf16_be));
977 CHECK(test_parse_fail("<\x00\x24\xde", 4, encoding_utf16_le));
978 }
979
TEST(document_load_buffer_empty)980 TEST(document_load_buffer_empty)
981 {
982 xml_encoding encodings[] =
983 {
984 encoding_auto,
985 encoding_utf8,
986 encoding_utf16_le,
987 encoding_utf16_be,
988 encoding_utf16,
989 encoding_utf32_le,
990 encoding_utf32_be,
991 encoding_utf32,
992 encoding_wchar,
993 encoding_latin1
994 };
995
996 char buffer[1];
997
998 for (unsigned int i = 0; i < sizeof(encodings) / sizeof(encodings[0]); ++i)
999 {
1000 xml_encoding encoding = encodings[i];
1001
1002 xml_document doc;
1003 CHECK(doc.load_buffer(buffer, 0, parse_default, encoding).status == status_no_document_element && !doc.first_child());
1004 CHECK(doc.load_buffer(0, 0, parse_default, encoding).status == status_no_document_element && !doc.first_child());
1005
1006 CHECK(doc.load_buffer_inplace(buffer, 0, parse_default, encoding).status == status_no_document_element && !doc.first_child());
1007 CHECK(doc.load_buffer_inplace(0, 0, parse_default, encoding).status == status_no_document_element && !doc.first_child());
1008
1009 void* own_buffer = pugi::get_memory_allocation_function()(1);
1010
1011 CHECK(doc.load_buffer_inplace_own(own_buffer, 0, parse_default, encoding).status == status_no_document_element && !doc.first_child());
1012 CHECK(doc.load_buffer_inplace_own(0, 0, parse_default, encoding).status == status_no_document_element && !doc.first_child());
1013 }
1014 }
1015
TEST(document_load_buffer_empty_fragment)1016 TEST(document_load_buffer_empty_fragment)
1017 {
1018 xml_encoding encodings[] =
1019 {
1020 encoding_auto,
1021 encoding_utf8,
1022 encoding_utf16_le,
1023 encoding_utf16_be,
1024 encoding_utf16,
1025 encoding_utf32_le,
1026 encoding_utf32_be,
1027 encoding_utf32,
1028 encoding_wchar,
1029 encoding_latin1
1030 };
1031
1032 char buffer[1];
1033
1034 for (unsigned int i = 0; i < sizeof(encodings) / sizeof(encodings[0]); ++i)
1035 {
1036 xml_encoding encoding = encodings[i];
1037
1038 xml_document doc;
1039 CHECK(doc.load_buffer(buffer, 0, parse_fragment, encoding) && !doc.first_child());
1040 CHECK(doc.load_buffer(0, 0, parse_fragment, encoding) && !doc.first_child());
1041
1042 CHECK(doc.load_buffer_inplace(buffer, 0, parse_fragment, encoding) && !doc.first_child());
1043 CHECK(doc.load_buffer_inplace(0, 0, parse_fragment, encoding) && !doc.first_child());
1044
1045 void* own_buffer = pugi::get_memory_allocation_function()(1);
1046
1047 CHECK(doc.load_buffer_inplace_own(own_buffer, 0, parse_fragment, encoding) && !doc.first_child());
1048 CHECK(doc.load_buffer_inplace_own(0, 0, parse_fragment, encoding) && !doc.first_child());
1049 }
1050 }
1051
TEST(document_load_buffer_null)1052 TEST(document_load_buffer_null)
1053 {
1054 xml_document doc;
1055
1056 CHECK(doc.load_buffer(0, 12).status == status_io_error && !doc.first_child());
1057 CHECK(doc.load_buffer(0, 12, parse_fragment).status == status_io_error && !doc.first_child());
1058
1059 CHECK(doc.load_buffer_inplace(0, 12).status == status_io_error && !doc.first_child());
1060 CHECK(doc.load_buffer_inplace_own(0, 12).status == status_io_error && !doc.first_child());
1061 }
1062
TEST(document_progressive_truncation)1063 TEST(document_progressive_truncation)
1064 {
1065 char* original_data;
1066 size_t original_size;
1067
1068 CHECK(load_file_in_memory("tests/data/truncation.xml", original_data, original_size));
1069
1070 char* buffer = new char[original_size];
1071
1072 for (size_t i = 1; i <= original_size; ++i)
1073 {
1074 char* truncated_data = buffer + original_size - i;
1075
1076 // default flags
1077 {
1078 memcpy(truncated_data, original_data, i);
1079
1080 xml_document doc;
1081 bool result = doc.load_buffer_inplace(truncated_data, i);
1082
1083 // only eof is parseable
1084 CHECK((i == original_size) ? result : !result);
1085 }
1086
1087 // fragment mode
1088 {
1089 memcpy(truncated_data, original_data, i);
1090
1091 xml_document doc;
1092 bool result = doc.load_buffer_inplace(truncated_data, i, parse_default | parse_fragment);
1093
1094 // some truncate locations are parseable - those that come after declaration, declaration + doctype, declaration + doctype + comment and eof
1095 CHECK(((i - 21) < 3 || (i - 66) < 3 || (i - 95) < 3 || i == original_size) ? result : !result);
1096 }
1097 }
1098
1099 delete[] buffer;
1100 delete[] original_data;
1101 }
1102
TEST(document_load_buffer_short)1103 TEST(document_load_buffer_short)
1104 {
1105 char* data = new char[4];
1106 memcpy(data, "abcd", 4);
1107
1108 xml_document doc;
1109
1110 CHECK(doc.load_buffer(data, 4).status == status_no_document_element);
1111 CHECK(doc.load_buffer(data + 1, 3).status == status_no_document_element);
1112 CHECK(doc.load_buffer(data + 2, 2).status == status_no_document_element);
1113 CHECK(doc.load_buffer(data + 3, 1).status == status_no_document_element);
1114 CHECK(doc.load_buffer(data + 4, 0).status == status_no_document_element);
1115 CHECK(doc.load_buffer(0, 0).status == status_no_document_element);
1116
1117 delete[] data;
1118 }
1119
TEST(document_load_buffer_short_fragment)1120 TEST(document_load_buffer_short_fragment)
1121 {
1122 char* data = new char[4];
1123 memcpy(data, "abcd", 4);
1124
1125 xml_document doc;
1126
1127 CHECK(doc.load_buffer(data, 4, parse_fragment) && test_string_equal(doc.text().get(), STR("abcd")));
1128 CHECK(doc.load_buffer(data + 1, 3, parse_fragment) && test_string_equal(doc.text().get(), STR("bcd")));
1129 CHECK(doc.load_buffer(data + 2, 2, parse_fragment) && test_string_equal(doc.text().get(), STR("cd")));
1130 CHECK(doc.load_buffer(data + 3, 1, parse_fragment) && test_string_equal(doc.text().get(), STR("d")));
1131 CHECK(doc.load_buffer(data + 4, 0, parse_fragment) && !doc.first_child());
1132 CHECK(doc.load_buffer(0, 0, parse_fragment) && !doc.first_child());
1133
1134 delete[] data;
1135 }
1136
TEST(document_load_buffer_inplace_short)1137 TEST(document_load_buffer_inplace_short)
1138 {
1139 char* data = new char[4];
1140 memcpy(data, "abcd", 4);
1141
1142 xml_document doc;
1143
1144 CHECK(doc.load_buffer_inplace(data, 4).status == status_no_document_element);
1145 CHECK(doc.load_buffer_inplace(data + 1, 3).status == status_no_document_element);
1146 CHECK(doc.load_buffer_inplace(data + 2, 2).status == status_no_document_element);
1147 CHECK(doc.load_buffer_inplace(data + 3, 1).status == status_no_document_element);
1148 CHECK(doc.load_buffer_inplace(data + 4, 0).status == status_no_document_element);
1149 CHECK(doc.load_buffer_inplace(0, 0).status == status_no_document_element);
1150
1151 delete[] data;
1152 }
1153
1154 #ifndef PUGIXML_NO_EXCEPTIONS
TEST(document_load_exceptions)1155 TEST(document_load_exceptions)
1156 {
1157 bool thrown = false;
1158
1159 try
1160 {
1161 pugi::xml_document doc;
1162 if (!doc.load_string(STR("<node attribute='value"))) throw std::bad_alloc();
1163
1164 CHECK_FORCE_FAIL("Expected parsing failure");
1165 }
1166 catch (const std::bad_alloc&)
1167 {
1168 thrown = true;
1169 }
1170
1171 CHECK(thrown);
1172 }
1173 #endif
1174
1175 TEST_XML_FLAGS(document_element, "<?xml version='1.0'?><node><child/></node><!---->", parse_default | parse_declaration | parse_comments)
1176 {
1177 CHECK(doc.document_element() == doc.child(STR("node")));
1178 }
1179
1180 TEST_XML_FLAGS(document_element_absent, "<!---->", parse_comments | parse_fragment)
1181 {
1182 CHECK(doc.document_element() == xml_node());
1183 }
1184
1185 TEST_XML(document_reset, "<node><child/></node>")
1186 {
1187 CHECK(doc.first_child());
1188
1189 doc.reset();
1190 CHECK(!doc.first_child());
1191 CHECK_NODE(doc, STR(""));
1192
1193 doc.reset();
1194 CHECK(!doc.first_child());
1195 CHECK_NODE(doc, STR(""));
1196
1197 CHECK(doc.load_string(STR("<node/>")));
1198 CHECK(doc.first_child());
1199 CHECK_NODE(doc, STR("<node/>"));
1200
1201 doc.reset();
1202 CHECK(!doc.first_child());
1203 CHECK_NODE(doc, STR(""));
1204 }
1205
TEST(document_reset_empty)1206 TEST(document_reset_empty)
1207 {
1208 xml_document doc;
1209
1210 doc.reset();
1211 CHECK(!doc.first_child());
1212 CHECK_NODE(doc, STR(""));
1213 }
1214
1215 TEST_XML(document_reset_copy, "<node><child/></node>")
1216 {
1217 xml_document doc2;
1218
1219 CHECK_NODE(doc2, STR(""));
1220
1221 doc2.reset(doc);
1222
1223 CHECK_NODE(doc2, STR("<node><child/></node>"));
1224 CHECK(doc.first_child() != doc2.first_child());
1225
1226 doc.reset(doc2);
1227
1228 CHECK_NODE(doc, STR("<node><child/></node>"));
1229 CHECK(doc.first_child() != doc2.first_child());
1230
1231 CHECK(doc.first_child().offset_debug() == -1);
1232 }
1233
1234 TEST_XML(document_reset_copy_self, "<node><child/></node>")
1235 {
1236 CHECK_NODE(doc, STR("<node><child/></node>"));
1237
1238 doc.reset(doc);
1239
1240 CHECK(!doc.first_child());
1241 CHECK_NODE(doc, STR(""));
1242 }
1243
TEST(document_load_buffer_utf_truncated)1244 TEST(document_load_buffer_utf_truncated)
1245 {
1246 const unsigned char utf8[] = {'<', 0xe2, 0x82, 0xac, '/', '>'};
1247 const unsigned char utf16_be[] = {0, '<', 0x20, 0xac, 0, '/', 0, '>'};
1248 const unsigned char utf16_le[] = {'<', 0, 0xac, 0x20, '/', 0, '>', 0};
1249 const unsigned char utf32_be[] = {0, 0, 0, '<', 0, 0, 0x20, 0xac, 0, 0, 0, '/', 0, 0, 0, '>'};
1250 const unsigned char utf32_le[] = {'<', 0, 0, 0, 0xac, 0x20, 0, 0, '/', 0, 0, 0, '>', 0, 0, 0};
1251
1252 struct document_data_t
1253 {
1254 xml_encoding encoding;
1255
1256 const unsigned char* data;
1257 size_t size;
1258 };
1259
1260 const document_data_t data[] =
1261 {
1262 { encoding_utf8, utf8, sizeof(utf8) },
1263 { encoding_utf16_be, utf16_be, sizeof(utf16_be) },
1264 { encoding_utf16_le, utf16_le, sizeof(utf16_le) },
1265 { encoding_utf32_be, utf32_be, sizeof(utf32_be) },
1266 { encoding_utf32_le, utf32_le, sizeof(utf32_le) },
1267 };
1268
1269 for (size_t i = 0; i < sizeof(data) / sizeof(data[0]); ++i)
1270 {
1271 const document_data_t& d = data[i];
1272
1273 for (size_t j = 0; j <= d.size; ++j)
1274 {
1275 char* buffer = new char[j];
1276 memcpy(buffer, d.data, j);
1277
1278 xml_document doc;
1279 xml_parse_result res = doc.load_buffer(buffer, j, parse_default, d.encoding);
1280
1281 if (j == d.size)
1282 {
1283 CHECK(res);
1284
1285 const char_t* name = doc.first_child().name();
1286
1287 #ifdef PUGIXML_WCHAR_MODE
1288 CHECK(name[0] == 0x20ac && name[1] == 0);
1289 #else
1290 CHECK_STRING(name, "\xe2\x82\xac");
1291 #endif
1292 }
1293 else
1294 {
1295 CHECK(!res || !doc.first_child());
1296 }
1297
1298 delete[] buffer;
1299 }
1300 }
1301 }
1302
1303 #ifndef PUGIXML_NO_STL
TEST(document_load_stream_truncated)1304 TEST(document_load_stream_truncated)
1305 {
1306 const unsigned char utf32_be[] = {0, 0, 0, '<', 0, 0, 0x20, 0xac, 0, 0, 0, '/', 0, 0, 0, '>'};
1307
1308 for (size_t i = 0; i <= sizeof(utf32_be); ++i)
1309 {
1310 std::string prefix(reinterpret_cast<const char*>(utf32_be), i);
1311 std::istringstream iss(prefix);
1312
1313 xml_document doc;
1314 xml_parse_result res = doc.load(iss);
1315
1316 if (i == sizeof(utf32_be))
1317 {
1318 CHECK(res);
1319 }
1320 else
1321 {
1322 CHECK(!res || !doc.first_child());
1323
1324 if (i < 8)
1325 {
1326 CHECK(!doc.first_child());
1327 }
1328 else
1329 {
1330 const char_t* name = doc.first_child().name();
1331
1332 #ifdef PUGIXML_WCHAR_MODE
1333 CHECK(name[0] == 0x20ac && name[1] == 0);
1334 #else
1335 CHECK_STRING(name, "\xe2\x82\xac");
1336 #endif
1337 }
1338 }
1339 }
1340 }
1341 #endif
1342
TEST(document_alignment)1343 TEST(document_alignment)
1344 {
1345 char buf[256 + sizeof(xml_document)];
1346
1347 for (size_t offset = 0; offset < 256; offset += sizeof(void*))
1348 {
1349 xml_document* doc = new (buf + offset) xml_document;
1350
1351 CHECK(doc->load_string(STR("<node />")));
1352 CHECK_NODE(*doc, STR("<node/>"));
1353
1354 doc->~xml_document();
1355 }
1356 }
1357
TEST(document_convert_out_of_memory)1358 TEST(document_convert_out_of_memory)
1359 {
1360 file_data_t files[] =
1361 {
1362 {"tests/data/utftest_utf16_be_clean.xml", encoding_utf16_be, 0, 0},
1363 {"tests/data/utftest_utf16_le_clean.xml", encoding_utf16_le, 0, 0},
1364 {"tests/data/utftest_utf32_be_clean.xml", encoding_utf32_be, 0, 0},
1365 {"tests/data/utftest_utf32_le_clean.xml", encoding_utf32_le, 0, 0},
1366 {"tests/data/utftest_utf8_clean.xml", encoding_utf8, 0, 0},
1367 {"tests/data/latintest_latin1.xml", encoding_latin1, 0, 0}
1368 };
1369
1370 // load files in memory
1371 for (unsigned int i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
1372 {
1373 CHECK(load_file_in_memory(files[i].path, files[i].data, files[i].size));
1374 }
1375
1376 // disallow allocations
1377 test_runner::_memory_fail_threshold = 1;
1378
1379 for (unsigned int src = 0; src < sizeof(files) / sizeof(files[0]); ++src)
1380 {
1381 xml_document doc;
1382 CHECK_ALLOC_FAIL(CHECK(doc.load_buffer(files[src].data, files[src].size, parse_default, files[src].encoding).status == status_out_of_memory));
1383 }
1384
1385 // cleanup
1386 for (unsigned int j = 0; j < sizeof(files) / sizeof(files[0]); ++j)
1387 {
1388 delete[] files[j].data;
1389 }
1390 }
1391
TEST(document_deprecated_load)1392 TEST(document_deprecated_load)
1393 {
1394 xml_document doc;
1395 CHECK(doc.load(STR("<node/>")));
1396 CHECK_NODE(doc, STR("<node/>"));
1397 }
1398