/* vim: set ts=8 sts=4 sw=4 tw=80 noet: */
/*======================================================================
Copyright (C) 2004,2005,2009 Walter Doekes <walter+tthsum@wjd.nu>
This file is part of tthsum.

tthsum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

tthsum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with tthsum.  If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#include "endian.h"

#include "test.h"
#include "types.h"


static int test_defines() {
#ifndef BYTE_ORDER
    FAIL("BYTE_ORDER is not defined");
#endif
#ifndef BIG_ENDIAN
    FAIL("BIG_ENDIAN is not defined");
#endif
#ifndef LITTLE_ENDIAN
    FAIL("LITTLE_ENDIAN is not defined");
#endif
#if BIG_ENDIAN == LITTLE_ENDIAN
    FAIL("BIG_ENDIAN == LITTLE_ENDIAN");
#endif
#if BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN
    FAIL("BYTE_ORDER not in (BIG_ENDIAN, LITTLE_ENDIAN)");
#endif
    return 0;
}

static int test_endian8() {
    uint8_t val8 = 0x1f;
    char val = 0x7f;
    if ((uint8_t)(val8 << 4) != 0xf0)
	FAIL("The unsigned 8bit type has too many bits");
    if ((char)(val >> 4) != 0x07)
	FAIL("The char type is broken");
    val = (char)0xf0;
    if (((signed char)val >> 2) != -4)
	FAIL("The char type is broken");
    return 0;
}

static int test_endian16() {
    uint16_t val16 = 0x4321;
    uint8_t *p = (uint8_t*)&val16;
    short val = 0x4321;
    char *q = (char*)&val;
#if BYTE_ORDER == BIG_ENDIAN
    if (p[0] != 0x43 || p[1] != 0x21)
	FAIL("Big endian check fails on 16 bit numbers");
    if (q[0] != 0x43 || q[1] != 0x21)
	FAIL("Big endian check fails on shorts");
#else /* BYTE_ORDER != BIG_ENDIAN */
    if (p[0] != 0x21 || p[1] != 0x43)
	FAIL("Little endian check fails on 16 bit numbers");
    if (q[0] != 0x21 || q[1] != 0x43)
	FAIL("Little endian check fails on shorts");
#endif /* BYTE_ORDER != BIG_ENDIAN */
    return 0;
}

static int test_endian32() {
    uint32_t val32 = 0x87654321;
    uint8_t *p = (uint8_t*)&val32;
    long val = -2023406815; /* 0x87654321 */
    char *q = (char*)&val;
#if BYTE_ORDER == BIG_ENDIAN
    if (p[0] != 0x87 || p[1] != 0x65 || p[2] != 0x43 || p[3] != 0x21)
	FAIL("Big endian check fails on 32 bit numbers");
    if (q[0] != -121 || q[1] != 0x65 || q[2] != 0x43 || q[3] != 0x21)
	FAIL("Big endian check fails on longs");
#else /* BYTE_ORDER != BIG_ENDIAN */
    if (p[0] != 0x21 || p[1] != 0x43 || p[2] != 0x65 || p[3] != 0x87)
	FAIL("Little endian check fails on 32 bit numbers");
    if (q[0] != 0x21 || q[1] != 0x43 || q[2] != 0x65 || q[3] != -121)
	FAIL("Little endian check fails on longs");
#endif /* BYTE_ORDER != BIG_ENDIAN */
    return 0;
}

static int test_endian64() {
    uint64_t val64 = _ULL(0x0fedcba987654321);
    uint8_t *p = (uint8_t*)&val64;
#if BYTE_ORDER == BIG_ENDIAN
    if (p[0] != 0x0f || p[1] != 0xed || p[2] != 0xcb || p[3] != 0xa9
	    || p[4] != 0x87 || p[5] != 0x65 || p[6] != 0x43 || p[7] != 0x21)
	FAIL("Big endian check fails on 32 bit numbers");
#else /* BYTE_ORDER != BIG_ENDIAN */
    if (p[0] != 0x21 || p[1] != 0x43 || p[2] != 0x65 || p[3] != 0x87
	    || p[4] != 0xa9 || p[5] != 0xcb || p[6] != 0xed || p[7] != 0x0f)
	FAIL("Little endian check fails on 32 bit numbers");
#endif /* BYTE_ORDER != BIG_ENDIAN */
    return 0;
}


TESTS(endian_test)
    TEST(test_defines);
    TEST(test_endian8);
    TEST(test_endian16);
    TEST(test_endian32);
    TEST(test_endian64);
ENDTESTS
