/*******************************************************************************
***  This file is part of Pecunia.                                           ***
***                                                                          ***
***  Copyright (C) 2017, 2018, 2019, 2020, 2021, 2023                        ***
***  John Schneiderman <Licencing _AT_ Schneiderman _DOT_ me>                ***
***                                                                          ***
***  This program is free software: you can redistribute it and/or modify it ***
***  under the terms of the GNU Lesser 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 Lesser General Public License for more details.             ***
***                                                                          ***
***  You should have received a copy of the GNU Lesser General Public License***
***  along with this program. If not, see <http://www.gnu.org/licenses/>.    ***
*******************************************************************************/
#include <QObject>
using ::QObject;
// using Q_OBJECT
#include <QTest>
// using QTEST_MAIN
// using QVERIFY_EXCEPTION_THROWN

#include <pecunia/FloatingPoint.h>
using namespace pecunia::literals;
using pecunia::FloatingPoint;

namespace pecunia
{
namespace tests
{

struct FloatingPointUT : QObject
{
	Q_OBJECT

private slots:
	//{ constructor Tests

	void constructor_default_ShouldBeDefaults()
	{
		const FloatingPoint fp{};
		QCOMPARE(fp.underlying(), static_cast<FloatingPointBase>(0.0));
	}

	void constructor_fullInit_ShouldBeValues()
	{
		const FloatingPoint fp{1.23};
		QCOMPARE(fp.underlying(), static_cast<FloatingPointBase>(1.23));
		QCOMPARE(fp.underlying(), 1.23_fp .underlying());
	}

	//}

	//{ equality operator

	void equality_withinPrecision_ShouldBeTrue()
	{
		const FloatingPoint fp{1.0 + 1.0 / 3.0};
		QVERIFY2(fp.isEqual(1.33, 0), "Inside the precision whole number range should be equal.");
		QVERIFY2(fp.isEqual(1.33, 1), "Inside the precision ones range should be equal.");
		QVERIFY2(fp.isEqual(1.33, 2), "Inside the precision tenths range should be equal.");
	}

	void equality_atPrecision_ShouldBeTrue()
	{
		const FloatingPoint fp0{1.0 + 999.0 / 1000.0};
		QVERIFY2(fp0.isEqual(1.99, 2), "At the precision range near next whole should be equal.");
		const FloatingPoint fp1{0.75 + 0.25};
		QVERIFY2(fp1.isEqual(1.0, 2), "At the precision range at one should be equal.");
		const FloatingPoint fp2{1.33 - (1.0 + 1.0 / 3.0)};
		QVERIFY2(fp2.isEqual(0.0, 2), "At the precision range at zero should be equal.");
		const FloatingPoint fp3{1.23};
		QVERIFY2(fp3.isEqual(1.23, 2), "At the precision range same number should be equal.");
	}

	void equality_outsidePrecision_ShouldBeFalse()
	{
		const FloatingPoint fp{1.0 + 1.0 / 3.0};
		QVERIFY2( ! fp.isEqual(1.33, 3), "Outside the precision range should not be equal.");
	}

	//}

	//{ decompose

	void decompose_validValue_ShouldSplit()
	{
		const FloatingPoint fp{1.23};
		const auto digits{2};
		const auto fpp{fp.decompose(digits)};
		QVERIFY2(fpp.whole_.isEqual(1, digits), "The whole number should be one.");
		QVERIFY2(fpp.decimal_.isEqual(0.23, digits), "The decimal number should be 23 hundredths.");
	}

	//}

	//{ reciprocal

	void reciprocal_1p25_ShouldBe0p80()
	{
		const FloatingPoint fp{1.25};
		QVERIFY2(fp.reciprocal().isEqual(0.8, 2), "The reciprocal of 1.25 should be 0.8.");
	}

	void reciprocal_backAndForth_ShouldBeOriginal()
	{
		const FloatingPoint fp{1.25};
		QVERIFY2(
			fp.reciprocal().reciprocal().isEqual(fp, 2),
			"The reciprocal of a reciprocal should be the original value."
		);
	}

	//}
};

}}

QTEST_MAIN(pecunia::tests::FloatingPointUT)
#include "FloatingPoint-unit-tests.moc"
