1 /* vim: set ts=8 sts=4 sw=4 tw=80 noet: */
2 /*======================================================================
3 Copyright (C) 2004,2005,2009 Walter Doekes <walter+tthsum@wjd.nu>
4 This file is part of tthsum.
5 
6 tthsum is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 tthsum is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with tthsum.  If not, see <http://www.gnu.org/licenses/>.
18 ======================================================================*/
19 #include "getopt.h"
20 
21 #include "test.h"
22 #include <string.h>
23 
24 
25 static int argc;
26 static const char* argv[64];
27 
reset_getopt(const char * const args[])28 static void reset_getopt(const char* const args[]) {
29     for (argc = 0; args[argc]; ++argc)
30 	argv[argc] = args[argc];
31 #if !defined(USE_MY_GETOPT) \
32 	&& (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__))
33     optind = 1;
34     optreset = 1;
35 #else /* USE_MY_GETOPT || !__*BSD__ */
36     optind = 0;
37     optopt = '\0';
38 #endif /* USE_MY_GETOPT || !__*BSD__ */
39     opterr = 1;
40 }
41 
test_getopt_counts_and_order()42 static int test_getopt_counts_and_order() {
43     const char* const args[] = {
44 #ifdef USE_BSD_GETOPT
45 	/* BSD getopt semantics means that no options are allowed after
46 	 * non-options. (Also available through POSIXLY_CORRECT.) */
47 	"test_getopt", "-o", "-4", "-ghi", "abc.txt", "De\xff.txt", 0
48 #else /* !USE_BSD_GETOPT */
49 	"test_getopt", "abc.txt", "-o", "-4", "De\xff.txt", "-ghi", 0
50 #endif /* !USE_BSD_GETOPT */
51     };
52     int ret;
53     int good_option_count = 0;
54     int bad_option_count = 0;
55     reset_getopt(args);
56     opterr = 0;
57     while ((ret = getopt(argc, (char* const*)argv, "Vbg")) >= 0) {
58 	switch(ret) {
59 	case 'g':
60 	    /* expected good option */
61 	    TEST_PASS(good_option_count == 0 && bad_option_count == 2,
62 		    "getopt returned option 'g' too soon or too late");
63 	    ++good_option_count;
64 	    break;
65 	case '?':
66 	    /* expected bad options */
67 	    if ((optopt == 'o' && bad_option_count == 0)
68 		    || (optopt == '4' && bad_option_count == 1)
69 		    || (optopt == 'h' && bad_option_count == 2)
70 		    || (optopt == 'i' && bad_option_count == 3)) {
71 		++bad_option_count;
72 		break;
73 	    }
74 	    FAIL3("getopt returned unexpected bad option character: %c (%i/%i)",
75 		    optopt, good_option_count, bad_option_count);
76 	default:
77 	    FAIL3("getopt returned unexpected option character: %c (%i/%i)",
78 		    ret, good_option_count, bad_option_count);
79 	}
80     }
81     TEST_PASS(good_option_count == 1, "got too many or too few good options");
82     TEST_PASS(bad_option_count == 4, "got too many or too few bad options");
83     TEST_PASS1(optind + 2 == argc, "%i arguments found", argc - optind);
84     TEST_PASS1(strcmp(argv[optind], "abc.txt") == 0, "abc.txt != %s",
85 	    argv[optind]);
86     TEST_PASS(strcmp(argv[optind+1], "De\xff.txt") == 0, "De?.txt mismatch");
87     return 0;
88 }
89 
test_getopt_missing_argument()90 static int test_getopt_missing_argument() {
91     const char* const args[] = {"test_getopt", "-o", 0};
92     int ret;
93     reset_getopt(args);
94     opterr = 0;
95     while ((ret = getopt(argc, (char* const*)argv, "o:")) >= 0) {
96 	switch(ret) {
97 	case 'o':
98 	    FAIL("getopt returned 'o' even though we lack arguments");
99 	case '?':
100 	    if (optopt == 'o')
101 		/* missing option argument */
102 		break;
103 	default:
104 	    FAIL2("fell through switch: ret=%i optopt=%i", ret, optopt);
105 	}
106     }
107     return 0;
108 }
109 
test_getopt_double_dash()110 static int test_getopt_double_dash() {
111     const char* const args[] = {"test_getopt", "-o", "--", "-o", "--", 0};
112     int ret;
113     int opts = 0;
114     reset_getopt(args);
115     opterr = 0;
116     while ((ret = getopt(argc, (char* const*)argv, "o")) >= 0) {
117 	switch(ret) {
118 	case 'o':
119 	case '?':
120 	    ++opts;
121 	    break;
122 	default:
123 	    FAIL2("fell through switch: ret=%i optopt=%i", ret, optopt);
124 	}
125     }
126     TEST_PASS(opts == 1, "got too many or too few options");
127     TEST_PASS1(optind + 2 == argc, "%i arguments found", argc - optind);
128     TEST_PASS1(strcmp(argv[optind], "-o") == 0, "-o != %s",
129 	    argv[optind]);
130     TEST_PASS1(strcmp(argv[optind+1], "--") == 0, "-- != %s",
131 	    argv[optind+1]);
132     return 0;
133 }
134 
135 
136 TESTS(getopt_test)
137     TEST(test_getopt_counts_and_order);
138     TEST(test_getopt_missing_argument);
139     TEST(test_getopt_double_dash);
140 ENDTESTS
141