
namespace TheBoxSoftware.Reflection.Tests.Unit.Core.PE
{
    using NUnit.Framework;
    using Reflection.Core;
    using Reflection.Core.PE;

    [TestFixture]
    public class PEHeaderTests
    {
        [Test]
        public void PEHeader_When64Bit_OffsetIsMovedOn()
        {
            byte[] contents = new byte[112];
            Offset offset = 0;

            // set it to a 64 magic
            contents[0] = 0x0b;
            contents[1] = 0x02;

            PEHeader header = new PEHeader(contents, offset);

            Assert.AreEqual(FileMagicNumbers.Bit64, header.Magic);
            Assert.AreEqual(112, header.Size);
        }

        [Test]
        public void PEHeader_When32Bit_OffsetIsMovedOn()
        {
            byte[] contents = new byte[96];
            Offset offset = 0;

            // set it to a 32 magic
            contents[0] = 0x0b;
            contents[1] = 0x01;

            PEHeader header = new PEHeader(contents, offset);

            Assert.AreEqual(FileMagicNumbers.Bit32, header.Magic);
            Assert.AreEqual(96, header.Size);
        }

        [Test]
        public void PEHeader_When64Bit_FieldsAreReadCorrectly()
        {
            Offset offset = 0;
            byte[] contents = new byte[] {
                0x0B, 0x02,
                0x0B,
                0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x02, 0xA0, 0x44, 0x06, 0x00, 0x00,
                0x00, 0x10, 0x00, 0x00,
                0x00, 0x02, 0x00, 0x00,
                0x05, 0x00,
                0x02, 0x00,
                0x00, 0x00,
                0x00, 0x00,
                0x05, 0x00,
                0x02, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x30, 0x00, 0x00,
                0x00, 0x02, 0x00, 0x00,
                0xAB, 0x57, 0x00, 0x00,
                0x03, 0x00,
                0x40, 0x81,
                0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 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,
                0x10, 0x00, 0x00, 0x00,
                // 16 directories
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
            };

            PEHeader header = new PEHeader(contents, offset);

            Assert.AreEqual(FileMagicNumbers.Bit64, header.Magic);
            Assert.AreEqual(0x0b, header.MajorLinkerVersion);
            Assert.AreEqual(0x00, header.MinorLinkerVersion);
            Assert.AreEqual(0x00000000, header.SizeOfCode);
            Assert.AreEqual(0x00000000, header.SizeOfInitializedData);
            Assert.AreEqual(0x00000000, header.SizeOfUnitializedData);
            Assert.AreEqual(0x00000000, header.AddressOfEntryPoint);
            Assert.AreEqual(0x00000000, header.BaseOfCode);
            Assert.AreEqual(0x00000644A0020000, header.ImageBase);
            Assert.AreEqual(0x00001000, header.SectionAlignment);
            Assert.AreEqual(0x00000200, header.FileAlignment);
            Assert.AreEqual(0x0005, header.MajorOperatingSystemVersion);
            Assert.AreEqual(0x0002, header.MinorOperatingSystemVersion);
            Assert.AreEqual(0x0, header.MajorImageVersion);
            Assert.AreEqual(0x0, header.MinorImageVersion);
            Assert.AreEqual(0x0005, header.MajorSubSystemVersion);
            Assert.AreEqual(0x0002, header.MinorSubSystemVersion);
            Assert.AreEqual(0x00000000, header.Win32VersionValue);
            Assert.AreEqual(0x00003000, header.SizeOfImage);
            Assert.AreEqual(0x00000200, header.SizeOfHeaders);
            Assert.AreEqual(0x000057ab, header.Checksum);
            Assert.AreEqual(0x0003, header.Subsystem);
            Assert.AreEqual(0x8140, header.DllCharacteristics);
            Assert.AreEqual(0x0000000000100000, header.SizeOfStackReserve);
            Assert.AreEqual(0x0000000000001000, header.SizeOfStackCommit);
            Assert.AreEqual(0x0000000000000000, header.SizeOfHeapReserve);
            Assert.AreEqual(0x0000000000000000, header.SizeOfHeapCommit);
            Assert.AreEqual(0x00000000, header.LoaderFlags);
            Assert.AreEqual(0x00000010, header.NumberOfRVAAndSizes);
        }

        [Test]
        public void PEHeader_When32Bit_FieldsAreReadCorrectly()
        {
            Offset offset = 0;
            byte[] contents = new byte[] {
                0x0B, 0x01,
                0x30,
                0x00,
                0x00, 0x4C, 0x00, 0x00,
                0x00, 0x08, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x7E, 0x6B, 0x00, 0x00,
                0x00, 0x20, 0x00, 0x00,
                0x00, 0x80, 0x00, 0x00,
                0x00, 0x00, 0x40, 0x00,
                0x00, 0x20, 0x00, 0x00,
                0x00, 0x02, 0x00, 0x00,
                0x04, 0x00,
                0x00, 0x00,
                0x00, 0x00,
                0x00, 0x00,
                0x04, 0x00,
                0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0xC0, 0x00, 0x00,
                0x00, 0x02, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x03, 0x00,
                0x40, 0x85,
                0x00, 0x00, 0x10, 0x00,
                0x00, 0x10, 0x00, 0x00,
                0x00, 0x00, 0x10, 0x00,
                0x00, 0x10, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x10, 0x00, 0x00, 0x00,
                // 16 directories
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
            };

            PEHeader header = new PEHeader(contents, offset);

            Assert.AreEqual(FileMagicNumbers.Bit32, header.Magic);
            Assert.AreEqual(0x30, header.MajorLinkerVersion);
            Assert.AreEqual(0x00, header.MinorLinkerVersion);
            Assert.AreEqual(0x00004c00, header.SizeOfCode);
            Assert.AreEqual(0x00000800, header.SizeOfInitializedData);
            Assert.AreEqual(0x00000000, header.SizeOfUnitializedData);
            Assert.AreEqual(0x00006b7e, header.AddressOfEntryPoint);
            Assert.AreEqual(0x00002000, header.BaseOfCode);
            Assert.AreEqual(0x00008000, header.BaseOfData);
            Assert.AreEqual(0x00400000, header.ImageBase);
            Assert.AreEqual(0x00002000, header.SectionAlignment);
            Assert.AreEqual(0x00000200, header.FileAlignment);
            Assert.AreEqual(0x0004, header.MajorOperatingSystemVersion);
            Assert.AreEqual(0x0000, header.MinorOperatingSystemVersion);
            Assert.AreEqual(0x0, header.MajorImageVersion);
            Assert.AreEqual(0x0, header.MinorImageVersion);
            Assert.AreEqual(0x0004, header.MajorSubSystemVersion);
            Assert.AreEqual(0x0000, header.MinorSubSystemVersion);
            Assert.AreEqual(0x00000000, header.Win32VersionValue);
            Assert.AreEqual(0x0000c000, header.SizeOfImage);
            Assert.AreEqual(0x00000200, header.SizeOfHeaders);
            Assert.AreEqual(0x00000000, header.Checksum);
            Assert.AreEqual(0x0003, header.Subsystem);
            Assert.AreEqual(0x8540, header.DllCharacteristics);
            Assert.AreEqual(0x00100000, header.SizeOfStackReserve);
            Assert.AreEqual(0x00001000, header.SizeOfStackCommit);
            Assert.AreEqual(0x00100000, header.SizeOfHeapReserve);
            Assert.AreEqual(0x00001000, header.SizeOfHeapCommit);
            Assert.AreEqual(0x00000000, header.LoaderFlags);
            Assert.AreEqual(0x00000010, header.NumberOfRVAAndSizes);
        }
    }
}
