/**
* @file tests/fileformat/coff_format_tests.cpp
* @brief Tests for the @c coff_format module.
* @copyright (c) 2019 Avast Software, licensed under the MIT license
*/

#include <string>

#include <gtest/gtest.h>

#include "retdec/fileformat/file_format/coff/coff_format.h"
#include "fileformat/fileformat_tests.h"

using namespace ::testing;
using namespace retdec::utils;

namespace retdec {
namespace fileformat {
namespace tests {

const std::vector<uint8_t> coffBytes =
{
	0x4c, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00,
	0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x2e, 0x74, 0x65, 0x78,
	0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xa8, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x60,
	0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00,
	0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
	0x40, 0x00, 0x30, 0xc0, 0x2e, 0x62, 0x73, 0x73, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x30, 0xc0, 0x2e, 0x72, 0x64, 0x61,
	0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x1c, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x30, 0x40,
	0x55, 0x89, 0xe5, 0x83, 0xec, 0x28, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x89,
	0x04, 0x24, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x45, 0x08, 0xdd, 0x1c,
	0x24, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x7d, 0xf6, 0x0f, 0xb7, 0x45,
	0xf6, 0xb4, 0x0c, 0x66, 0x89, 0x45, 0xf4, 0xd9, 0x6d, 0xf4, 0xdb, 0x5d,
	0xf0, 0xd9, 0x6d, 0xf6, 0x8b, 0x45, 0xf0, 0xc9, 0xc3, 0x55, 0x89, 0xe5,
	0x83, 0xec, 0x18, 0xa1, 0x04, 0x00, 0x00, 0x00, 0x89, 0x04, 0x24, 0xe8,
	0x00, 0x00, 0x00, 0x00, 0x8b, 0x45, 0x08, 0x01, 0xc0, 0xc9, 0xc3, 0x55,
	0x89, 0xe5, 0x53, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0xe8, 0x00, 0x00,
	0x00, 0x00, 0xc7, 0x04, 0x24, 0x08, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00,
	0x00, 0x00, 0xc7, 0x04, 0x24, 0x05, 0x00, 0x00, 0x00, 0xe8, 0xbf, 0xff,
	0xff, 0xff, 0x89, 0xc3, 0xc7, 0x04, 0x24, 0x05, 0x00, 0x00, 0x00, 0xe8,
	0x78, 0xff, 0xff, 0xff, 0x89, 0x5c, 0x24, 0x08, 0x89, 0x44, 0x24, 0x04,
	0xc7, 0x04, 0x24, 0x15, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00,
	0xb8, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x5d, 0xfc, 0xc9, 0xc3, 0x90, 0x90,
	0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6f, 0x00,
	0x62, 0x61, 0x72, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f,
	0x72, 0x6c, 0x64, 0x21, 0x00, 0x25, 0x64, 0x20, 0x25, 0x64, 0x0a, 0x00,
	0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x00,
	0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x14, 0x00, 0x1a, 0x00, 0x00, 0x00,
	0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00,
	0x00, 0x00, 0x06, 0x00, 0x48, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
	0x14, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00,
	0x65, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6a, 0x00,
	0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x14, 0x00, 0x93, 0x00, 0x00, 0x00,
	0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x98, 0x00, 0x00, 0x00, 0x13, 0x00,
	0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
	0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00,
	0x2e, 0x66, 0x69, 0x6c, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xfe, 0xff, 0x00, 0x00, 0x67, 0x01, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
	0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x5f, 0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x01, 0x00, 0x20, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x5f, 0x62, 0x61, 0x72, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,
	0x01, 0x00, 0x20, 0x00, 0x02, 0x00, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x00,
	0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00,
	0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x01, 0x00, 0x00, 0x00, 0x03, 0x01, 0xa6, 0x00, 0x00, 0x00, 0x0a, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x02, 0x00, 0x00, 0x00, 0x03, 0x01, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x2e, 0x62, 0x73, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x03, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x2e, 0x72, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x04, 0x00, 0x00, 0x00, 0x03, 0x01, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x5f, 0x73, 0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5f, 0x73, 0x62, 0x61, 0x72, 0x00,
	0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
	0x5f, 0x5f, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x20, 0x00, 0x02, 0x00, 0x5f, 0x70, 0x75, 0x74, 0x73, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x00,
	0x5f, 0x73, 0x71, 0x72, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x20, 0x00, 0x02, 0x00, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74,
	0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x00,
	0x04, 0x00, 0x00, 0x00
};

/**
 * Tests for the @c coff_format module - using istream constructor.
 */
class CoffFormatTests_istream : public Test
{
	private:
		std::stringstream coffStringStream;
	protected:
		std::unique_ptr<CoffFormat> parser;
	public:
		CoffFormatTests_istream()
		{
			coffStringStream << std::string(
					coffBytes.begin(),
					coffBytes.end());
			parser = std::make_unique<CoffFormat>(coffStringStream);
		}
};

TEST_F(CoffFormatTests_istream, CorrectParsing)
{
	EXPECT_EQ(true, parser->isInValidState());
	EXPECT_EQ(4, parser->getNumberOfSections());
	EXPECT_EQ(0, parser->getNumberOfSegments());
}

TEST_F(CoffFormatTests_istream, DataInterpretationDefault)
{
	std::uint64_t res = 0;
	EXPECT_EQ(true, parser->get1ByteOffset(0xb4, res));
	EXPECT_EQ(0x55, res);
	EXPECT_EQ(true, parser->get2ByteOffset(0xb4, res));
	EXPECT_EQ(0x8955, res);
	EXPECT_EQ(true, parser->get4ByteOffset(0xb4, res));
	EXPECT_EQ(0x83e58955, res);
	EXPECT_EQ(true, parser->get8ByteOffset(0xb4, res));
	EXPECT_EQ(0x00a128ec83e58955, res);
}

TEST_F(CoffFormatTests_istream, DataInterpretationBig)
{
	std::uint64_t res = 0;
	EXPECT_EQ(true, parser->get1ByteOffset(0xb4, res, Endianness::BIG));
	EXPECT_EQ(0x55, res);
	EXPECT_EQ(true, parser->get2ByteOffset(0xb4, res, Endianness::BIG));
	EXPECT_EQ(0x5589, res);
	EXPECT_EQ(true, parser->get4ByteOffset(0xb4, res, Endianness::BIG));
	EXPECT_EQ(0x5589e583, res);
	EXPECT_EQ(true, parser->get8ByteOffset(0xb4, res, Endianness::BIG));
	EXPECT_EQ(0x5589e583ec28a100, res);
}

/**
 * Tests for the @c coff_format module - using istream constructor.
 */
class CoffFormatTests_data : public Test
{
	protected:
		std::unique_ptr<CoffFormat> parser;
	public:
		CoffFormatTests_data()
		{
			parser = std::make_unique<CoffFormat>(
					coffBytes.data(),
					coffBytes.size());
		}
};

TEST_F(CoffFormatTests_data, CorrectParsing)
{
	EXPECT_EQ(true, parser->isInValidState());
	EXPECT_EQ(4, parser->getNumberOfSections());
	EXPECT_EQ(0, parser->getNumberOfSegments());
}

TEST_F(CoffFormatTests_data, DataInterpretationDefault)
{
	std::uint64_t res = 0;
	EXPECT_EQ(true, parser->get1ByteOffset(0xb4, res));
	EXPECT_EQ(0x55, res);
	EXPECT_EQ(true, parser->get2ByteOffset(0xb4, res));
	EXPECT_EQ(0x8955, res);
	EXPECT_EQ(true, parser->get4ByteOffset(0xb4, res));
	EXPECT_EQ(0x83e58955, res);
	EXPECT_EQ(true, parser->get8ByteOffset(0xb4, res));
	EXPECT_EQ(0x00a128ec83e58955, res);
}

} // namespace tests
} // namespace fileformat
} // namespace retdec
