1.3.49
 
Loading...
Searching...
No Matches
Test_XML.h
1#pragma once
2// =================================================================================
3// Suite 3: XML Parsing Utilities
4//
5// Tests for functions related to loading data from XML files and nodes.
6// =================================================================================
7TEST_CASE("XMLoad functions") {
8 pugi::xml_document doc;
9 pugi::xml_node node = doc.append_child("node");
10 node.append_child("float").text().set("1.23");
11 node.append_child("int").text().set("123");
12 node.append_child("string").text().set("hello");
13 node.append_child("vec2").text().set("1.1 2.2");
14 node.append_child("vec3").text().set("1.1 2.2 3.3");
15 node.append_child("vec4").text().set("1.1 2.2 3.3 4.4");
16 node.append_child("int2").text().set("1 2");
17 node.append_child("int3").text().set("1 2 3");
18 node.append_child("int4").text().set("1 2 3 4");
19 node.append_child("rgb").text().set("0.1 0.2 0.3");
20 node.append_child("rgba").text().set("0.1 0.2 0.3 0.4");
21
22 SUBCASE("XMLloadfloat") {
23 float f = XMLloadfloat(node, "float");
24 DOCTEST_CHECK(f == doctest::Approx(1.23f));
25 }
26 SUBCASE("XMLloadint") {
27 int i = XMLloadint(node, "int");
28 DOCTEST_CHECK(i == 123);
29 }
30 SUBCASE("XMLloadstring") {
31 std::string s = XMLloadstring(node, "string");
32 DOCTEST_CHECK(s == "hello");
33 }
34 SUBCASE("XMLloadvec2") {
35 vec2 v = XMLloadvec2(node, "vec2");
36 DOCTEST_CHECK(v == vec2(1.1f, 2.2f));
37 }
38 SUBCASE("XMLloadvec3") {
39 vec3 v = XMLloadvec3(node, "vec3");
40 DOCTEST_CHECK(v == vec3(1.1f, 2.2f, 3.3f));
41 }
42 SUBCASE("XMLloadvec4") {
43 vec4 v = XMLloadvec4(node, "vec4");
44 DOCTEST_CHECK(v == vec4(1.1f, 2.2f, 3.3f, 4.4f));
45 }
46 SUBCASE("XMLloadint2") {
47 int2 i = XMLloadint2(node, "int2");
48 DOCTEST_CHECK(i == int2(1, 2));
49 }
50 SUBCASE("XMLloadint3") {
51 int3 i = XMLloadint3(node, "int3");
52 DOCTEST_CHECK(i == int3(1, 2, 3));
53 }
54 SUBCASE("XMLloadint4") {
55 int4 i = XMLloadint4(node, "int4");
56 DOCTEST_CHECK(i == int4(1, 2, 3, 4));
57 }
58 SUBCASE("XMLoad* for missing nodes") {
59 pugi::xml_document doc;
60 pugi::xml_node node = doc.append_child("node");
61 // The XMLoad functions throw when the node is not found, so we check for that.
62 capture_cerr cerr_buffer;
63 DOCTEST_CHECK(XMLloadfloat(node, "non_existent") == 99999);
64 DOCTEST_CHECK(XMLloadint(node, "non_existent") == 99999);
65 DOCTEST_CHECK(XMLloadstring(node, "non_existent") == "99999");
66 DOCTEST_CHECK(XMLloadvec2(node, "non_existent") == vec2(99999, 99999));
67 DOCTEST_CHECK(XMLloadvec3(node, "non_existent") == vec3(99999, 99999, 99999));
68 DOCTEST_CHECK(XMLloadvec4(node, "non_existent") == vec4(99999, 99999, 99999, 99999));
69 DOCTEST_CHECK(XMLloadint2(node, "non_existent") == int2(99999, 99999));
70 DOCTEST_CHECK(XMLloadint3(node, "non_existent") == int3(99999, 99999, 99999));
71 DOCTEST_CHECK(XMLloadint4(node, "non_existent") == int4(99999, 99999, 99999, 99999));
72 DOCTEST_CHECK(XMLloadrgb(node, "non_existent") == RGBcolor(99999, 99999, 99999));
73 DOCTEST_CHECK(XMLloadrgba(node, "non_existent") == RGBAcolor(99999, 99999, 99999, 99999));
74 }
75 SUBCASE("XMLoad* for missing fields") {
76 pugi::xml_document doc;
77 pugi::xml_node node = doc.append_child("tag");
78 DOCTEST_CHECK(XMLloadfloat(node, "non_existent") == 99999);
79 DOCTEST_CHECK(XMLloadint(node, "non_existent") == 99999);
80 DOCTEST_CHECK(XMLloadstring(node, "non_existent") == "99999");
81 DOCTEST_CHECK(XMLloadvec2(node, "non_existent") == make_vec2(99999, 99999));
82 DOCTEST_CHECK(XMLloadvec3(node, "non_existent") == make_vec3(99999, 99999, 99999));
83 }
84
85 SUBCASE("parse_xml_tag_*") {
86 pugi::xml_document doc;
87 pugi::xml_node node = doc.append_child("tag");
88 node.text().set(" 123 ");
89 int i = parse_xml_tag_int(node, "tag", "test");
90 DOCTEST_CHECK(i == 123);
91 node.text().set(" 1.23 ");
92 float f = parse_xml_tag_float(node, "tag", "test");
93 DOCTEST_CHECK(f == doctest::Approx(1.23f));
94 node.text().set(" 1.1 2.2 ");
95 vec2 v2 = parse_xml_tag_vec2(node, "tag", "test");
96 DOCTEST_CHECK(v2 == vec2(1.1f, 2.2f));
97 node.text().set(" 1.1 2.2 3.3 ");
98 vec3 v3 = parse_xml_tag_vec3(node, "tag", "test");
99 DOCTEST_CHECK(v3 == vec3(1.1f, 2.2f, 3.3f));
100 node.text().set(" hello ");
101 std::string s = parse_xml_tag_string(node, "tag", "test");
102 DOCTEST_CHECK(s == "hello");
103
104 capture_cerr cerr_buffer;
105 node.text().set("abc");
106 int result_int;
107 DOCTEST_CHECK_THROWS(result_int = parse_xml_tag_int(node, "tag", "test"));
108 float result_float;
109 DOCTEST_CHECK_THROWS(result_float = parse_xml_tag_float(node, "tag", "test"));
110 vec2 result_vec2;
111 DOCTEST_CHECK_THROWS(result_vec2 = parse_xml_tag_vec2(node, "tag", "test"));
112 vec3 result_vec3;
113 DOCTEST_CHECK_THROWS(result_vec3 = parse_xml_tag_vec3(node, "tag", "test"));
114 }
115
116 SUBCASE("open_xml_file") {
117 pugi::xml_document doc;
118 std::string error_string;
119 DOCTEST_CHECK(!open_xml_file("non_existent.xml", doc, error_string));
120 DOCTEST_CHECK(!error_string.empty());
121
122 // Create a dummy invalid xml file
123 std::ofstream outfile("invalid.xml");
124 outfile << "<helios><data>blah</helios>";
125 outfile.close();
126 DOCTEST_CHECK(!open_xml_file("invalid.xml", doc, error_string));
127
128 // Create a dummy valid xml file
129 outfile.open("valid.xml");
130 outfile << "<helios><data>blah</data></helios>";
131 outfile.close();
132 DOCTEST_CHECK(open_xml_file("valid.xml", doc, error_string));
133 std::remove("invalid.xml");
134 std::remove("valid.xml");
135 }
136}
137
138TEST_CASE("Context XML I/O Functions") {
139 SUBCASE("writeXML and loadXML") {
140 Context ctx;
141
142 // Create some test data
143 uint patch = ctx.addPatch(make_vec3(1, 2, 3), make_vec2(2, 4), nullrotation, RGB::red);
144 uint triangle = ctx.addTriangle(make_vec3(0, 0, 0), make_vec3(1, 0, 0), make_vec3(0, 1, 0), RGB::blue);
145 uint box = ctx.addBoxObject(make_vec3(0, 0, 0), make_vec3(1, 1, 1), make_int3(1, 1, 1));
146
147 // Add some data
148 ctx.setPrimitiveData(patch, "test_data", 42.0f);
149 ctx.setObjectData(box, "object_data", "test_string");
150 ctx.setGlobalData("global_test", 123);
151
152 // Write to XML (use quiet parameter to avoid output)
153 const char *test_file = "helios_test.xml";
154 DOCTEST_CHECK_NOTHROW(ctx.writeXML(test_file, true));
155
156 // Create new context and load (use quiet parameter)
157 Context ctx2;
158 std::vector<uint> loaded_uuids;
159 DOCTEST_CHECK_NOTHROW(loaded_uuids = ctx2.loadXML(test_file, true));
160 DOCTEST_CHECK(loaded_uuids.size() >= 2);
161
162 // Verify loaded data
163 DOCTEST_CHECK(ctx2.getPrimitiveCount() >= 2);
164 DOCTEST_CHECK(ctx2.getObjectCount() >= 1);
165
166 // Check primitive data was loaded
167 bool found_data = false;
168 for (uint uuid: loaded_uuids) {
169 if (ctx2.doesPrimitiveDataExist(uuid, "test_data")) {
170 float data;
171 ctx2.getPrimitiveData(uuid, "test_data", data);
172 DOCTEST_CHECK(data == doctest::Approx(42.0f));
173 found_data = true;
174 break;
175 }
176 }
177 DOCTEST_CHECK(found_data);
178
179 // Check global data
180 int global_val;
181 ctx2.getGlobalData("global_test", global_val);
182 DOCTEST_CHECK(global_val == 123);
183
184 // Clean up
185 std::remove(test_file);
186 }
187
188 SUBCASE("writeXML_byobject") {
189 Context ctx;
190 uint box1 = ctx.addBoxObject(make_vec3(0, 0, 0), make_vec3(1, 1, 1), make_int3(1, 1, 1));
191 uint box2 = ctx.addBoxObject(make_vec3(2, 0, 0), make_vec3(1, 1, 1), make_int3(1, 1, 1));
192
193 std::vector<uint> selected_objects = {box1};
194 const char *test_file = "helios_partial_test.xml";
195
196 // Use quiet parameter to avoid output
197 DOCTEST_CHECK_NOTHROW(ctx.writeXML_byobject(test_file, selected_objects, true));
198
199 Context ctx2;
200 std::vector<uint> loaded_uuids = ctx2.loadXML(test_file, true);
201
202 // Should only have primitives from one box (6 faces)
203 DOCTEST_CHECK(loaded_uuids.size() == 6);
204 DOCTEST_CHECK(ctx2.getObjectCount() == 1);
205
206 std::remove(test_file);
207 }
208
209 SUBCASE("writeXML with specific UUIDs") {
210 Context ctx;
211 uint p1 = ctx.addPatch(make_vec3(0, 0, 0), make_vec2(1, 1));
212 uint p2 = ctx.addPatch(make_vec3(1, 0, 0), make_vec2(1, 1));
213 uint p3 = ctx.addPatch(make_vec3(2, 0, 0), make_vec2(1, 1));
214
215 std::vector<uint> selected_uuids = {p1, p3};
216 const char *test_file = "helios_uuid_test.xml";
217
218 // Use quiet parameter to avoid output
219 DOCTEST_CHECK_NOTHROW(ctx.writeXML(test_file, selected_uuids, true));
220
221 Context ctx2;
222 std::vector<uint> loaded_uuids = ctx2.loadXML(test_file, true);
223
224 DOCTEST_CHECK(loaded_uuids.size() == 2);
225
226 std::remove(test_file);
227 }
228
229 SUBCASE("getLoadedXMLFiles") {
230 Context ctx;
231
232 // Initially should be empty
233 std::vector<std::string> files = ctx.getLoadedXMLFiles();
234 size_t initial_count = files.size();
235
236 // Create and load a test file using current working directory (cross-platform)
237 uint patch = ctx.addPatch();
238 std::string test_file = "helios_loaded_files_test.xml";
239 // Use quiet parameter to avoid output
240 ctx.writeXML(test_file.c_str(), true);
241
242 Context ctx2;
243 ctx2.loadXML(test_file.c_str(), true);
244
245 std::vector<std::string> loaded_files = ctx2.getLoadedXMLFiles();
246 DOCTEST_CHECK(loaded_files.size() == initial_count + 1);
247
248 // Compare against the resolved path, not the original path
249 std::filesystem::path resolved_test_file = resolveProjectFile(test_file);
250 std::string resolved_test_file_str = resolved_test_file.string();
251 DOCTEST_CHECK(std::find(loaded_files.begin(), loaded_files.end(), resolved_test_file_str) != loaded_files.end());
252
253 std::remove(test_file.c_str());
254 }
255
256 SUBCASE("XML I/O quiet parameter") {
257 Context ctx;
258 uint patch = ctx.addPatch(make_vec3(0, 0, 0), make_vec2(1, 1));
259 const char *test_file = "helios_quiet_test.xml";
260
261 // Test writeXML with quiet=false (should produce output)
262 {
263 capture_cout cout_buffer;
264 ctx.writeXML(test_file, false);
265 DOCTEST_CHECK(cout_buffer.get_captured_output().find("Writing XML file") != std::string::npos);
266 }
267
268 // Test loadXML with quiet=false (should produce output)
269 Context ctx2;
270 {
271 capture_cout cout_buffer;
272 ctx2.loadXML(test_file, false);
273 DOCTEST_CHECK(cout_buffer.get_captured_output().find("Loading XML file") != std::string::npos);
274 }
275
276 // Test writeXML with quiet=true (should not produce output)
277 {
278 capture_cout cout_buffer;
279 ctx.writeXML(test_file, true);
280 DOCTEST_CHECK(cout_buffer.get_captured_output().find("Writing XML file") == std::string::npos);
281 }
282
283 // Test loadXML with quiet=true (should not produce output)
284 Context ctx3;
285 {
286 capture_cout cout_buffer;
287 ctx3.loadXML(test_file, true);
288 DOCTEST_CHECK(cout_buffer.get_captured_output().find("Loading XML file") == std::string::npos);
289 }
290
291 std::remove(test_file);
292 }
293
294 // Note: scanXMLForTag testing removed due to complex XML tag structure requirements
295}