#include "tile/base/byte_order.h"

#include "gtest/gtest.h"
#ifdef __linux__
#include <arpa/inet.h>
#endif

namespace tile {

static union EndianHelper {
    uint16_t v16;
    uint32_t v32;
    uint32_t v64;
    uint8_t bytes[8];
} endian_helper = {
    .bytes = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}
};

TEST(ByteOrder, ByteSwap16)
{
    const uint16_t val      = 0x1234;
    const uint16_t expected = 0x3412;
    ASSERT_EQ(expected, ByteSwap16(val));
}

TEST(ByteOrder, ByteSwap32)
{
    const uint32_t val      = 0x12345678;
    const uint32_t expected = 0x78563412;
    ASSERT_EQ(expected, ByteSwap32(val));
}

TEST(ByteOrder, ByteSwap64)
{
    const uint64_t val      = 0x1234567890abcdef;
    const uint64_t expected = 0xefcdab9078563412;
    ASSERT_EQ(expected, ByteSwap64(val));
}

TEST(ByteOrder, IsHostByteOrder)
{
    ASSERT_NE(IsHostBigEndian(), IsHostLittleEndian());
#if TILE_BYTE_ORDER == TILE_BIG_ENDIAN
    ASSERT_TRUE(IsHostBigEndian());
    ASSERT_FALSE(IsHostLittleEndian());
#else
    ASSERT_TRUE(IsHostLittleEndian());
    ASSERT_FALSE(IsHostBigEndian());
#endif
}

TEST(ByteOrder, HostToNetwork16)
{
    const uint16_t val = 0x1234;
#if TILE_BYTE_ORDER == TILE_BIG_ENDIAN
    const uint16_t expected = val;
#elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN
    const uint16_t expected = 0x3412;
#else
#error "Unsupported byte order"
#endif
    ASSERT_EQ(expected, HostToNetwork16(val));
}

TEST(ByteOrder, HostToNetwork32)
{
    const uint32_t val = 0x12345678;
#if TILE_BYTE_ORDER == TILE_BIG_ENDIAN
    const uint32_t expected = val;
#elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN
    const uint32_t expected = 0x78563412;
#else
#error "Unsupported byte order"
#endif
    ASSERT_EQ(expected, HostToNetwork32(val));
}

TEST(ByteOrder, HostToNetwork64)
{
    const uint64_t val = 0x1234567890abcdef;
#if TILE_BYTE_ORDER == TILE_BIG_ENDIAN
    const uint64_t expected = val;
#elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN
    const uint64_t expected = 0xefcdab9078563412;
#else
#error "Unsupported byte order"
#endif
    ASSERT_EQ(expected, HostToNetwork64(val));
}

TEST(ByteOrder, NetworkToHost16)
{
    const uint16_t val = 0x1234;
#if TILE_BYTE_ORDER == TILE_BIG_ENDIAN
    const uint16_t expected = val;
#elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN
    const uint16_t expected = 0x3412;
#else
#error "Unsupported byte order"
#endif
    ASSERT_EQ(expected, NetworkToHost16(val));
}

TEST(ByteOrder, NetworkToHost32)
{
    const uint32_t val = 0x12345678;
#if TILE_BYTE_ORDER == TILE_BIG_ENDIAN
    const uint32_t expected = val;
#elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN
    const uint32_t expected = 0x78563412;
#else
#error "Unsupported byte order"
#endif
    ASSERT_EQ(expected, NetworkToHost32(val));
}

TEST(ByteOrder, NetworkToHost64)
{
    const uint64_t val = 0x1234567890abcdef;
#if TILE_BYTE_ORDER == TILE_BIG_ENDIAN
    const uint64_t expected = val;
#elif TILE_BYTE_ORDER == TILE_LITTLE_ENDIAN
    const uint64_t expected = 0xefcdab9078563412;
#else
#error "Unsupported byte order"
#endif
    ASSERT_EQ(expected, NetworkToHost64(val));
}

}// namespace tile
