1 // 2 // Copyright (c) 2017 Benjamin Kaufmann 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to 6 // deal in the Software without restriction, including without limitation the 7 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 // sell copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 // IN THE SOFTWARE. 21 #include "catch.hpp" 22 #include <potassco/program_opts/value_store.h> 23 #include <potassco/program_opts/mapped_value.h> 24 #include <potassco/program_opts/typed_value.h> 25 #include <string.h> 26 #include <memory> 27 #include <map> 28 namespace Potassco { 29 namespace ProgramOptions { 30 namespace Test { 31 namespace Po = ProgramOptions; 32 struct Counted { 33 static int count; 34 int parsed; CountedPotassco::ProgramOptions::Test::Counted35 Counted() : parsed(0) { ++count; } ~CountedPotassco::ProgramOptions::Test::Counted36 ~Counted() { --count; } CountedPotassco::ProgramOptions::Test::Counted37 Counted(const Counted& o) : parsed(o.parsed) { ++count; } parsePotassco::ProgramOptions::Test::Counted38 static bool parse(const std::string&, Counted& out) { 39 ++out.parsed; 40 return true; 41 } 42 }; 43 class ValuePtr { 44 public: ValuePtr(Po::Value * p)45 explicit ValuePtr(Po::Value* p) : ptr_(p) {} ~ValuePtr()46 ~ValuePtr() { delete ptr_; } operator ->() const47 Po::Value* operator->() const { return ptr_; } 48 private: 49 ValuePtr(const ValuePtr&); 50 ValuePtr& operator=(const ValuePtr&); 51 Po::Value* ptr_; 52 }; 53 54 int Counted::count = 0; 55 struct Notified { NotifiedPotassco::ProgramOptions::Test::Notified56 Notified() : notifications(0), reused(0), loc(0), ret(false) {} ~NotifiedPotassco::ProgramOptions::Test::Notified57 ~Notified() { delete loc; } notifyIntPotassco::ProgramOptions::Test::Notified58 static bool notifyInt(Notified* this_, const std::string& name, const int* loc) { 59 ++this_->notifications; 60 this_->opts.insert(std::map<std::string, int>::value_type(name, *loc)); 61 if (this_->loc == loc) { 62 ++this_->reused; 63 } 64 if (this_->ret) { 65 this_->loc = loc; 66 } 67 return this_->ret; 68 } notifyUntypedPotassco::ProgramOptions::Test::Notified69 static bool notifyUntyped(Notified* this_, const std::string& name, const std::string& value) { 70 ++this_->notifications; 71 int temp; 72 if (Potassco::string_cast<int>(value, temp)) { 73 this_->opts[name] = temp; 74 return true; 75 } 76 return false; 77 } 78 std::map<std::string, int> opts; 79 int notifications, reused; 80 const int* loc; 81 bool ret; 82 }; 83 84 TEST_CASE("Test value store", "[value]") { 85 SECTION("default is empty") { 86 Po::ValueStore x; 87 REQUIRE(x.empty()); 88 } 89 SECTION("values are copied into store") { 90 Po::ValueStore x; 91 Po::ValueStore y((Counted())); 92 x = y; 93 REQUIRE(Counted::count == 2); 94 } 95 SECTION("store supports swap") { 96 Po::ValueStore x((Counted())), y((Counted())); 97 Po::value_cast<Counted>(x).parsed = 0; 98 Po::value_cast<Counted>(y).parsed = 10; 99 x.swap(y); 100 REQUIRE(Po::value_cast<Counted>(x).parsed == 10); 101 REQUIRE(Po::value_cast<Counted>(y).parsed == 0); 102 x.clear(); 103 REQUIRE(Po::unsafe_value_cast<Counted>(&x) == static_cast<Counted*>(0)); 104 } 105 REQUIRE(Counted::count == 0); 106 } 107 108 TEST_CASE("Test flag", "[value]") { 109 bool loud; 110 SECTION("check properties") { 111 ValuePtr loudFlag(Po::flag(loud)); 112 REQUIRE(loudFlag->isImplicit() == true); 113 REQUIRE(loudFlag->isFlag() == true); 114 REQUIRE(strcmp(loudFlag->implicit(), "1") == 0); 115 } 116 SECTION("default parser stores true") { 117 ValuePtr loudFlag(Po::flag(loud)); 118 REQUIRE((loudFlag->parse("", "") && loud == true)); 119 loud = false; 120 loudFlag->parse("", "on"); 121 REQUIRE(loud == true); 122 } 123 SECTION("alternative parser can store false") { 124 ValuePtr quietFlag(Po::flag(loud, Po::store_false)); 125 REQUIRE((quietFlag->parse("", "") && loud == false)); 126 quietFlag->parse("", "off"); 127 REQUIRE(loud == true); 128 } 129 } 130 131 TEST_CASE("Test storeTo", "[value]") { 132 int x; bool y; 133 ValuePtr v1(Po::storeTo(x)); 134 ValuePtr v2(Po::flag(y)); 135 SECTION("store int") { 136 REQUIRE(v1->parse("", "22")); 137 REQUIRE(x == 22); 138 } 139 SECTION("fail on invalid type") { 140 x = 99; 141 REQUIRE(!v1->parse("", "ab")); 142 REQUIRE(x == 99); 143 } 144 SECTION("init with state") { 145 ValuePtr v(Po::storeTo(x)->state(Po::Value::value_defaulted)); 146 REQUIRE(v->state() == Po::Value::value_defaulted); 147 REQUIRE((v2->state() == Po::Value::value_unassigned && v2->isImplicit() && v2->isFlag())); 148 } 149 SECTION("parse as default") { 150 REQUIRE(v2->parse("", "off", Po::Value::value_defaulted)); 151 REQUIRE(v2->state() == Po::Value::value_defaulted); 152 } 153 SECTION("parse bool as implicit") { 154 REQUIRE(v2->parse("", "")); 155 REQUIRE(y == true); 156 v2->implicit("0"); 157 REQUIRE(v2->parse("", "")); 158 REQUIRE(y == false); 159 } 160 SECTION("parse int as implicit") { 161 v1->implicit(LIT_TO_STRING(102)); 162 REQUIRE(v1->isImplicit()); 163 REQUIRE((v1->parse("", "") && x == 102)); 164 } 165 166 SECTION("test custom parser") { 167 Counted c; 168 ValuePtr vc(Po::storeTo(c, &Counted::parse)->implicit("")); 169 REQUIRE(vc->parse("", "")); 170 REQUIRE(c.parsed == 1); 171 } 172 } 173 174 TEST_CASE("Test custom value", "[value]") { 175 Notified n; 176 SECTION("with typed value creation") { 177 ValuePtr v(Po::notify<int>(&n, &Notified::notifyInt)); 178 v->parse("foo", "123"); 179 n.ret = true; 180 v->parse("bar", "342"); 181 v->parse("jojo", "999"); 182 REQUIRE(n.notifications == 3); 183 REQUIRE(n.reused == 1); 184 REQUIRE(n.opts["foo"] == 123); 185 REQUIRE(n.opts["bar"] == 342); 186 REQUIRE(*n.loc == 999); 187 } 188 SECTION("with untyped value") { 189 ValuePtr v(Po::notify(&n, &Notified::notifyUntyped)); 190 REQUIRE(v->parse("foo", "123")); 191 REQUIRE(v->parse("bar", "342")); 192 REQUIRE(v->parse("jojo", "999")); 193 REQUIRE(!v->parse("kaputt", "x12")); 194 REQUIRE(n.reused == 0); 195 REQUIRE(n.notifications == 4); 196 REQUIRE(n.opts["foo"] == 123); 197 REQUIRE(n.opts["bar"] == 342); 198 REQUIRE(n.opts["jojo"] == 999); 199 REQUIRE(n.opts.count("kaputt") == 0); 200 } 201 } 202 TEST_CASE("Test mapped value", "[value]") { 203 Po::ValueMap vm; 204 ValuePtr v1(Po::store<int>(vm)); 205 ValuePtr v2(Po::store<double>(vm)); 206 ValuePtr v3(Po::flag(vm)); 207 v1->parse("foo", "22"); 208 v2->parse("bar", "99.2"); 209 v3->parse("help", "false"); 210 REQUIRE(Po::value_cast<int>(vm["foo"]) == 22); 211 REQUIRE(Po::value_cast<double>(vm["bar"]) == 99.2); 212 REQUIRE(Po::value_cast<bool>(vm["help"]) == false); 213 214 v1->parse("foo", "27"); 215 REQUIRE(Po::value_cast<int>(vm["foo"]) == 27); 216 } 217 struct Color { enum Value { RED = 2, GREEN = 10, BLUE = 20 }; }; 218 struct Mode { enum Value { DEF, IMP, EXP }; }; 219 TEST_CASE("Test enum value", "[value]") { 220 int x; 221 Mode::Value y; 222 223 ValuePtr v1(Po::storeTo(x, Po::values<Color::Value>() 224 ("Red", Color::RED) 225 ("Green", Color::GREEN) 226 ("Blue", Color::BLUE))); 227 228 ValuePtr v2(Po::storeTo(y, Po::values<Mode::Value>() 229 ("Default", Mode::DEF) 230 ("Implicit", Mode::IMP) 231 ("Explicit", Mode::EXP))); 232 233 REQUIRE((v1->parse("", "Red") && x == 2)); 234 REQUIRE((v1->parse("", "GREEN") && x == Color::GREEN)); 235 REQUIRE(!v1->parse("", "Blu")); 236 237 REQUIRE((v2->parse("", "Implicit") && y == Mode::IMP)); 238 } 239 240 }}} 241