From c3be17d8793aea29a438b704315858e9e4d5fded Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Sun, 7 Aug 2022 14:48:52 +0100
Subject: Simplified document interfaces

---
 slicer/json/serializer.cpp  | 22 ++------------
 slicer/json/serializer.h    | 21 ++++++-------
 slicer/test/serializers.cpp | 73 ++++-----------------------------------------
 slicer/xml/serializer.cpp   | 22 ++------------
 slicer/xml/serializer.h     | 27 +++++++----------
 5 files changed, 30 insertions(+), 135 deletions(-)

diff --git a/slicer/json/serializer.cpp b/slicer/json/serializer.cpp
index 6d99725..e2db939 100644
--- a/slicer/json/serializer.cpp
+++ b/slicer/json/serializer.cpp
@@ -368,14 +368,11 @@ namespace Slicer {
 	void
 	JsonStreamSerializer::Serialize(ModelPartForRootPtr modelRoot)
 	{
-		json::Value doc;
-		modelRoot->OnEachChild([&doc](auto &&, auto && PH2, auto &&) {
-			return JsonSerializer::ModelTreeIterateRoot(&doc, PH2);
-		});
-		json::serializeValue(doc, strm, "utf-8");
+		JsonValueSerializer::Serialize(modelRoot);
+		json::serializeValue(value, strm, "utf-8");
 	}
 
-	JsonFileSerializer::JsonFileSerializer(std::filesystem::path p) : path(std::move(p)) { }
+	JsonFileSerializer::JsonFileSerializer(const std::filesystem::path & p) : JsonStreamSerializer {strm}, strm(p) { }
 
 	JsonFileDeserializer::JsonFileDeserializer(std::filesystem::path p) : path(std::move(p)) { }
 
@@ -388,19 +385,6 @@ namespace Slicer {
 		std::visit(DocumentTreeIterate(mp), obj);
 	}
 
-	void
-	JsonFileSerializer::Serialize(ModelPartForRootPtr modelRoot)
-	{
-		json::Value doc;
-		modelRoot->OnEachChild([&doc](auto &&, auto && PH2, auto &&) {
-			return JsonSerializer::ModelTreeIterateRoot(&doc, PH2);
-		});
-		std::ofstream outFile(path);
-		json::serializeValue(doc, outFile, "utf-8");
-	}
-
-	JsonValueSerializer::JsonValueSerializer(json::Value & v) : value(v) { }
-
 	JsonValueDeserializer::JsonValueDeserializer(const json::Value & v) : value(v) { }
 
 	void
diff --git a/slicer/json/serializer.h b/slicer/json/serializer.h
index 32500e8..e2687ce 100644
--- a/slicer/json/serializer.h
+++ b/slicer/json/serializer.h
@@ -2,6 +2,7 @@
 #define SLICER_JSON_H
 
 #include <filesystem>
+#include <fstream>
 #include <iosfwd>
 #include <jsonpp.h>
 #include <slicer/modelParts.h>
@@ -18,34 +19,30 @@ namespace Slicer {
 		static void ModelTreeIterateRoot(json::Value *, ModelPartPtr mp);
 	};
 
-	class DLL_PUBLIC JsonStreamSerializer : public JsonSerializer {
+	class DLL_PUBLIC JsonValueSerializer : public JsonSerializer {
 	public:
-		explicit JsonStreamSerializer(std::ostream &);
-
 		void Serialize(ModelPartForRootPtr) override;
 
 	protected:
-		std::ostream & strm;
+		json::Value value;
 	};
 
-	class DLL_PUBLIC JsonFileSerializer : public JsonSerializer {
+	class DLL_PUBLIC JsonStreamSerializer : public JsonValueSerializer {
 	public:
-		explicit JsonFileSerializer(std::filesystem::path);
+		explicit JsonStreamSerializer(std::ostream &);
 
 		void Serialize(ModelPartForRootPtr) override;
 
 	protected:
-		const std::filesystem::path path;
+		std::ostream & strm;
 	};
 
-	class DLL_PUBLIC JsonValueSerializer : public JsonSerializer {
+	class DLL_PUBLIC JsonFileSerializer : public JsonStreamSerializer {
 	public:
-		explicit JsonValueSerializer(json::Value &);
-
-		void Serialize(ModelPartForRootPtr) override;
+		explicit JsonFileSerializer(const std::filesystem::path &);
 
 	protected:
-		json::Value & value;
+		std::ofstream strm;
 	};
 
 	class DLL_PUBLIC JsonStreamDeserializer : public Deserializer {
diff --git a/slicer/test/serializers.cpp b/slicer/test/serializers.cpp
index 9389090..6efc02b 100644
--- a/slicer/test/serializers.cpp
+++ b/slicer/test/serializers.cpp
@@ -104,46 +104,6 @@ public:
 		BOOST_TEST_CHECKPOINT("Checksum: " << input << " === " << output);
 		diff(expected, output);
 	}
-
-	template<typename T, typename Deserializer, typename Serializer, typename Internal>
-	void
-	verifyByHelper(const fs::path & infile, const std::function<Internal(const fs::path &)> & in,
-			const std::function<void(const Internal &, const fs::path &)> & out,
-			const std::function<void(Internal &)> & ifree, const std::function<void(const T &)> & check = nullptr)
-	{
-		const fs::path input = rootDir / "initial" / infile;
-		const fs::path tmph = binDir / "byHandler";
-		fs::create_directory(tmph);
-		const fs::path output = tmph / infile;
-
-		BOOST_TEST_CHECKPOINT("Read: " << input);
-		Internal docRead = in(input);
-
-		BOOST_TEST_CHECKPOINT("Deserialize: " << input);
-		T p = Slicer::DeserializeAny<Deserializer, T>(docRead);
-		ifree(docRead);
-
-		if (check) {
-			BOOST_TEST_CHECKPOINT("Check1: " << input);
-			check(p);
-		}
-
-		BOOST_TEST_CHECKPOINT("Serialize: " << input);
-		Internal docWrite;
-		Slicer::SerializeAny<Serializer>(p, docWrite);
-
-		if (check) {
-			BOOST_TEST_CHECKPOINT("Check2: " << input);
-			check(p);
-		}
-
-		BOOST_TEST_CHECKPOINT("Write: " << output);
-		out(docWrite, output);
-		ifree(docWrite);
-
-		BOOST_TEST_CHECKPOINT("Checksum: " << input << " === " << output);
-		diff(input, output);
-	}
 };
 
 void
@@ -638,28 +598,6 @@ BOOST_AUTO_TEST_CASE(invalid_enum)
 
 BOOST_AUTO_TEST_SUITE_END()
 
-BOOST_FIXTURE_TEST_SUITE(byHandler, FileBased)
-
-BOOST_AUTO_TEST_CASE(optionals_areset2_json)
-{
-	verifyByHelper<TestModule::OptionalsPtr, Slicer::JsonValueDeserializer, Slicer::JsonValueSerializer, json::Value>(
-			"optionals-areset2.json", readJson, writeJson, freeJson, checkOptionals_areset);
-}
-
-BOOST_AUTO_TEST_CASE(optionals_areset_xml)
-{
-	verifyByHelper<TestModule::OptionalsPtr, Slicer::XmlDocumentDeserializer, Slicer::XmlDocumentSerializer,
-			xmlpp::Document *>("optionals-areset.xml", readXml, writeXml, freeXml, checkOptionals_areset);
-}
-
-BOOST_AUTO_TEST_CASE(simple_complete_validator)
-{
-	verifyByHelper<TestModule::IsoDate, Slicer::XmlDocumentDeserializer, Slicer::XmlDocumentSerializer,
-			xmlpp::Document *>("isodate.xml", readXml, writeXml, freeXml);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
 BOOST_AUTO_TEST_CASE(missingConversion)
 {
 	auto in = json::parseValue(R"J({"conv": "2016-06-30 12:34:56"})J");
@@ -667,8 +605,7 @@ BOOST_AUTO_TEST_CASE(missingConversion)
 			Slicer::NoConversionFound);
 
 	auto obj = std::make_shared<TestModule2::MissingConv>("2016-06-30 12:34:56");
-	json::Value v;
-	BOOST_REQUIRE_THROW(Slicer::SerializeAny<Slicer::JsonValueSerializer>(obj, v), Slicer::NoConversionFound);
+	BOOST_REQUIRE_THROW(Slicer::SerializeAny<Slicer::JsonValueSerializer>(obj), Slicer::NoConversionFound);
 }
 
 BOOST_AUTO_TEST_CASE(conversion)
@@ -677,9 +614,9 @@ BOOST_AUTO_TEST_CASE(conversion)
 	auto obj = Slicer::DeserializeAny<Slicer::JsonValueDeserializer, TestModule2::ConvPtr>(in);
 	BOOST_REQUIRE_EQUAL("2016-06-30 12:34:56", obj->conv);
 
-	json::Value v;
-	Slicer::SerializeAny<Slicer::JsonValueSerializer>(obj, v);
-	BOOST_REQUIRE_EQUAL("2016-06-30 12:34:56", std::get<json::String>(std::get<json::Object>(v)["conv"]));
+	std::stringstream out;
+	Slicer::SerializeAny<Slicer::JsonStreamSerializer>(obj, out);
+	BOOST_REQUIRE_EQUAL(R"J({"conv":"2016-06-30 12:34:56"})J", out.view());
 }
 
 BOOST_AUTO_TEST_CASE(DeserializeJsonAbstractEmpty)
@@ -747,7 +684,7 @@ BOOST_AUTO_TEST_CASE(DeserializeXmlIncorrectSeqElementName)
 
 BOOST_AUTO_TEST_CASE(customerModelPartCounters)
 {
-	BOOST_REQUIRE_EQUAL(35, TestModule::completions);
+	BOOST_REQUIRE_EQUAL(22, TestModule::completions);
 }
 
 BOOST_AUTO_TEST_CASE(enum_lookups)
diff --git a/slicer/xml/serializer.cpp b/slicer/xml/serializer.cpp
index 76efa95..96c1a9f 100644
--- a/slicer/xml/serializer.cpp
+++ b/slicer/xml/serializer.cpp
@@ -441,14 +441,11 @@ namespace Slicer {
 	void
 	XmlStreamSerializer::Serialize(ModelPartForRootPtr modelRoot)
 	{
-		xmlpp::Document doc;
-		modelRoot->OnEachChild([&doc](auto && PH1, auto && PH2, auto &&) {
-			return XmlSerializer::ModelTreeIterateRoot(&doc, PH1, PH2);
-		});
+		XmlDocumentSerializer::Serialize(modelRoot);
 		doc.write_to_stream(strm);
 	}
 
-	XmlFileSerializer::XmlFileSerializer(std::filesystem::path p) : path(std::move(p)) { }
+	XmlFileSerializer::XmlFileSerializer(const std::filesystem::path & p) : XmlStreamSerializer {strm}, strm(p) { }
 
 	XmlFileDeserializer::XmlFileDeserializer(std::filesystem::path p) : path(std::move(p)) { }
 
@@ -460,18 +457,6 @@ namespace Slicer {
 		DocumentTreeIterate(doc, modelRoot);
 	}
 
-	void
-	XmlFileSerializer::Serialize(ModelPartForRootPtr modelRoot)
-	{
-		xmlpp::Document doc;
-		modelRoot->OnEachChild([&doc](auto && PH1, auto && PH2, auto &&) {
-			return XmlSerializer::ModelTreeIterateRoot(&doc, PH1, PH2);
-		});
-		doc.write_to_file_formatted(path);
-	}
-
-	XmlDocumentSerializer::XmlDocumentSerializer(xmlpp::Document *& d) : doc(d) { }
-
 	XmlDocumentDeserializer::XmlDocumentDeserializer(const xmlpp::Document * d) : doc(d) { }
 
 	void
@@ -483,9 +468,8 @@ namespace Slicer {
 	void
 	XmlDocumentSerializer::Serialize(ModelPartForRootPtr modelRoot)
 	{
-		doc = new xmlpp::Document();
 		modelRoot->OnEachChild([this](auto && PH1, auto && PH2, auto &&) {
-			return XmlSerializer::ModelTreeIterateRoot(doc, PH1, PH2);
+			return XmlSerializer::ModelTreeIterateRoot(&doc, PH1, PH2);
 		});
 	}
 
diff --git a/slicer/xml/serializer.h b/slicer/xml/serializer.h
index fd8616c..d07a77e 100644
--- a/slicer/xml/serializer.h
+++ b/slicer/xml/serializer.h
@@ -8,9 +8,11 @@
 #ifndef __clang__
 #	pragma GCC diagnostic ignored "-Wuseless-cast"
 #endif
+#include <libxml++/document.h>
 #include <libxml++/nodes/element.h>
 #pragma GCC diagnostic pop
 #include <filesystem>
+#include <fstream>
 #include <functional>
 #include <iosfwd>
 #include <slicer/modelParts.h>
@@ -20,10 +22,6 @@
 namespace Glib {
 	class ustring;
 }
-namespace xmlpp {
-	class Document;
-	class Node;
-}
 
 namespace Slicer {
 	using CurrentElementCreator = ::AdHoc::LazyPointer<xmlpp::Element, xmlpp::Element *>;
@@ -41,35 +39,30 @@ namespace Slicer {
 		static void ModelTreeIterateDictElements(xmlpp::Element * element, const ModelPartPtr & dict);
 	};
 
-	class DLL_PUBLIC XmlStreamSerializer : public XmlSerializer {
+	class DLL_PUBLIC XmlDocumentSerializer : public XmlSerializer {
 	public:
-		explicit XmlStreamSerializer(std::ostream &);
-
 		void Serialize(ModelPartForRootPtr) override;
 
 	protected:
-		std::ostream & strm;
+		xmlpp::Document doc;
 	};
 
-	class DLL_PUBLIC XmlFileSerializer : public XmlSerializer {
+	class DLL_PUBLIC XmlStreamSerializer : public XmlDocumentSerializer {
 	public:
-		explicit XmlFileSerializer(std::filesystem::path);
+		explicit XmlStreamSerializer(std::ostream &);
 
 		void Serialize(ModelPartForRootPtr) override;
 
 	protected:
-		const std::filesystem::path path;
+		std::ostream & strm;
 	};
 
-	class DLL_PUBLIC XmlDocumentSerializer : public XmlSerializer {
+	class DLL_PUBLIC XmlFileSerializer : public XmlStreamSerializer {
 	public:
-		explicit XmlDocumentSerializer(xmlpp::Document *&);
-
-		void Serialize(ModelPartForRootPtr) override;
+		explicit XmlFileSerializer(const std::filesystem::path &);
 
 	protected:
-		// cppcheck-suppress unsafeClassCanLeak
-		xmlpp::Document *& doc;
+		std::ofstream strm;
 	};
 
 	class DLL_PUBLIC XmlDeserializer : public Deserializer {
-- 
cgit v1.2.3