openMSX
XMLOutputStream_test.cc
Go to the documentation of this file.
1#include "catch.hpp"
2#include "XMLOutputStream.hh"
3#include <sstream>
4
5// Write to a 'stringstream' instead of a file.
6// Throws an exception instead of assert'ing on error.
8{
9public:
10 explicit TestWriter(std::stringstream& ss_)
11 : ss(ss_) {}
12 void write(std::span<const char> buf) {
13 ss.write(buf.data(), buf.size());
14 }
15 void write1(char c) {
16 ss.put(c);
17 }
18 void check(bool condition) const {
19 if (!condition) {
20 throw std::logic_error("assertion failed");
21 }
22 }
23private:
24 std::stringstream& ss;
25};
26
27TEST_CASE("XMLOutputStream: simple")
28{
29 std::stringstream ss;
30 TestWriter writer(ss);
31 XMLOutputStream xml(writer);
32
33 SECTION("empty") {
34 CHECK(ss.str().empty());
35 }
36 SECTION("2 nested tags, inner tag empty") {
37 xml.begin("abc");
38 xml.begin("def");
39 xml.end("def");
40 xml.end("abc");
41 CHECK(ss.str() == "<abc>\n <def/>\n</abc>\n");
42 }
43 SECTION("2 nested tags, inner tag with data") {
44 xml.begin("abc");
45 xml.begin("def");
46 xml.data("foobar");
47 xml.end("def");
48 xml.end("abc");
49 CHECK(ss.str() == "<abc>\n <def>foobar</def>\n</abc>\n");
50 }
51 SECTION("2 nested tags, inner tag with attribute, no data") {
52 xml.begin("abc");
53 xml.begin("def");
54 xml.attribute("foo", "bar");
55 xml.end("def");
56 xml.end("abc");
57 CHECK(ss.str() == "<abc>\n <def foo=\"bar\"/>\n</abc>\n");
58 }
59 SECTION("2 nested tags, inner tag with attribute and data") {
60 xml.begin("abc");
61 xml.begin("def");
62 xml.attribute("foo", "bar");
63 xml.data("qux");
64 xml.end("def");
65 xml.end("abc");
66 CHECK(ss.str() == "<abc>\n <def foo=\"bar\">qux</def>\n</abc>\n");
67 }
68}
69
70TEST_CASE("XMLOutputStream: complex")
71{
72 std::stringstream ss;
73 TestWriter writer(ss);
74 XMLOutputStream xml(writer);
75
76 xml.begin("settings");
77 xml.begin("settings");
78 xml.begin("setting");
79 xml.attribute("id", "noise");
80 xml.data("3.0");
81 xml.end("setting");
82 xml.end("settings");
83 xml.begin("bindings");
84 xml.begin("bind");
85 xml.attribute("key", "keyb F6");
86 xml.data("cycle \"videosource\"");
87 xml.end("bind");
88 xml.end("bindings");
89 xml.end("settings");
90
91 std::string expected =
92 "<settings>\n"
93 " <settings>\n"
94 " <setting id=\"noise\">3.0</setting>\n"
95 " </settings>\n"
96 " <bindings>\n"
97 " <bind key=\"keyb F6\">cycle &quot;videosource&quot;</bind>\n"
98 " </bindings>\n"
99 "</settings>\n";
100 CHECK(ss.str() == expected);
101}
102
103TEST_CASE("XMLOutputStream: errors")
104{
105 std::stringstream ss;
106 TestWriter writer(ss);
107 XMLOutputStream xml(writer);
108
109 SECTION("more end than begin") {
110 xml.begin("bla");
111 xml.end("bla");
112 CHECK_THROWS(xml.end("bla"));
113 }
114 SECTION("attribute after data") {
115 xml.begin("bla");
116 xml.data("qux");
117 CHECK_THROWS(xml.attribute("foo", "bar"));
118 //xml.end("bla");
119 }
120 SECTION("attribute after end") {
121 xml.begin("bla");
122 xml.begin("bla");
123 xml.end("bla");
124 CHECK_THROWS(xml.attribute("foo", "bar"));
125 //xml.end("bla");
126 }
127 SECTION("begin after data") {
128 xml.begin("bla");
129 xml.data("qux");
130 CHECK_THROWS(xml.begin("bla"));
131 // xml.end("bla");
132 //xml.end("bla");
133 }
134 SECTION("data after end") {
135 xml.begin("bla");
136 xml.begin("bla");
137 xml.end("bla");
138 CHECK_THROWS(xml.data("qux"));
139 //xml.end("bla");
140 }
141 SECTION("data after data") {
142 xml.begin("bla");
143 xml.begin("bla");
144 xml.data("bla");
145 CHECK_THROWS(xml.data("qux"));
146 //xml.end("bla");
147 //xml.end("bla");
148 }
149#ifdef DEBUG // only detected when compiled with -DDEBUG
150 SECTION("non-matching begin/end") {
151 xml.begin("bla");
152 xml.begin("bla");
153 xml.data("foobar");
154 xml.end("bla");
155 CHECK_THROWS(xml.end("err"));
156 }
157#endif
158}
TEST_CASE("XMLOutputStream: simple")
void check(bool condition) const
void write(std::span< const char > buf)
void write1(char c)
TestWriter(std::stringstream &ss_)
'XMLOutputStream' is a helper to write an XML file in a streaming way.
void attribute(std::string_view name, std::string_view value)
void begin(std::string_view tag)
void end(std::string_view tag)
void data(std::string_view value)
CHECK(m3==m3)