/* 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 "getopt.h"

#include "test.h"
#include <string.h>


static int argc;
static const char* argv[64];

static void reset_getopt(const char* const args[]) {
    for (argc = 0; args[argc]; ++argc)
	argv[argc] = args[argc];
#if !defined(USE_MY_GETOPT) \
	&& (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__))
    optind = 1;
    optreset = 1;
#else /* USE_MY_GETOPT || !__*BSD__ */
    optind = 0;
    optopt = '\0';
#endif /* USE_MY_GETOPT || !__*BSD__ */
    opterr = 1;
}

static int test_getopt_counts_and_order() {
    const char* const args[] = {
#ifdef USE_BSD_GETOPT
	/* BSD getopt semantics means that no options are allowed after
	 * non-options. (Also available through POSIXLY_CORRECT.) */
	"test_getopt", "-o", "-4", "-ghi", "abc.txt", "De\xff.txt", 0
#else /* !USE_BSD_GETOPT */
	"test_getopt", "abc.txt", "-o", "-4", "De\xff.txt", "-ghi", 0
#endif /* !USE_BSD_GETOPT */
    };
    int ret;
    int good_option_count = 0;
    int bad_option_count = 0;
    reset_getopt(args);
    opterr = 0;
    while ((ret = getopt(argc, (char* const*)argv, "Vbg")) >= 0) {
	switch(ret) {
	case 'g':
	    /* expected good option */
	    TEST_PASS(good_option_count == 0 && bad_option_count == 2,
		    "getopt returned option 'g' too soon or too late");
	    ++good_option_count;
	    break;
	case '?':
	    /* expected bad options */
	    if ((optopt == 'o' && bad_option_count == 0)
		    || (optopt == '4' && bad_option_count == 1)
		    || (optopt == 'h' && bad_option_count == 2)
		    || (optopt == 'i' && bad_option_count == 3)) {
		++bad_option_count;
		break;
	    }
	    FAIL3("getopt returned unexpected bad option character: %c (%i/%i)",
		    optopt, good_option_count, bad_option_count);
	default:
	    FAIL3("getopt returned unexpected option character: %c (%i/%i)",
		    ret, good_option_count, bad_option_count);
	}
    }
    TEST_PASS(good_option_count == 1, "got too many or too few good options");
    TEST_PASS(bad_option_count == 4, "got too many or too few bad options");
    TEST_PASS1(optind + 2 == argc, "%i arguments found", argc - optind);
    TEST_PASS1(strcmp(argv[optind], "abc.txt") == 0, "abc.txt != %s",
	    argv[optind]);
    TEST_PASS(strcmp(argv[optind+1], "De\xff.txt") == 0, "De?.txt mismatch");
    return 0;
}

static int test_getopt_missing_argument() {
    const char* const args[] = {"test_getopt", "-o", 0};
    int ret;
    reset_getopt(args);
    opterr = 0;
    while ((ret = getopt(argc, (char* const*)argv, "o:")) >= 0) {
	switch(ret) {
	case 'o':
	    FAIL("getopt returned 'o' even though we lack arguments");
	case '?':
	    if (optopt == 'o')
		/* missing option argument */
		break;
	default:
	    FAIL2("fell through switch: ret=%i optopt=%i", ret, optopt);
	}
    }
    return 0;
}

static int test_getopt_double_dash() {
    const char* const args[] = {"test_getopt", "-o", "--", "-o", "--", 0};
    int ret;
    int opts = 0;
    reset_getopt(args);
    opterr = 0;
    while ((ret = getopt(argc, (char* const*)argv, "o")) >= 0) {
	switch(ret) {
	case 'o':
	case '?':
	    ++opts;
	    break;
	default:
	    FAIL2("fell through switch: ret=%i optopt=%i", ret, optopt);
	}
    }
    TEST_PASS(opts == 1, "got too many or too few options");
    TEST_PASS1(optind + 2 == argc, "%i arguments found", argc - optind);
    TEST_PASS1(strcmp(argv[optind], "-o") == 0, "-o != %s",
	    argv[optind]);
    TEST_PASS1(strcmp(argv[optind+1], "--") == 0, "-- != %s",
	    argv[optind+1]);
    return 0;
}


TESTS(getopt_test)
    TEST(test_getopt_counts_and_order);
    TEST(test_getopt_missing_argument);
    TEST(test_getopt_double_dash);
ENDTESTS
