OXYGENHUB
◆ main openmsx / src / unittest / TclArgParser.cc
4.7 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "catch.hpp"
2
#include "TclArgParser.hh"
3
4
#include "Interpreter.hh"
5
6
#include <array>
7
#include <optional>
8
9
using namespace openmsx;
10
11
TEST_CASE("TclArgParser")
12
{
13
	Interpreter interp;
14
15
	// variables (possibly) filled in by parser
16
	int int1 = -1;
17
	std::optional<int> int2;
18
	double dbl1 = -1.0;
19
	std::optional<double> dbl2;
20
	std::string s1;
21
	std::optional<std::string> s2;
22
	std::vector<int> ints;
23
	bool flag = false;
24
25
	// description of the parser
26
	auto table = std::to_array<const ArgsInfo>({
27
		valueArg("-int1", int1),
28
		valueArg("-int2", int2),
29
		valueArg("-double1", dbl1),
30
		valueArg("-double2", dbl2),
31
		valueArg("-string1", s1),
32
		valueArg("-string2", s2),
33
		valueArg("-ints", ints),
34
		flagArg("-flag", flag),
35
	});
36
37
	SECTION("empty") {
38
		std::span<const TclObject, 0> in;
39
		auto out = parseTclArgs(interp, in, table);
40
41
		CHECK(out.empty()); // no args
42
		CHECK(int1 == -1); // other stuff unchanged
43
		CHECK(!int2);
44
		CHECK(!flag);
45
	}
46
	SECTION("only normal args") {
47
		std::array in = { TclObject("arg1"), TclObject(2), TclObject(3) };
48
		auto out = parseTclArgs(interp, in, table);
49
50
		CHECK(out.size() == 3);
51
		CHECK(out[0] == "arg1");
52
		CHECK(out[1] == "2");
53
		CHECK(out[2] == "3");
54
		CHECK(int1 == -1); // other stuff unchanged
55
		CHECK(!int2);
56
	}
57
	SECTION("(regular) integer option") {
58
		std::array in = { TclObject("-int1"), TclObject(123) };
59
		auto out = parseTclArgs(interp, in, table);
60
61
		CHECK(out.empty()); // no regular args
62
		CHECK(int1 == 123); // this has a new value
63
		CHECK(!int2); // other stuff unchanged
64
	}
65
	SECTION("(optional) integer option") {
66
		std::array in = { TclObject("-int2"), TclObject(456) };
67
		auto out = parseTclArgs(interp, in, table);
68
69
		CHECK(out.empty()); // no regular args
70
		CHECK(int1 == -1); // this is unchanged (or was it explicitly set to -1 ;-)
71
		CHECK(int2); // with an optional<int> we can check that it was set or not
72
		CHECK(*int2 == 456);
73
	}
74
	SECTION("(regular) double option") {
75
		std::array in = { TclObject("-double1"), TclObject(2.72) };
76
		auto out = parseTclArgs(interp, in, table);
77
78
		CHECK(out.empty()); // no regular args
79
		CHECK(dbl1 == 2.72); // this has a new value
80
	}
81
	SECTION("(regular) string option") {
82
		std::array in = { TclObject("-string1"), TclObject("foobar") };
83
		auto out = parseTclArgs(interp, in, table);
84
85
		CHECK(out.empty()); // no regular args
86
		CHECK(s1 == "foobar"); // this has a new value
87
	}
88
	SECTION("flag value") {
89
		std::array in = { TclObject("-flag") };
90
		auto out = parseTclArgs(interp, in, table);
91
92
		CHECK(out.empty()); // no regular args
93
		CHECK(flag); // flag was set
94
	}
95
	SECTION("multiple options and args") {
96
		std::array in = { TclObject("bla"), TclObject("-int2"), TclObject(789), TclObject("qwerty"),
97
		                  TclObject("-double1"), TclObject("6.28"), TclObject("-string2"), TclObject("bar"),
98
		                  TclObject("zyxwv"), TclObject("-flag"), TclObject("-int1"), TclObject("-30"),
99
		};
100
		auto out = parseTclArgs(interp, in, table);
101
102
		CHECK(out.size() == 3);
103
		CHECK(out[0] == "bla");
104
		CHECK(out[1] == "qwerty");
105
		CHECK(out[2] == "zyxwv");
106
		CHECK(int1 == -30);
107
		CHECK(int2); CHECK(*int2 == 789);
108
		CHECK(dbl1 == 6.28);
109
		CHECK(!dbl2);
110
		CHECK(s1 == "");
111
		CHECK(s2); CHECK(*s2 == "bar");
112
		CHECK(flag);
113
	}
114
	SECTION("set same option twice") {
115
		std::array in = { TclObject("-int1"), TclObject(123), TclObject("bla"), TclObject("-int1"), TclObject(234) };
116
		auto out = parseTclArgs(interp, in, table);
117
118
		CHECK(out.size() == 1);
119
		CHECK(int1 == 234); // take the value of the last option
120
	}
121
	SECTION("vector<T> accepts repeated options") {
122
		std::array in = { TclObject("-ints"), TclObject(11), TclObject("-ints"), TclObject(22) };
123
		auto out = parseTclArgs(interp, in, table);
124
125
		CHECK(out.empty());
126
		CHECK(ints.size() == 2);
127
		CHECK(ints[0] == 11);
128
		CHECK(ints[1] == 22);
129
	}
130
	SECTION("no options after --") {
131
		std::array in = { TclObject("-int1"), TclObject(123), TclObject("--"), TclObject("-int1"), TclObject(234) };
132
		auto out = parseTclArgs(interp, in, table);
133
134
		CHECK(out.size() == 2);
135
		CHECK(out[0] == "-int1");
136
		CHECK(out[1] == "234");
137
		CHECK(int1 == 123); // take the value of the option before --
138
	}
139
	SECTION("missing value for option") {
140
		std::array in = { TclObject("bla"), TclObject("-int1") };
141
		CHECK_THROWS(parseTclArgs(interp, in, table));
142
	}
143
	SECTION("non-integer value for integer-option") {
144
		std::array in = { TclObject("-int1"), TclObject("bla") };
145
		CHECK_THROWS(parseTclArgs(interp, in, table));
146
	}
147
	SECTION("non-double value for double-option") {
148
		std::array in = { TclObject("-double2"), TclObject("bla") };
149
		CHECK_THROWS(parseTclArgs(interp, in, table));
150
	}
151
	SECTION("unknown option") {
152
		std::array in = { TclObject("-bla"), TclObject("bla") };
153
		CHECK_THROWS(parseTclArgs(interp, in, table));
154
	}
155
}