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

#include <string>

#include <gtest/gtest.h>

#include "retdec/fileformat/file_format/pe/pe_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> peBytes =
{
	0x4d, 0x5a, 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, 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,
	0x40, 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x4c, 0x01, 0x01, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xe0, 0x00, 0x02, 0x01, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
	0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x20, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xa0, 0x10, 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, 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, 0x60, 0x11, 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, 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, 0x10, 0x00, 0x00,
	0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0xa0, 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,
	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, 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, 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,
	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, 0xc7, 0x05, 0x38, 0x10,
	0x40, 0x00, 0x5d, 0x10, 0x40, 0x00, 0x68, 0x6f, 0x10, 0x40, 0x00, 0xe8,
	0x1c, 0x00, 0x00, 0x00, 0x83, 0xc4, 0x04, 0x6a, 0x00, 0xff, 0x15, 0x20,
	0x11, 0x40, 0x00, 0xcc, 0xff, 0x35, 0x38, 0x10, 0x40, 0x00, 0xe8, 0x05,
	0x00, 0x00, 0x00, 0x83, 0xc4, 0x04, 0xc3, 0xcc, 0xff, 0x25, 0x28, 0x11,
	0x40, 0x00, 0xcc, 0xcc, 0x3c, 0x10, 0x40, 0x00, 0x20, 0x2a, 0x20, 0x73,
	0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x54, 0x4c, 0x53, 0x3a, 0x0a, 0x20,
	0x20, 0x23, 0x20, 0x31, 0x73, 0x74, 0x20, 0x54, 0x4c, 0x53, 0x20, 0x63,
	0x61, 0x6c, 0x6c, 0x0a, 0x00, 0x20, 0x20, 0x23, 0x20, 0x32, 0x6e, 0x64,
	0x20, 0x54, 0x4c, 0x53, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x0a, 0x00, 0x20,
	0x20, 0x23, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, 0x6e,
	0x74, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x0a, 0x20,
	0x20, 0x23, 0x20, 0x45, 0x78, 0x69, 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65,
	0x73, 0x73, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x0a, 0x00, 0x00,
	0xe0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x40, 0x11, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0xe8, 0x10, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x11, 0x00, 0x00,
	0x28, 0x11, 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, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x0e, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x45, 0x78, 0x69, 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73,
	0x73, 0x00, 0x00, 0x00, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x0e, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x33, 0x32,
	0x2e, 0x64, 0x6c, 0x6c, 0x00, 0x6d, 0x73, 0x76, 0x63, 0x72, 0x74, 0x2e,
	0x64, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x40, 0x00,
	0x84, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x23, 0x01, 0x00,
	0x20, 0x10, 0x40, 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, 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, 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, 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
};

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

TEST_F(PeFormatTests_istream, CorrectParsing)
{
	EXPECT_EQ(true, parser->isInValidState());
	EXPECT_EQ(0, parser->getNumberOfSegments());
	ASSERT_EQ(1, parser->getNumberOfSections());
	EXPECT_EQ(0x401000, parser->getSection(0)->getAddress());
	EXPECT_EQ(0x200, parser->getSection(0)->getOffset());
	unsigned long long memsize = 0;
	EXPECT_EQ(true, parser->getSection(0)->getSizeInMemory(memsize));
	EXPECT_EQ(0x1000, memsize);
}

TEST_F(PeFormatTests_istream, DataInterpretationDefault)
{
	std::uint64_t res;
	EXPECT_EQ(true, parser->get1Byte(0x401000, res));
	EXPECT_EQ(0xc7, res);
	EXPECT_EQ(true, parser->get2Byte(0x401000, res));
	EXPECT_EQ(0x05c7, res);
	EXPECT_EQ(true, parser->get4Byte(0x401000, res));
	EXPECT_EQ(0x103805c7, res);
	EXPECT_EQ(true, parser->get8Byte(0x401000, res));
	EXPECT_EQ(0x105d0040103805c7, res);
}

TEST_F(PeFormatTests_istream, DataInterpretationDefaultBig)
{
	std::uint64_t res;
	EXPECT_EQ(true, parser->get1Byte(0x401000, res, Endianness::BIG));
	EXPECT_EQ(0xc7, res);
	EXPECT_EQ(true, parser->get2Byte(0x401000, res, Endianness::BIG));
	EXPECT_EQ(0xc705, res);
	EXPECT_EQ(true, parser->get4Byte(0x401000, res, Endianness::BIG));
	EXPECT_EQ(0xc7053810, res);
	EXPECT_EQ(true, parser->get8Byte(0x401000, res, Endianness::BIG));
	EXPECT_EQ(0xc705381040005d10, res);
}

/**
 * Tests for the @c coff_format module - using istream constructor.
 */
class PeFormatTests_data : public Test
{
	private:
		std::stringstream coffStringStream;
	protected:
		std::unique_ptr<PeFormat> parser;
	public:
		PeFormatTests_data()
		{
			parser = std::make_unique<PeFormat>(peBytes.data(), peBytes.size());
		}
};

TEST_F(PeFormatTests_data, CorrectParsing)
{
	EXPECT_EQ(true, parser->isInValidState());
	EXPECT_EQ(0, parser->getNumberOfSegments());
	ASSERT_EQ(1, parser->getNumberOfSections());
	EXPECT_EQ(0x401000, parser->getSection(0)->getAddress());
	EXPECT_EQ(0x200, parser->getSection(0)->getOffset());
	unsigned long long memsize = 0;
	EXPECT_EQ(true, parser->getSection(0)->getSizeInMemory(memsize));
	EXPECT_EQ(0x1000, memsize);
}

TEST_F(PeFormatTests_data, DataInterpretationDefault)
{
	std::uint64_t res;
	EXPECT_EQ(true, parser->get1Byte(0x401000, res));
	EXPECT_EQ(0xc7, res);
	EXPECT_EQ(true, parser->get2Byte(0x401000, res));
	EXPECT_EQ(0x05c7, res);
	EXPECT_EQ(true, parser->get4Byte(0x401000, res));
	EXPECT_EQ(0x103805c7, res);
	EXPECT_EQ(true, parser->get8Byte(0x401000, res));
	EXPECT_EQ(0x105d0040103805c7, res);
}

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