/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2022, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

#include <gtest/gtest.h>
#include <mrpt/config.h>
#include <mrpt/core/bit_cast.h>
#include <mrpt/core/reverse_bytes.h>

// Load data from constant file and check for exact match.
TEST(bits, reverseBytes)
{
	{
		uint8_t val = 0x88, val_r;
		const uint8_t val_r_ok = 0x88;

		mrpt::reverseBytes(val, val_r);
		EXPECT_EQ(val_r, val_r_ok);
		mrpt::reverseBytesInPlace(val);
		EXPECT_EQ(val, val_r_ok);
	}
	{
		int8_t val = 0x66, val_r;
		const int8_t val_r_ok = 0x66;

		mrpt::reverseBytes(val, val_r);
		EXPECT_EQ(val_r, val_r_ok);
		mrpt::reverseBytesInPlace(val);
		EXPECT_EQ(val, val_r_ok);
	}
	{
		uint16_t val = 0x1122, val_r;
		const uint16_t val_r_ok = 0x2211;

		mrpt::reverseBytes(val, val_r);
		EXPECT_EQ(val_r, val_r_ok);
		mrpt::reverseBytesInPlace(val);
		EXPECT_EQ(val, val_r_ok);
	}
	{
		int16_t val = 0x1122, val_r;
		const int16_t val_r_ok = 0x2211;

		mrpt::reverseBytes(val, val_r);
		EXPECT_EQ(val_r, val_r_ok);
		mrpt::reverseBytesInPlace(val);
		EXPECT_EQ(val, val_r_ok);
	}
	{
		uint32_t val = UINT32_C(0x11223344), val_r;
		const uint32_t val_r_ok = UINT32_C(0x44332211);

		mrpt::reverseBytes(val, val_r);
		EXPECT_EQ(val_r, val_r_ok);
		mrpt::reverseBytesInPlace(val);
		EXPECT_EQ(val, val_r_ok);
	}
	{
		int32_t val = INT32_C(0x11223344), val_r;
		const int32_t val_r_ok = INT32_C(0x44332211);

		mrpt::reverseBytes(val, val_r);
		EXPECT_EQ(val_r, val_r_ok);
		mrpt::reverseBytesInPlace(val);
		EXPECT_EQ(val, val_r_ok);
	}
	{
		uint64_t val = UINT64_C(0x1122334455667788), val_r;
		const uint64_t val_r_ok = UINT64_C(0x8877665544332211);

		mrpt::reverseBytes(val, val_r);
		EXPECT_EQ(val_r, val_r_ok);
		mrpt::reverseBytesInPlace(val);
		EXPECT_EQ(val, val_r_ok);
	}
	{
		int64_t val = INT64_C(0x1122334455667766), val_r;
		const int64_t val_r_ok = INT64_C(0x6677665544332211);

		mrpt::reverseBytes(val, val_r);
		EXPECT_EQ(val_r, val_r_ok);
		mrpt::reverseBytesInPlace(val);
		EXPECT_EQ(val, val_r_ok);
	}
	{
		bool valTrue = true;
		bool valFalse = false;
		mrpt::reverseBytesInPlace(valTrue);
		mrpt::reverseBytesInPlace(valFalse);
		EXPECT_TRUE(valTrue);
		EXPECT_FALSE(valFalse);
	}
	{
		uint8_t val = UINT8_C(0xc1);

		mrpt::reverseBytesInPlace(val);
		EXPECT_EQ(val, 0xc1);
	}
	{
		// 1.0 == 0x3F800000
		float val = 1;
		const uint32_t val_r_ok = UINT32_C(0x803f);

		mrpt::reverseBytesInPlace(val);
		auto val_check = bit_cast<uint32_t>(val);
		EXPECT_EQ(val_check, val_r_ok);
	}
	{
		// 1.0 == 0x3ff0000000000000
		double val = 1;
		const uint64_t val_r_ok = UINT32_C(0xf03f);

		mrpt::reverseBytesInPlace(val);
		auto val_check = bit_cast<uint64_t>(val);
		EXPECT_EQ(val_check, val_r_ok);
	}
	{
		std::chrono::time_point<mrpt::Clock> t = mrpt::Clock::now();
		const auto t_org = t;
		mrpt::reverseBytesInPlace(t);
		EXPECT_NE(t, t_org);
		mrpt::reverseBytesInPlace(t);
		EXPECT_EQ(t, t_org);
	}
}
