/*******************************************************************************
***  This file is part of Dux Rei Nummariae.                                 ***
***                                                                          ***
***  Copyright (C) 2017, 2018, 2019, 2020, 2021                              ***
***  John Schneiderman <Licensing _AT_ Schneiderman _DOT_ me>                ***
***                                                                          ***
***  This program is free software: you can redistribute it and/or modify it ***
***  under the terms of the GNU Affero General Public License as published   ***
***  by the Free Software Foundation, either version 3 of the License, or    ***
***  (at your option) any later version.                                     ***
***                                                                          ***
***  This program is distributed in the hope that it will be useful, but     ***
***  WITHOUT ANY WARRANTY; without even the implied warranty of              ***
***  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                    ***
***  See the GNU Affero General Public License for more details.             ***
***                                                                          ***
***  You should have received a copy of the GNU Affero General Public License***
***  along with this program. If not, see <http://www.gnu.org/licenses/>.    ***
*******************************************************************************/
#include <pecunia/Codes.h>
using pecunia::currency::allIso4217Codes;
using pecunia::currency::Iso4217Codes;
using pecunia::currency::toStdString;
#include <QDebug>
// using qDebug.
#include <QString>
using ::QString;
#include <QTest>
// using QTEST_MAIN

#include <cstddef>
using std::size_t;
#include <set>
using std::set;

#include <conversion/ConversionMap.h>
using drn::conversion::ConversionMap;
using drn::conversion::ConversionRatio;
#include <foundation/Error.h>
using drn::foundation::Error;


namespace drn
{
namespace conversion
{
namespace tests
{

struct ConversionMapUT : QObject
{
	Q_OBJECT

private slots:
	//{ constructor Tests

	void constructor_default_ShouldHaveUnknownCode()
	{
		const ConversionMap cm{};
		QCOMPARE(cm.size(), allIso4217Codes.size());
		QVERIFY2(cm.hasFrom(Iso4217Codes::XXX), "The unknown conversion should exist.");
		QCOMPARE(cm.at(Iso4217Codes::XXX).size(), allIso4217Codes.size());

		for (const auto& toCode : allIso4217Codes)
		{
			qDebug() << "Comparing conversion from XXX to"
					<< QString::fromStdString(toStdString(toCode));
			QCOMPARE(cm.at(Iso4217Codes::XXX).find(toCode)->ratio_, 1.0);
		}

		for (const auto& fromCode : allIso4217Codes)
		{
			qDebug() << "Comparing conversion identity of"
					<< QString::fromStdString(toStdString(fromCode));
			QCOMPARE(cm.at(fromCode).find(fromCode)->ratio_, 1.0);
		}
	}

	//}

	//{ setConversion

	void setConversion_ConversionDoesNotExist_ShouldBeAdded()
	{
		ConversionMap cm{};
		cm.setConversion(Iso4217Codes::USD, Iso4217Codes::PLN, 2.00);
		QVERIFY2(cm.hasFrom(Iso4217Codes::USD), "The USD conversion should exist.");
		QVERIFY2(
			cm.at(Iso4217Codes::USD).find(Iso4217Codes::PLN) != cm.at(Iso4217Codes::USD).cend(),
				 "Present values should be found."
		);
		QCOMPARE(cm.at(Iso4217Codes::USD).find(Iso4217Codes::PLN)->convertTo_, Iso4217Codes::PLN);
		QCOMPARE(cm.at(Iso4217Codes::USD).find(Iso4217Codes::PLN)->ratio_ , 2.00);
	}
	void setConversion_MultipleConversionDoesNotExist_ShouldBeAdded()
	{
		ConversionMap cm{};
		cm.setConversion(Iso4217Codes::USD, Iso4217Codes::PLN, 2.00);
		cm.setConversion(Iso4217Codes::USD, Iso4217Codes::EUR, 1.05);
		QVERIFY2(cm.hasFrom(Iso4217Codes::USD), "The USD conversion should exist.");
		QVERIFY2(
			cm.at(Iso4217Codes::USD).find(Iso4217Codes::PLN) != cm.at(Iso4217Codes::USD).cend(),
				 "Present values should be found."
		);
		QVERIFY2(
			cm.at(Iso4217Codes::USD).find(Iso4217Codes::EUR) != cm.at(Iso4217Codes::USD).cend(),
				 "Present values should be found."
		);
		QCOMPARE(cm.at(Iso4217Codes::USD).find(Iso4217Codes::PLN)->convertTo_, Iso4217Codes::PLN);
		QCOMPARE(cm.at(Iso4217Codes::USD).find(Iso4217Codes::PLN)->ratio_ , 2.00);
		QCOMPARE(cm.at(Iso4217Codes::USD).find(Iso4217Codes::EUR)->convertTo_, Iso4217Codes::EUR);
		QCOMPARE(cm.at(Iso4217Codes::USD).find(Iso4217Codes::EUR)->ratio_ , 1.05);
	}
	void setConversion_ConversionAlreadyExists_ShouldUpdate()
	{
		ConversionMap cm{};
		cm.setConversion(Iso4217Codes::USD, Iso4217Codes::PLN, 2.00);
		QVERIFY2(cm.hasFrom(Iso4217Codes::USD), "The USD conversion should exist.");
		cm.setConversion(Iso4217Codes::USD, Iso4217Codes::PLN, 3.15);
		QCOMPARE(cm.at(Iso4217Codes::USD).find(Iso4217Codes::PLN)->ratio_ , 3.15);
	}
	void setConversion_NonIdentityForCurrency_ShouldThrow()
	{
		ConversionMap cm{};
		QVERIFY_EXCEPTION_THROWN(cm.setConversion(Iso4217Codes::PLN, Iso4217Codes::PLN, 2.00), Error);
	}

	//}

	//{ hasConversion

	void hasConversion_FromDoesExistsToDoesExists_ShouldBeTrue()
	{
		ConversionMap cm{};
		cm.setConversion(Iso4217Codes::USD, Iso4217Codes::PLN, 1.00);
		QVERIFY2(cm.hasConversion(Iso4217Codes::USD, Iso4217Codes::PLN), "Present values should be found.");
	}
	void hasConversion_FromDoesNotExistsToDoesExists_ShouldBeFalse()
	{
		ConversionMap cm{};
		cm.setConversion(Iso4217Codes::PLN, Iso4217Codes::PLN, 1.00);
		QVERIFY2( ! cm.hasConversion(Iso4217Codes::USD, Iso4217Codes::PLN), "Should not be found.");
	}
	void hasConversion_FromDoesExistsToDoesNotExists_ShouldBeFalse()
	{
		ConversionMap cm{};
		cm.setConversion(Iso4217Codes::USD, Iso4217Codes::USD, 1.00);
		QVERIFY2( ! cm.hasConversion(Iso4217Codes::USD, Iso4217Codes::PLN), "Should not be found.");
	}

	//}
};

}}}

QTEST_MAIN(drn::conversion::tests::ConversionMapUT)
#include "ConversionMap-unit-tests.moc"
