From 5eed07c6203865e23f7f2bbfcac2051acd95f650 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Tue, 5 Jun 2018 18:35:49 +0200
Subject: [PATCH] make cli fully extendable by file type modifiers

---
 alib2cli/makefile.conf                        |   2 +-
 .../InputFileTypeRegistration.cpp             |  49 ------
 .../OutputFileTypeRegistration.cpp            |  43 -----
 alib2raw_cli_integration/Doxyfile             |   9 +
 alib2raw_cli_integration/makefile             |   3 +
 alib2raw_cli_integration/makefile.conf        |   9 +
 .../src/InputFileTypeRegistration.cpp         |  34 ++++
 .../src/OutputFileTypeRegistration.cpp        |  32 ++++
 alib2raw_cli_integration/test-src/main.cpp    | 164 ++++++++++++++++++
 alib2str_cli_integration/Doxyfile             |   9 +
 alib2str_cli_integration/makefile             |   3 +
 alib2str_cli_integration/makefile.conf        |   9 +
 .../src/InputFileTypeRegistration.cpp         |  34 ++++
 .../src/OutputFileTypeRegistration.cpp        |  32 ++++
 alib2str_cli_integration/test-src/main.cpp    | 164 ++++++++++++++++++
 aql2/makefile.conf                            |   2 +-
 makefile                                      |   4 +-
 17 files changed, 507 insertions(+), 95 deletions(-)
 create mode 100644 alib2raw_cli_integration/Doxyfile
 create mode 100644 alib2raw_cli_integration/makefile
 create mode 100644 alib2raw_cli_integration/makefile.conf
 create mode 100644 alib2raw_cli_integration/src/InputFileTypeRegistration.cpp
 create mode 100644 alib2raw_cli_integration/src/OutputFileTypeRegistration.cpp
 create mode 100644 alib2raw_cli_integration/test-src/main.cpp
 create mode 100644 alib2str_cli_integration/Doxyfile
 create mode 100644 alib2str_cli_integration/makefile
 create mode 100644 alib2str_cli_integration/makefile.conf
 create mode 100644 alib2str_cli_integration/src/InputFileTypeRegistration.cpp
 create mode 100644 alib2str_cli_integration/src/OutputFileTypeRegistration.cpp
 create mode 100644 alib2str_cli_integration/test-src/main.cpp

diff --git a/alib2cli/makefile.conf b/alib2cli/makefile.conf
index 89e4689b2d..a433dc4b45 100644
--- a/alib2cli/makefile.conf
+++ b/alib2cli/makefile.conf
@@ -1,7 +1,7 @@
 LIBRARY:=alib2cli
 TESTBIN:=alib2test
 
-LINK_LIBRARIES=alib2raw alib2str alib2data alib2xml alib2common alib2abstraction alib2measure alib2std
+LINK_LIBRARIES=alib2xml alib2common alib2abstraction alib2measure alib2std
 SYSTEM_LIBRARIES=xml2 stdc++fs
 SYSTEM_INCLUDE_PATHS=/usr/include/libxml2
 TEST_LINK_LIBRARIES=
diff --git a/alib2cli/src/registration/InputFileTypeRegistration.cpp b/alib2cli/src/registration/InputFileTypeRegistration.cpp
index 1635f9e9c1..9f2a432922 100644
--- a/alib2cli/src/registration/InputFileTypeRegistration.cpp
+++ b/alib2cli/src/registration/InputFileTypeRegistration.cpp
@@ -1,10 +1,7 @@
 #include "InputFileTypeRegistration.hpp"
 
 #include <registry/XmlRegistry.h>
-#include <registry/StringReaderRegistry.hpp>
-#include <registry/RawReaderRegistry.hpp>
 
-#include <abstraction/ImmediateValueAbstraction.hpp>
 #include <abstraction/XmlTokensParserAbstraction.hpp>
 #include <abstraction/WrapperAbstraction.hpp>
 #include <abstraction/PackingAbstraction.hpp>
@@ -56,53 +53,7 @@ namespace {
 		return abstraction::Registry::getAlgorithmAbstraction ( "cli::builtin::ReadFile", templateParams, paramTypes, category );
 	}
 
-	std::shared_ptr < abstraction::OperationAbstraction > dummy3 ( const std::string & typehint, const ext::vector < std::string > & ) {
-		ext::vector < std::shared_ptr < abstraction::OperationAbstraction > > abstractions;
-
-		ext::vector < std::string > templateParams;
-		ext::vector < std::string > paramTypes { ext::to_string < std::string > ( ) };
-		abstraction::AlgorithmCategories::AlgorithmCategory category = abstraction::AlgorithmCategories::AlgorithmCategory::NONE;
-
-		abstractions.push_back ( abstraction::Registry::getAlgorithmAbstraction ( "cli::builtin::ReadFile", templateParams, paramTypes, category ) );
-
-		auto stringParserAbstractionFinder = [ = ] ( const std::string & data ) {
-			return abstraction::StringReaderRegistry::getAbstraction ( typehint, data );
-		};
-
-		abstractions.push_back ( std::make_shared < abstraction::WrapperAbstraction < abstraction::UnspecifiedType, std::string && > > ( stringParserAbstractionFinder ) );
-
-		std::shared_ptr < abstraction::PackingAbstraction < 1 > > res = std::make_shared < abstraction::PackingAbstraction < 1 > > ( std::move ( abstractions ), 1 );
-		res->setInnerConnection ( 0, 1, 0, true );
-		res->setOuterConnection ( 0, 0, 0 );
-
-		return res;
-	}
-
-	std::shared_ptr < abstraction::OperationAbstraction > dummy4 ( const std::string & typehint, const ext::vector < std::string > & ) {
-		ext::vector < std::shared_ptr < abstraction::OperationAbstraction > > abstractions;
-
-		ext::vector < std::string > templateParams;
-		ext::vector < std::string > paramTypes { ext::to_string < std::string > ( ) };
-		abstraction::AlgorithmCategories::AlgorithmCategory category = abstraction::AlgorithmCategories::AlgorithmCategory::NONE;
-
-		abstractions.push_back ( abstraction::Registry::getAlgorithmAbstraction ( "cli::builtin::ReadFile", templateParams, paramTypes, category ) );
-
-		auto rawParserAbstractionFinder = [ = ] ( const std::string & ) {
-			return abstraction::RawReaderRegistry::getAbstraction ( typehint );
-		};
-
-		abstractions.push_back ( std::make_shared < abstraction::WrapperAbstraction < abstraction::UnspecifiedType, std::string && > > ( rawParserAbstractionFinder ) );
-
-		std::shared_ptr < abstraction::PackingAbstraction < 1 > > res = std::make_shared < abstraction::PackingAbstraction < 1 > > ( std::move ( abstractions ), 1 );
-		res->setInnerConnection ( 0, 1, 0, true );
-		res->setOuterConnection ( 0, 0, 0 );
-
-		return res;
-	}
-
 auto xmlInputFileHandler = registration::InputFileRegister ( "xml", dummy );
 auto fileInputFileHandler = registration::InputFileRegister ( "file", dummy2 );
-auto stringInputFileHandler = registration::InputFileRegister ( "string", dummy3 );
-auto rawInputFileHandler = registration::InputFileRegister ( "raw", dummy4 );
 
 }
diff --git a/alib2cli/src/registration/OutputFileTypeRegistration.cpp b/alib2cli/src/registration/OutputFileTypeRegistration.cpp
index 9245135895..2e4f4a4fd4 100644
--- a/alib2cli/src/registration/OutputFileTypeRegistration.cpp
+++ b/alib2cli/src/registration/OutputFileTypeRegistration.cpp
@@ -3,10 +3,7 @@
 #include <exception/CommonException.h>
 
 #include <registry/XmlRegistry.h>
-#include <registry/StringWriterRegistry.hpp>
-#include <registry/RawWriterRegistry.hpp>
 
-#include <abstraction/ImmediateValueAbstraction.hpp>
 #include <abstraction/XmlTokensComposerAbstraction.hpp>
 #include <abstraction/PackingAbstraction.hpp>
 
@@ -36,47 +33,7 @@ namespace {
 		return abstraction::Registry::getAlgorithmAbstraction ( "cli::builtin::WriteFile", templateParams, paramTypes, category );
 	}
 
-	std::shared_ptr < abstraction::OperationAbstraction > dummy3 ( const std::string & typehint ) {
-		ext::vector < std::shared_ptr < abstraction::OperationAbstraction > > abstractions;
-
-		abstractions.push_back ( abstraction::StringWriterRegistry::getAbstraction ( typehint ) );
-
-		ext::vector < std::string > templateParams;
-		ext::vector < std::string > paramTypes { ext::to_string < std::string > ( ), ext::to_string < std::string > ( ) };
-		abstraction::AlgorithmCategories::AlgorithmCategory category = abstraction::AlgorithmCategories::AlgorithmCategory::NONE;
-
-		abstractions.push_back ( abstraction::Registry::getAlgorithmAbstraction ( "cli::builtin::WriteFile", templateParams, paramTypes, category ) );
-
-		std::shared_ptr < abstraction::PackingAbstraction < 2 > > res = std::make_shared < abstraction::PackingAbstraction < 2 > > ( std::move ( abstractions ), 1 );
-		res->setInnerConnection ( 0, 1, 1, true );
-		res->setOuterConnection ( 0, 1, 0 ); // filename
-		res->setOuterConnection ( 1, 0, 0 ); // data
-
-		return res;
-	}
-
-	std::shared_ptr < abstraction::OperationAbstraction > dummy4 ( const std::string & typehint ) {
-		ext::vector < std::shared_ptr < abstraction::OperationAbstraction > > abstractions;
-
-		abstractions.push_back ( abstraction::RawWriterRegistry::getAbstraction ( typehint ) );
-
-		ext::vector < std::string > templateParams;
-		ext::vector < std::string > paramTypes { ext::to_string < std::string > ( ), ext::to_string < std::string > ( ) };
-		abstraction::AlgorithmCategories::AlgorithmCategory category = abstraction::AlgorithmCategories::AlgorithmCategory::NONE;
-
-		abstractions.push_back ( abstraction::Registry::getAlgorithmAbstraction ( "cli::builtin::WriteFile", templateParams, paramTypes, category ) );
-
-		std::shared_ptr < abstraction::PackingAbstraction < 2 > > res = std::make_shared < abstraction::PackingAbstraction < 2 > > ( std::move ( abstractions ), 1 );
-		res->setInnerConnection ( 0, 1, 1, true );
-		res->setOuterConnection ( 0, 1, 0 ); // filename
-		res->setOuterConnection ( 1, 0, 0 ); // data
-
-		return res;
-	}
-
 auto xmlOutputFileHandler = registration::OutputFileRegister ( "xml", dummy );
 auto fileOutputFileHandler = registration::OutputFileRegister ( "file", dummy2 );
-auto stringOutputFileHandler = registration::OutputFileRegister ( "string", dummy3 );
-auto rawOutputFileHandler = registration::OutputFileRegister ( "raw", dummy4 );
 
 }
diff --git a/alib2raw_cli_integration/Doxyfile b/alib2raw_cli_integration/Doxyfile
new file mode 100644
index 0000000000..c8b05a1d06
--- /dev/null
+++ b/alib2raw_cli_integration/Doxyfile
@@ -0,0 +1,9 @@
+@INCLUDE = ../Doxyfile-library
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "alib2raw"
diff --git a/alib2raw_cli_integration/makefile b/alib2raw_cli_integration/makefile
new file mode 100644
index 0000000000..0b88694038
--- /dev/null
+++ b/alib2raw_cli_integration/makefile
@@ -0,0 +1,3 @@
+-include makefile.conf
+-include ../build.conf
+-include ../makefile-library
diff --git a/alib2raw_cli_integration/makefile.conf b/alib2raw_cli_integration/makefile.conf
new file mode 100644
index 0000000000..8a0672aae3
--- /dev/null
+++ b/alib2raw_cli_integration/makefile.conf
@@ -0,0 +1,9 @@
+LIBRARY:=alib2raw_cli_integration
+TESTBIN:=alib2test
+
+LINK_LIBRARIES=alib2raw alib2data alib2cli alib2xml alib2common alib2abstraction alib2measure alib2std
+SYSTEM_LIBRARIES=xml2
+SYSTEM_INCLUDE_PATHS=/usr/include/libxml2
+TEST_LINK_LIBRARIES=
+TEST_SYSTEM_LIBRARIES=
+TEST_SYSTEM_INCLUDE_PATHS=
diff --git a/alib2raw_cli_integration/src/InputFileTypeRegistration.cpp b/alib2raw_cli_integration/src/InputFileTypeRegistration.cpp
new file mode 100644
index 0000000000..eb9eb3cb04
--- /dev/null
+++ b/alib2raw_cli_integration/src/InputFileTypeRegistration.cpp
@@ -0,0 +1,34 @@
+#include <registration/InputFileTypeRegistration.hpp>
+
+#include <registry/RawReaderRegistry.hpp>
+
+#include <abstraction/WrapperAbstraction.hpp>
+#include <abstraction/PackingAbstraction.hpp>
+
+namespace {
+
+	std::shared_ptr < abstraction::OperationAbstraction > dummy4 ( const std::string & typehint, const ext::vector < std::string > & ) {
+		ext::vector < std::shared_ptr < abstraction::OperationAbstraction > > abstractions;
+
+		ext::vector < std::string > templateParams;
+		ext::vector < std::string > paramTypes { ext::to_string < std::string > ( ) };
+		abstraction::AlgorithmCategories::AlgorithmCategory category = abstraction::AlgorithmCategories::AlgorithmCategory::NONE;
+
+		abstractions.push_back ( abstraction::Registry::getAlgorithmAbstraction ( "cli::builtin::ReadFile", templateParams, paramTypes, category ) );
+
+		auto rawParserAbstractionFinder = [ = ] ( const std::string & ) {
+			return abstraction::RawReaderRegistry::getAbstraction ( typehint );
+		};
+
+		abstractions.push_back ( std::make_shared < abstraction::WrapperAbstraction < abstraction::UnspecifiedType, std::string && > > ( rawParserAbstractionFinder ) );
+
+		std::shared_ptr < abstraction::PackingAbstraction < 1 > > res = std::make_shared < abstraction::PackingAbstraction < 1 > > ( std::move ( abstractions ), 1 );
+		res->setInnerConnection ( 0, 1, 0, true );
+		res->setOuterConnection ( 0, 0, 0 );
+
+		return res;
+	}
+
+auto rawInputFileHandler = registration::InputFileRegister ( "raw", dummy4 );
+
+}
diff --git a/alib2raw_cli_integration/src/OutputFileTypeRegistration.cpp b/alib2raw_cli_integration/src/OutputFileTypeRegistration.cpp
new file mode 100644
index 0000000000..bb03f39f52
--- /dev/null
+++ b/alib2raw_cli_integration/src/OutputFileTypeRegistration.cpp
@@ -0,0 +1,32 @@
+#include <registration/OutputFileTypeRegistration.hpp>
+
+#include <exception/CommonException.h>
+
+#include <registry/RawWriterRegistry.hpp>
+
+#include <abstraction/PackingAbstraction.hpp>
+
+namespace {
+
+	std::shared_ptr < abstraction::OperationAbstraction > dummy4 ( const std::string & typehint ) {
+		ext::vector < std::shared_ptr < abstraction::OperationAbstraction > > abstractions;
+
+		abstractions.push_back ( abstraction::RawWriterRegistry::getAbstraction ( typehint ) );
+
+		ext::vector < std::string > templateParams;
+		ext::vector < std::string > paramTypes { ext::to_string < std::string > ( ), ext::to_string < std::string > ( ) };
+		abstraction::AlgorithmCategories::AlgorithmCategory category = abstraction::AlgorithmCategories::AlgorithmCategory::NONE;
+
+		abstractions.push_back ( abstraction::Registry::getAlgorithmAbstraction ( "cli::builtin::WriteFile", templateParams, paramTypes, category ) );
+
+		std::shared_ptr < abstraction::PackingAbstraction < 2 > > res = std::make_shared < abstraction::PackingAbstraction < 2 > > ( std::move ( abstractions ), 1 );
+		res->setInnerConnection ( 0, 1, 1, true );
+		res->setOuterConnection ( 0, 1, 0 ); // filename
+		res->setOuterConnection ( 1, 0, 0 ); // data
+
+		return res;
+	}
+
+auto rawOutputFileHandler = registration::OutputFileRegister ( "raw", dummy4 );
+
+}
diff --git a/alib2raw_cli_integration/test-src/main.cpp b/alib2raw_cli_integration/test-src/main.cpp
new file mode 100644
index 0000000000..fd442ebd12
--- /dev/null
+++ b/alib2raw_cli_integration/test-src/main.cpp
@@ -0,0 +1,164 @@
+#include <tclap/CmdLine.h>
+
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/XmlOutputter.h>
+
+#include <cppunit/Test.h>
+#include <cppunit/TestFailure.h>
+#include <cppunit/portability/Stream.h>
+#include <cppunit/TestListener.h>
+#include <cppunit/SourceLine.h>
+#include <cppunit/Exception.h>
+
+#include <exception/CommonException.h>
+
+CPPUNIT_NS_BEGIN
+
+class CPPUNIT_API TestProgressListener : public TestListener
+{
+public:
+	TestProgressListener();
+
+	virtual ~TestProgressListener();
+
+	void startTest( Test *test );
+
+	void addFailure( const TestFailure &failure );
+
+	void endTest( Test *test );
+
+	int getResult() const;
+
+	void printResults() const;
+
+private:
+	TestProgressListener( const TestProgressListener &copy );
+
+	void operator =( const TestProgressListener &copy );
+
+private:
+	int m_Failures;
+	int m_Tests;
+	int m_Assertions;
+	bool m_lastTestFailed;
+};
+
+TestProgressListener::TestProgressListener() : m_Failures( 0 ), m_Tests(0), m_Assertions(0), m_lastTestFailed( false )
+{
+}
+
+TestProgressListener::~TestProgressListener()
+{
+}
+
+void TestProgressListener::startTest( Test * test )
+{
+	stdCOut() << test->getName() << ":" << "\n";
+	stdCOut().flush();
+
+	m_lastTestFailed = false;
+	m_Tests++;
+}
+
+void TestProgressListener::addFailure( const TestFailure &failure )
+{
+	stdCOut() << (failure.isError() ? "error" : "assertion") << " : " << failure.failedTestName() << " : " << failure.sourceLine().lineNumber() << "\n";
+	stdCOut() << "Exception " << failure.thrownException()->message().details();
+
+	m_lastTestFailed = true;
+	if(failure.isError()) m_Failures++; else m_Assertions++;
+}
+
+void TestProgressListener::endTest( Test * test)
+{
+	stdCOut() << "Result (" << test->getName() << ")";
+	stdCOut().flush();
+
+	if ( !m_lastTestFailed )
+		stdCOut() <<	" : OK";
+	else
+		stdCOut() << " : Fail";
+	stdCOut() << "\n\n";
+}
+
+int TestProgressListener::getResult() const {
+	return m_Failures + m_Assertions;
+}
+
+void TestProgressListener::printResults() const {
+	stdCOut() << "Overal result: Tests: " << m_Tests << " Assertions: " << m_Assertions << " Failures: " << m_Failures << "\n";
+}
+
+CPPUNIT_NS_END
+
+int main(int argc, char* argv[]) {
+	try {
+		TCLAP::CmdLine cmd("Main test binary.", ' ', "0.01");
+
+		TCLAP::MultiArg<std::string> testPathSegments("p", "path", "test path", false, "string" );
+		cmd.add( testPathSegments );
+
+		cmd.parse(argc, argv);
+
+		CppUnit::TestResult controller;
+
+		CppUnit::TestResultCollector result;
+		controller.addListener( &result );
+
+		CppUnit::TestProgressListener progressListener;
+		controller.addListener( &progressListener );
+
+		CppUnit::Test *suite = NULL;
+		std::string testPath = "";
+		if(testPathSegments.getValue().size() == 0) {
+			// Get the top level suite from the registry
+			suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
+		} else if(testPathSegments.getValue().size() == 1) {
+			suite = CppUnit::TestFactoryRegistry::getRegistry(testPathSegments.getValue()[0]).makeTest();
+		} else {
+			suite = CppUnit::TestFactoryRegistry::getRegistry(testPathSegments.getValue()[0]).makeTest();
+			bool first = true;
+			for(const std::string& path : testPathSegments.getValue()) {
+				if(first) {
+					first = false;
+					continue;
+				}
+				testPath += path + "/";
+			}
+			testPath.pop_back();
+		}
+
+		// Adds the test to the list of test to run
+		CppUnit::TextUi::TestRunner runner;
+		runner.addTest( suite );
+
+		// Change the default outputter to a compiler error format outputter
+		runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(), std::cerr ) );
+		// Run the tests.
+		runner.run( controller, testPath );
+
+		progressListener.printResults();
+
+		std::ofstream xmlFileResults("CppUnitTestResults.xml");
+		CppUnit::XmlOutputter xmlOut(&result, xmlFileResults);
+		xmlOut.write();
+
+		return progressListener.getResult();
+	} catch(const exception::CommonException& exception) {
+		std::cerr << exception.getCause() << std::endl;
+		return 1;
+	} catch(const TCLAP::ArgException& exception) {
+		std::cerr << exception.error() << std::endl;
+		return 2;
+	} catch (const std::exception& exception) {
+		std::cerr << "Exception caught: " << exception.what() << std::endl;
+		return 3;
+	} catch(...) {
+		std::cerr << "Unknown exception caught." << std::endl;
+		return 127;
+	}
+}
diff --git a/alib2str_cli_integration/Doxyfile b/alib2str_cli_integration/Doxyfile
new file mode 100644
index 0000000000..c8b05a1d06
--- /dev/null
+++ b/alib2str_cli_integration/Doxyfile
@@ -0,0 +1,9 @@
+@INCLUDE = ../Doxyfile-library
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "alib2raw"
diff --git a/alib2str_cli_integration/makefile b/alib2str_cli_integration/makefile
new file mode 100644
index 0000000000..0b88694038
--- /dev/null
+++ b/alib2str_cli_integration/makefile
@@ -0,0 +1,3 @@
+-include makefile.conf
+-include ../build.conf
+-include ../makefile-library
diff --git a/alib2str_cli_integration/makefile.conf b/alib2str_cli_integration/makefile.conf
new file mode 100644
index 0000000000..1c01f70032
--- /dev/null
+++ b/alib2str_cli_integration/makefile.conf
@@ -0,0 +1,9 @@
+LIBRARY:=alib2str_cli_integration
+TESTBIN:=alib2test
+
+LINK_LIBRARIES=alib2str alib2data alib2cli alib2xml alib2common alib2abstraction alib2measure alib2std
+SYSTEM_LIBRARIES=xml2
+SYSTEM_INCLUDE_PATHS=/usr/include/libxml2
+TEST_LINK_LIBRARIES=
+TEST_SYSTEM_LIBRARIES=
+TEST_SYSTEM_INCLUDE_PATHS=
diff --git a/alib2str_cli_integration/src/InputFileTypeRegistration.cpp b/alib2str_cli_integration/src/InputFileTypeRegistration.cpp
new file mode 100644
index 0000000000..6748fcc71c
--- /dev/null
+++ b/alib2str_cli_integration/src/InputFileTypeRegistration.cpp
@@ -0,0 +1,34 @@
+#include <registration/InputFileTypeRegistration.hpp>
+
+#include <registry/StringReaderRegistry.hpp>
+
+#include <abstraction/WrapperAbstraction.hpp>
+#include <abstraction/PackingAbstraction.hpp>
+
+namespace {
+
+	std::shared_ptr < abstraction::OperationAbstraction > dummy3 ( const std::string & typehint, const ext::vector < std::string > & ) {
+		ext::vector < std::shared_ptr < abstraction::OperationAbstraction > > abstractions;
+
+		ext::vector < std::string > templateParams;
+		ext::vector < std::string > paramTypes { ext::to_string < std::string > ( ) };
+		abstraction::AlgorithmCategories::AlgorithmCategory category = abstraction::AlgorithmCategories::AlgorithmCategory::NONE;
+
+		abstractions.push_back ( abstraction::Registry::getAlgorithmAbstraction ( "cli::builtin::ReadFile", templateParams, paramTypes, category ) );
+
+		auto stringParserAbstractionFinder = [ = ] ( const std::string & data ) {
+			return abstraction::StringReaderRegistry::getAbstraction ( typehint, data );
+		};
+
+		abstractions.push_back ( std::make_shared < abstraction::WrapperAbstraction < abstraction::UnspecifiedType, std::string && > > ( stringParserAbstractionFinder ) );
+
+		std::shared_ptr < abstraction::PackingAbstraction < 1 > > res = std::make_shared < abstraction::PackingAbstraction < 1 > > ( std::move ( abstractions ), 1 );
+		res->setInnerConnection ( 0, 1, 0, true );
+		res->setOuterConnection ( 0, 0, 0 );
+
+		return res;
+	}
+
+auto stringInputFileHandler = registration::InputFileRegister ( "string", dummy3 );
+
+}
diff --git a/alib2str_cli_integration/src/OutputFileTypeRegistration.cpp b/alib2str_cli_integration/src/OutputFileTypeRegistration.cpp
new file mode 100644
index 0000000000..dbb841e4e9
--- /dev/null
+++ b/alib2str_cli_integration/src/OutputFileTypeRegistration.cpp
@@ -0,0 +1,32 @@
+#include <registration/OutputFileTypeRegistration.hpp>
+
+#include <exception/CommonException.h>
+
+#include <registry/StringWriterRegistry.hpp>
+
+#include <abstraction/PackingAbstraction.hpp>
+
+namespace {
+
+	std::shared_ptr < abstraction::OperationAbstraction > dummy3 ( const std::string & typehint ) {
+		ext::vector < std::shared_ptr < abstraction::OperationAbstraction > > abstractions;
+
+		abstractions.push_back ( abstraction::StringWriterRegistry::getAbstraction ( typehint ) );
+
+		ext::vector < std::string > templateParams;
+		ext::vector < std::string > paramTypes { ext::to_string < std::string > ( ), ext::to_string < std::string > ( ) };
+		abstraction::AlgorithmCategories::AlgorithmCategory category = abstraction::AlgorithmCategories::AlgorithmCategory::NONE;
+
+		abstractions.push_back ( abstraction::Registry::getAlgorithmAbstraction ( "cli::builtin::WriteFile", templateParams, paramTypes, category ) );
+
+		std::shared_ptr < abstraction::PackingAbstraction < 2 > > res = std::make_shared < abstraction::PackingAbstraction < 2 > > ( std::move ( abstractions ), 1 );
+		res->setInnerConnection ( 0, 1, 1, true );
+		res->setOuterConnection ( 0, 1, 0 ); // filename
+		res->setOuterConnection ( 1, 0, 0 ); // data
+
+		return res;
+	}
+
+auto stringOutputFileHandler = registration::OutputFileRegister ( "string", dummy3 );
+
+}
diff --git a/alib2str_cli_integration/test-src/main.cpp b/alib2str_cli_integration/test-src/main.cpp
new file mode 100644
index 0000000000..fd442ebd12
--- /dev/null
+++ b/alib2str_cli_integration/test-src/main.cpp
@@ -0,0 +1,164 @@
+#include <tclap/CmdLine.h>
+
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/XmlOutputter.h>
+
+#include <cppunit/Test.h>
+#include <cppunit/TestFailure.h>
+#include <cppunit/portability/Stream.h>
+#include <cppunit/TestListener.h>
+#include <cppunit/SourceLine.h>
+#include <cppunit/Exception.h>
+
+#include <exception/CommonException.h>
+
+CPPUNIT_NS_BEGIN
+
+class CPPUNIT_API TestProgressListener : public TestListener
+{
+public:
+	TestProgressListener();
+
+	virtual ~TestProgressListener();
+
+	void startTest( Test *test );
+
+	void addFailure( const TestFailure &failure );
+
+	void endTest( Test *test );
+
+	int getResult() const;
+
+	void printResults() const;
+
+private:
+	TestProgressListener( const TestProgressListener &copy );
+
+	void operator =( const TestProgressListener &copy );
+
+private:
+	int m_Failures;
+	int m_Tests;
+	int m_Assertions;
+	bool m_lastTestFailed;
+};
+
+TestProgressListener::TestProgressListener() : m_Failures( 0 ), m_Tests(0), m_Assertions(0), m_lastTestFailed( false )
+{
+}
+
+TestProgressListener::~TestProgressListener()
+{
+}
+
+void TestProgressListener::startTest( Test * test )
+{
+	stdCOut() << test->getName() << ":" << "\n";
+	stdCOut().flush();
+
+	m_lastTestFailed = false;
+	m_Tests++;
+}
+
+void TestProgressListener::addFailure( const TestFailure &failure )
+{
+	stdCOut() << (failure.isError() ? "error" : "assertion") << " : " << failure.failedTestName() << " : " << failure.sourceLine().lineNumber() << "\n";
+	stdCOut() << "Exception " << failure.thrownException()->message().details();
+
+	m_lastTestFailed = true;
+	if(failure.isError()) m_Failures++; else m_Assertions++;
+}
+
+void TestProgressListener::endTest( Test * test)
+{
+	stdCOut() << "Result (" << test->getName() << ")";
+	stdCOut().flush();
+
+	if ( !m_lastTestFailed )
+		stdCOut() <<	" : OK";
+	else
+		stdCOut() << " : Fail";
+	stdCOut() << "\n\n";
+}
+
+int TestProgressListener::getResult() const {
+	return m_Failures + m_Assertions;
+}
+
+void TestProgressListener::printResults() const {
+	stdCOut() << "Overal result: Tests: " << m_Tests << " Assertions: " << m_Assertions << " Failures: " << m_Failures << "\n";
+}
+
+CPPUNIT_NS_END
+
+int main(int argc, char* argv[]) {
+	try {
+		TCLAP::CmdLine cmd("Main test binary.", ' ', "0.01");
+
+		TCLAP::MultiArg<std::string> testPathSegments("p", "path", "test path", false, "string" );
+		cmd.add( testPathSegments );
+
+		cmd.parse(argc, argv);
+
+		CppUnit::TestResult controller;
+
+		CppUnit::TestResultCollector result;
+		controller.addListener( &result );
+
+		CppUnit::TestProgressListener progressListener;
+		controller.addListener( &progressListener );
+
+		CppUnit::Test *suite = NULL;
+		std::string testPath = "";
+		if(testPathSegments.getValue().size() == 0) {
+			// Get the top level suite from the registry
+			suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
+		} else if(testPathSegments.getValue().size() == 1) {
+			suite = CppUnit::TestFactoryRegistry::getRegistry(testPathSegments.getValue()[0]).makeTest();
+		} else {
+			suite = CppUnit::TestFactoryRegistry::getRegistry(testPathSegments.getValue()[0]).makeTest();
+			bool first = true;
+			for(const std::string& path : testPathSegments.getValue()) {
+				if(first) {
+					first = false;
+					continue;
+				}
+				testPath += path + "/";
+			}
+			testPath.pop_back();
+		}
+
+		// Adds the test to the list of test to run
+		CppUnit::TextUi::TestRunner runner;
+		runner.addTest( suite );
+
+		// Change the default outputter to a compiler error format outputter
+		runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(), std::cerr ) );
+		// Run the tests.
+		runner.run( controller, testPath );
+
+		progressListener.printResults();
+
+		std::ofstream xmlFileResults("CppUnitTestResults.xml");
+		CppUnit::XmlOutputter xmlOut(&result, xmlFileResults);
+		xmlOut.write();
+
+		return progressListener.getResult();
+	} catch(const exception::CommonException& exception) {
+		std::cerr << exception.getCause() << std::endl;
+		return 1;
+	} catch(const TCLAP::ArgException& exception) {
+		std::cerr << exception.error() << std::endl;
+		return 2;
+	} catch (const std::exception& exception) {
+		std::cerr << "Exception caught: " << exception.what() << std::endl;
+		return 3;
+	} catch(...) {
+		std::cerr << "Unknown exception caught." << std::endl;
+		return 127;
+	}
+}
diff --git a/aql2/makefile.conf b/aql2/makefile.conf
index c2f3d9f2a5..a68ce5463e 100644
--- a/aql2/makefile.conf
+++ b/aql2/makefile.conf
@@ -1,4 +1,4 @@
 EXECUTABLE:=aql2
-LINK_LIBRARIES=alib2cli alib2elgo alib2algo alib2aux alib2raw alib2str alib2data alib2dummy alib2xml alib2common alib2abstraction alib2measure alib2std
+LINK_LIBRARIES=alib2elgo alib2algo alib2aux alib2raw_cli_integration alib2raw alib2str_cli_integration alib2str alib2data alib2dummy alib2cli alib2xml alib2common alib2abstraction alib2measure alib2std
 SYSTEM_LIBRARIES=xml2 readline
 SYSTEM_INCLUDE_PATHS=/usr/include/libxml2
diff --git a/makefile b/makefile
index b6911759d8..0a3f4e4a62 100644
--- a/makefile
+++ b/makefile
@@ -24,16 +24,18 @@ SUBDIRS_LIBS = alib2std \
 		alib2abstraction \
 		alib2common \
 		alib2xml \
+		alib2cli \
 		alib2dummy \
 		alib2data \
 		alib2data_experimental \
 		alib2str \
+		alib2str_cli_integration \
 		alib2raw \
+		alib2raw_cli_integration \
 		alib2aux \
 		alib2algo \
 		alib2algo_experimental \
 		alib2elgo \
-		alib2cli \
 
 SUBDIRS_BINS = aecho2 \
 		aarbology2 \
-- 
GitLab