| 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 |
|
| 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 |
|
| 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()); |
| 42 |
CHECK(int1 == -1); |
| 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); |
| 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()); |
| 62 |
CHECK(int1 == 123); |
| 63 |
CHECK(!int2); |
| 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()); |
| 70 |
CHECK(int1 == -1); |
| 71 |
CHECK(int2); |
| 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()); |
| 79 |
CHECK(dbl1 == 2.72); |
| 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()); |
| 86 |
CHECK(s1 == "foobar"); |
| 87 |
} |
| 88 |
SECTION("flag value") { |
| 89 |
std::array in = { TclObject("-flag") }; |
| 90 |
auto out = parseTclArgs(interp, in, table); |
| 91 |
|
| 92 |
CHECK(out.empty()); |
| 93 |
CHECK(flag); |
| 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); |
| 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); |
| 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 |
} |