// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#define CATCH_CONFIG_RUNNER
#include <catch.hpp>
#include <reporters/catch_reporter_compact.hpp>
#include <QFile>

int (*TestForkedMethod)()/* = nullptr*/;

namespace base {
namespace assertion {

// For Assert() / Expects() / Ensures() / Unexpected() to work.
void log(const char *message, const char *file, int line) {
	std::cout << message << " (" << file << ":" << line << ")" << std::endl;
}

} // namespace assertion
} // namespace base

namespace Catch {

struct MinimalReporter : CompactReporter {
	MinimalReporter( ReporterConfig const& _config )
	: CompactReporter( _config )
	{}

	virtual void testRunEnded( TestRunStats const& _testRunStats ) {
		printTotals( _testRunStats.totals );
	}

private:
	// Colour, message variants:
	// - white: No tests ran.
	// -   red: Failed [both/all] N test cases, failed [both/all] M assertions.
	// - white: Passed [both/all] N test cases (no assertions).
	// -   red: Failed N tests cases, failed M assertions.
	// - green: Passed [both/all] N tests cases with M assertions.

	std::string bothOrAll( std::size_t count ) const {
		return count == 1 ? std::string() : count == 2 ? "both " : "all " ;
	}

	void printTotals( const Totals& totals ) const {
		if( totals.testCases.total() == 0 ) {
		}
		else if( totals.testCases.failed == totals.testCases.total() ) {
			Colour colour( Colour::ResultError );
			const std::string qualify_assertions_failed =
				totals.assertions.failed == totals.assertions.total() ?
					bothOrAll( totals.assertions.failed ) : std::string();
			stream <<
				"Failed " << bothOrAll( totals.testCases.failed )
							<< pluralise( totals.testCases.failed, "test case"  ) << ", "
				"failed " << qualify_assertions_failed <<
								pluralise( totals.assertions.failed, "assertion" ) << '.';
		}
		else if( totals.assertions.total() == 0 ) {
			stream <<
				"Passed " << bothOrAll( totals.testCases.total() )
							<< pluralise( totals.testCases.total(), "test case" )
							<< " (no assertions).";
		}
		else if( totals.assertions.failed ) {
			Colour colour( Colour::ResultError );
			stream <<
				"Failed " << pluralise( totals.testCases.failed, "test case"  ) << ", "
				"failed " << pluralise( totals.assertions.failed, "assertion" ) << '.';
		}
		else {
		}
	}
};

INTERNAL_CATCH_REGISTER_REPORTER( "minimal", MinimalReporter )

} // namespace Catch

int main(int argc, const char *argv[]) {
	auto touchFile = QString();
	for (auto i = 0; i != argc; ++i) {
		if (argv[i] == QString("--touch") && i + 1 != argc) {
			touchFile = QFile::decodeName(argv[++i]);
		} else if (argv[i] == QString("--forked") && TestForkedMethod) {
			return TestForkedMethod();
		}
	}
	const char *catch_argv[] = {
		argv[0],
		touchFile.isEmpty() ? "-b" : "-r",
		touchFile.isEmpty() ? "-b" : "minimal" };
	constexpr auto catch_argc = sizeof(catch_argv) / sizeof(catch_argv[0]);
	auto result = Catch::Session().run(catch_argc, catch_argv);
	if (result == 0 && !touchFile.isEmpty()) {
		QFile(touchFile).open(QIODevice::WriteOnly);
	}
	return (result < 0xff ? result : 0xff);
}

