/*
 * Copyright © 2005-2020 Rich Felker
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <wchar.h>

/* r = place to store result
 * f = function call to test (or any expression)
 * x = expected result
 * m = message to print on failure (with formats for r & x)
 **/

#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __GNUC__ > 4)
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wunknown-warning-option"
#pragma GCC diagnostic ignored "-Wformat-extra-args"
#pragma GCC diagnostic ignored "-Wformat"
#endif

#define TEST(r, f, x, m)                                                                 \
    (msg = #f,                                                                           \
     ((r) = (f)) == (x)                                                                  \
         || (printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, #f, r, x), err++, 0))

#define TEST2(r, f, x, m)                                                             \
    (((r) = (f)) == (x)                                                               \
     || (printf(__FILE__ ":%d: %s failed (" m ")\n", __LINE__, msg, r, x), err++, 0))

static int
test_wcstol(void)
{
    int                i;
    long               l;
    unsigned long      ul;
    long long          ll;
    unsigned long long ull;
    char              *msg = "";
    int                err = 0;
    wchar_t           *s, *c;

    (void)ll;
    (void)ull;
    //	TEST(l, atol("2147483647"), 2147483647L, "max 32bit signed %ld != %ld");

    TEST(l, wcstol(L"2147483647", 0, 0), 2147483647L, "max 32bit signed %ld != %ld");
    TEST(ul, wcstoul(L"4294967295", 0, 0), 4294967295UL, "max 32bit unsigned %lu != %lu");

    if (sizeof(long) == 4) {
        errno = 0;
        TEST(l, wcstol(s = L"2147483648", &c, 0), 2147483647L, "uncaught overflow %ld != %ld");
        TEST2(i, c - s, 10, "wrong final position %d != %d");
        TEST2(i, errno, ERANGE, "missing errno %d != %d");
        errno = 0;
        TEST(l, wcstol(s = L"-2147483649", &c, 0), -2147483647L - 1,
             "uncaught overflow %ld != %ld");
        TEST2(i, c - s, 11, "wrong final position %d != %d");
        TEST2(i, errno, ERANGE, "missing errno %d != %d");
        errno = 0;
        TEST(ul, wcstoul(s = L"4294967296", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu");
        TEST2(i, c - s, 10, "wrong final position %d != %d");
        TEST2(i, errno, ERANGE, "missing errno %d != %d");
        errno = 0;
        TEST(ul, wcstoul(s = L"-1", &c, 0), -1UL, "rejected negative %lu != %lu");
        TEST2(i, c - s, 2, "wrong final position %d != %d");
        TEST2(i, errno, 0, "spurious errno %d != %d");
        errno = 0;
        TEST(ul, wcstoul(s = L"-2", &c, 0), -2UL, "rejected negative %lu != %lu");
        TEST2(i, c - s, 2, "wrong final position %d != %d");
        TEST2(i, errno, 0, "spurious errno %d != %d");
        errno = 0;
        TEST(ul, wcstoul(s = L"-2147483648", &c, 0), -2147483648UL, "rejected negative %lu != %lu");
        TEST2(i, c - s, 11, "wrong final position %d != %d");
        TEST2(i, errno, 0, "spurious errno %d != %d");
        errno = 0;
        TEST(ul, wcstoul(s = L"-2147483649", &c, 0), -2147483649UL, "rejected negative %lu != %lu");
        TEST2(i, c - s, 11, "wrong final position %d != %d");
        TEST2(i, errno, 0, "spurious errno %d != %d");
    } else {
        errno = 0;
        TEST(l, wcstol(s = L"9223372036854775808", &c, 0), 9223372036854775807L,
             "uncaught overflow %ld != %ld");
        TEST2(i, c - s, 19, "wrong final position %d != %d");
        TEST2(i, errno, ERANGE, "missing errno %d != %d");
        errno = 0;
        TEST(l, wcstol(s = L"-9223372036854775809", &c, 0), -9223372036854775807L - 1,
             "uncaught overflow %ld != %ld");
        TEST2(i, c - s, 20, "wrong final position %d != %d");
        TEST2(i, errno, ERANGE, "missing errno %d != %d");
        errno = 0;
        TEST(ul, wcstoul(s = L"18446744073709551616", &c, 0), 18446744073709551615UL,
             "uncaught overflow %lu != %lu");
        TEST2(i, c - s, 20, "wrong final position %d != %d");
        TEST2(i, errno, ERANGE, "missing errno %d != %d");
        errno = 0;
        TEST(ul, wcstoul(s = L"-1", &c, 0), -1UL, "rejected negative %lu != %lu");
        TEST2(i, c - s, 2, "wrong final position %d != %d");
        TEST2(i, errno, 0, "spurious errno %d != %d");
        errno = 0;
        TEST(ul, wcstoul(s = L"-2", &c, 0), -2UL, "rejected negative %lu != %lu");
        TEST2(i, c - s, 2, "wrong final position %d != %d");
        TEST2(i, errno, 0, "spurious errno %d != %d");
        errno = 0;
        TEST(ul, wcstoul(s = L"-9223372036854775808", &c, 0), -9223372036854775808UL,
             "rejected negative %lu != %lu");
        TEST2(i, c - s, 20, "wrong final position %d != %d");
        TEST2(i, errno, 0, "spurious errno %d != %d");
        errno = 0;
        TEST(ul, wcstoul(s = L"-9223372036854775809", &c, 0), -9223372036854775809UL,
             "rejected negative %lu != %lu");
        TEST2(i, c - s, 20, "wrong final position %d != %d");
        TEST2(i, errno, 0, "spurious errno %d != %d");
    }

    TEST(l, wcstol(L"z", 0, 36), 35, "%ld != %ld");
    TEST(l, wcstol(L"00010010001101000101011001111000", 0, 2), 0x12345678, "%ld != %ld");
    TEST(l, wcstol(s = L"0F5F", &c, 16), 0x0f5f, "%ld != %ld");

    TEST(l, wcstol(s = L"0xz", &c, 16), 0, "%ld != %ld");
    TEST2(i, c - s, 1, "wrong final position %ld != %ld");

    TEST(l, wcstol(s = L"0x1234", &c, 16), 0x1234, "%ld != %ld");
    TEST2(i, c - s, 6, "wrong final position %ld != %ld");

    wchar_t delim_buf[6] = L"09af:";

    for (int j = 0; j < 256; j++) {
        delim_buf[4] = j;
        if (('0' <= j && j <= '9') || ('A' <= j && j <= 'F') || ('a' <= j && j <= 'f')) {
            long k;
            if ('0' <= j && j <= '9')
                k = j - '0';
            else if ('A' <= j && j <= 'Z')
                k = j - 'A' + 10;
            else if ('a' <= j && j <= 'z')
                k = j - 'a' + 10;
            else
                k = 0xffffffff;
            TEST(l, wcstol(s = delim_buf, &c, 16), 0x09af0 | k, "%ld != %ld");
            TEST2(i, c - s, 5, "wrong final position %ld != %ld");
        } else {
            TEST(l, wcstol(s = delim_buf, &c, 16), 0x09af, "%ld != %ld");
            TEST2(i, c - s, 4, "wrong final position %ld != %ld");
        }
    }

    errno = 0;
    c = NULL;
    TEST(l, wcstol(s = L"123", &c, 37), 0, "%ld != %ld");

    /*
      The value of 'c' is undefined when base is invalid, so this
      test isn't valid:
       TEST2(i, c-s, 0, "wrong final position %d != %d");
    */
    TEST2(i, errno, EINVAL, "%d != %d");

    TEST(l, wcstol(s = L"  15437", &c, 8), 015437, "%ld != %ld");
    TEST2(i, c - s, 7, "wrong final position %d != %d");

    TEST(l, wcstol(s = L"  1", &c, 0), 1, "%ld != %ld");
    TEST2(i, c - s, 3, "wrong final position %d != %d");

    return err;
}

#define TEST_NAME wcstol
#include "testcase.h"
