1 // Copyright 2010 The Kyua Authors. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // * Neither the name of Google Inc. nor the names of its contributors 14 // may be used to endorse or promote products derived from this software 15 // without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #include "utils/cmdline/options.hpp" 30 31 #include <atf-c++.hpp> 32 33 #include "utils/cmdline/exceptions.hpp" 34 #include "utils/defs.hpp" 35 #include "utils/fs/path.hpp" 36 37 namespace cmdline = utils::cmdline; 38 39 namespace { 40 41 42 /// Simple string-based option type for testing purposes. 43 class mock_option : public cmdline::base_option { 44 public: 45 /// Constructs a mock option with a short name and a long name. 46 /// 47 /// 48 /// \param short_name_ The short name for the option. 49 /// \param long_name_ The long name for the option. 50 /// \param description_ A user-friendly description for the option. 51 /// \param arg_name_ If not NULL, specifies that the option must receive an 52 /// argument and specifies the name of such argument for documentation 53 /// purposes. 54 /// \param default_value_ If not NULL, specifies that the option has a 55 /// default value for the mandatory argument. 56 mock_option(const char short_name_, const char* long_name_, 57 const char* description_, const char* arg_name_ = NULL, 58 const char* default_value_ = NULL) : 59 base_option(short_name_, long_name_, description_, arg_name_, 60 default_value_) {} 61 62 /// Constructs a mock option with a long name only. 63 /// 64 /// \param long_name_ The long name for the option. 65 /// \param description_ A user-friendly description for the option. 66 /// \param arg_name_ If not NULL, specifies that the option must receive an 67 /// argument and specifies the name of such argument for documentation 68 /// purposes. 69 /// \param default_value_ If not NULL, specifies that the option has a 70 /// default value for the mandatory argument. 71 mock_option(const char* long_name_, 72 const char* description_, const char* arg_name_ = NULL, 73 const char* default_value_ = NULL) : 74 base_option(long_name_, description_, arg_name_, default_value_) {} 75 76 /// The data type of this option. 77 typedef std::string option_type; 78 79 /// Ensures that the argument passed to the option is valid. 80 /// 81 /// In this particular mock option, this does not perform any validation. 82 void 83 validate(const std::string& /* str */) const 84 { 85 // Do nothing. 86 } 87 88 /// Returns the input parameter without any conversion. 89 /// 90 /// \param str The user-provided argument to the option. 91 /// 92 /// \return The same value as provided by the user without conversion. 93 static std::string 94 convert(const std::string& str) 95 { 96 return str; 97 } 98 }; 99 100 101 } // anonymous namespace 102 103 104 ATF_TEST_CASE_WITHOUT_HEAD(base_option__short_name__no_arg); 105 ATF_TEST_CASE_BODY(base_option__short_name__no_arg) 106 { 107 const mock_option o('f', "force", "Force execution"); 108 ATF_REQUIRE(o.has_short_name()); 109 ATF_REQUIRE_EQ('f', o.short_name()); 110 ATF_REQUIRE_EQ("force", o.long_name()); 111 ATF_REQUIRE_EQ("Force execution", o.description()); 112 ATF_REQUIRE(!o.needs_arg()); 113 ATF_REQUIRE_EQ("-f", o.format_short_name()); 114 ATF_REQUIRE_EQ("--force", o.format_long_name()); 115 } 116 117 118 ATF_TEST_CASE_WITHOUT_HEAD(base_option__short_name__with_arg__no_default); 119 ATF_TEST_CASE_BODY(base_option__short_name__with_arg__no_default) 120 { 121 const mock_option o('c', "conf_file", "Configuration file", "path"); 122 ATF_REQUIRE(o.has_short_name()); 123 ATF_REQUIRE_EQ('c', o.short_name()); 124 ATF_REQUIRE_EQ("conf_file", o.long_name()); 125 ATF_REQUIRE_EQ("Configuration file", o.description()); 126 ATF_REQUIRE(o.needs_arg()); 127 ATF_REQUIRE_EQ("path", o.arg_name()); 128 ATF_REQUIRE(!o.has_default_value()); 129 ATF_REQUIRE_EQ("-c path", o.format_short_name()); 130 ATF_REQUIRE_EQ("--conf_file=path", o.format_long_name()); 131 } 132 133 134 ATF_TEST_CASE_WITHOUT_HEAD(base_option__short_name__with_arg__with_default); 135 ATF_TEST_CASE_BODY(base_option__short_name__with_arg__with_default) 136 { 137 const mock_option o('c', "conf_file", "Configuration file", "path", 138 "defpath"); 139 ATF_REQUIRE(o.has_short_name()); 140 ATF_REQUIRE_EQ('c', o.short_name()); 141 ATF_REQUIRE_EQ("conf_file", o.long_name()); 142 ATF_REQUIRE_EQ("Configuration file", o.description()); 143 ATF_REQUIRE(o.needs_arg()); 144 ATF_REQUIRE_EQ("path", o.arg_name()); 145 ATF_REQUIRE(o.has_default_value()); 146 ATF_REQUIRE_EQ("defpath", o.default_value()); 147 ATF_REQUIRE_EQ("-c path", o.format_short_name()); 148 ATF_REQUIRE_EQ("--conf_file=path", o.format_long_name()); 149 } 150 151 152 ATF_TEST_CASE_WITHOUT_HEAD(base_option__long_name__no_arg); 153 ATF_TEST_CASE_BODY(base_option__long_name__no_arg) 154 { 155 const mock_option o("dryrun", "Dry run mode"); 156 ATF_REQUIRE(!o.has_short_name()); 157 ATF_REQUIRE_EQ("dryrun", o.long_name()); 158 ATF_REQUIRE_EQ("Dry run mode", o.description()); 159 ATF_REQUIRE(!o.needs_arg()); 160 ATF_REQUIRE_EQ("--dryrun", o.format_long_name()); 161 } 162 163 164 ATF_TEST_CASE_WITHOUT_HEAD(base_option__long_name__with_arg__no_default); 165 ATF_TEST_CASE_BODY(base_option__long_name__with_arg__no_default) 166 { 167 const mock_option o("helper", "Path to helper", "path"); 168 ATF_REQUIRE(!o.has_short_name()); 169 ATF_REQUIRE_EQ("helper", o.long_name()); 170 ATF_REQUIRE_EQ("Path to helper", o.description()); 171 ATF_REQUIRE(o.needs_arg()); 172 ATF_REQUIRE_EQ("path", o.arg_name()); 173 ATF_REQUIRE(!o.has_default_value()); 174 ATF_REQUIRE_EQ("--helper=path", o.format_long_name()); 175 } 176 177 178 ATF_TEST_CASE_WITHOUT_HEAD(base_option__long_name__with_arg__with_default); 179 ATF_TEST_CASE_BODY(base_option__long_name__with_arg__with_default) 180 { 181 const mock_option o("executable", "Executable name", "file", "foo"); 182 ATF_REQUIRE(!o.has_short_name()); 183 ATF_REQUIRE_EQ("executable", o.long_name()); 184 ATF_REQUIRE_EQ("Executable name", o.description()); 185 ATF_REQUIRE(o.needs_arg()); 186 ATF_REQUIRE_EQ("file", o.arg_name()); 187 ATF_REQUIRE(o.has_default_value()); 188 ATF_REQUIRE_EQ("foo", o.default_value()); 189 ATF_REQUIRE_EQ("--executable=file", o.format_long_name()); 190 } 191 192 193 ATF_TEST_CASE_WITHOUT_HEAD(bool_option__short_name); 194 ATF_TEST_CASE_BODY(bool_option__short_name) 195 { 196 const cmdline::bool_option o('f', "force", "Force execution"); 197 ATF_REQUIRE(o.has_short_name()); 198 ATF_REQUIRE_EQ('f', o.short_name()); 199 ATF_REQUIRE_EQ("force", o.long_name()); 200 ATF_REQUIRE_EQ("Force execution", o.description()); 201 ATF_REQUIRE(!o.needs_arg()); 202 } 203 204 205 ATF_TEST_CASE_WITHOUT_HEAD(bool_option__long_name); 206 ATF_TEST_CASE_BODY(bool_option__long_name) 207 { 208 const cmdline::bool_option o("force", "Force execution"); 209 ATF_REQUIRE(!o.has_short_name()); 210 ATF_REQUIRE_EQ("force", o.long_name()); 211 ATF_REQUIRE_EQ("Force execution", o.description()); 212 ATF_REQUIRE(!o.needs_arg()); 213 } 214 215 216 ATF_TEST_CASE_WITHOUT_HEAD(int_option__short_name); 217 ATF_TEST_CASE_BODY(int_option__short_name) 218 { 219 const cmdline::int_option o('p', "int", "The int", "arg", "value"); 220 ATF_REQUIRE(o.has_short_name()); 221 ATF_REQUIRE_EQ('p', o.short_name()); 222 ATF_REQUIRE_EQ("int", o.long_name()); 223 ATF_REQUIRE_EQ("The int", o.description()); 224 ATF_REQUIRE(o.needs_arg()); 225 ATF_REQUIRE_EQ("arg", o.arg_name()); 226 ATF_REQUIRE(o.has_default_value()); 227 ATF_REQUIRE_EQ("value", o.default_value()); 228 } 229 230 231 ATF_TEST_CASE_WITHOUT_HEAD(int_option__long_name); 232 ATF_TEST_CASE_BODY(int_option__long_name) 233 { 234 const cmdline::int_option o("int", "The int", "arg", "value"); 235 ATF_REQUIRE(!o.has_short_name()); 236 ATF_REQUIRE_EQ("int", o.long_name()); 237 ATF_REQUIRE_EQ("The int", o.description()); 238 ATF_REQUIRE(o.needs_arg()); 239 ATF_REQUIRE_EQ("arg", o.arg_name()); 240 ATF_REQUIRE(o.has_default_value()); 241 ATF_REQUIRE_EQ("value", o.default_value()); 242 } 243 244 245 ATF_TEST_CASE_WITHOUT_HEAD(int_option__type); 246 ATF_TEST_CASE_BODY(int_option__type) 247 { 248 const cmdline::int_option o("int", "The int", "arg"); 249 250 o.validate("123"); 251 ATF_REQUIRE_EQ(123, cmdline::int_option::convert("123")); 252 253 o.validate("-567"); 254 ATF_REQUIRE_EQ(-567, cmdline::int_option::convert("-567")); 255 256 ATF_REQUIRE_THROW(cmdline::option_argument_value_error, o.validate("")); 257 ATF_REQUIRE_THROW(cmdline::option_argument_value_error, o.validate("5a")); 258 ATF_REQUIRE_THROW(cmdline::option_argument_value_error, o.validate("a5")); 259 ATF_REQUIRE_THROW(cmdline::option_argument_value_error, o.validate("5 a")); 260 ATF_REQUIRE_THROW(cmdline::option_argument_value_error, o.validate("5.0")); 261 } 262 263 264 ATF_TEST_CASE_WITHOUT_HEAD(list_option__short_name); 265 ATF_TEST_CASE_BODY(list_option__short_name) 266 { 267 const cmdline::list_option o('p', "list", "The list", "arg", "value"); 268 ATF_REQUIRE(o.has_short_name()); 269 ATF_REQUIRE_EQ('p', o.short_name()); 270 ATF_REQUIRE_EQ("list", o.long_name()); 271 ATF_REQUIRE_EQ("The list", o.description()); 272 ATF_REQUIRE(o.needs_arg()); 273 ATF_REQUIRE_EQ("arg", o.arg_name()); 274 ATF_REQUIRE(o.has_default_value()); 275 ATF_REQUIRE_EQ("value", o.default_value()); 276 } 277 278 279 ATF_TEST_CASE_WITHOUT_HEAD(list_option__long_name); 280 ATF_TEST_CASE_BODY(list_option__long_name) 281 { 282 const cmdline::list_option o("list", "The list", "arg", "value"); 283 ATF_REQUIRE(!o.has_short_name()); 284 ATF_REQUIRE_EQ("list", o.long_name()); 285 ATF_REQUIRE_EQ("The list", o.description()); 286 ATF_REQUIRE(o.needs_arg()); 287 ATF_REQUIRE_EQ("arg", o.arg_name()); 288 ATF_REQUIRE(o.has_default_value()); 289 ATF_REQUIRE_EQ("value", o.default_value()); 290 } 291 292 293 ATF_TEST_CASE_WITHOUT_HEAD(list_option__type); 294 ATF_TEST_CASE_BODY(list_option__type) 295 { 296 const cmdline::list_option o("list", "The list", "arg"); 297 298 o.validate(""); 299 { 300 const cmdline::list_option::option_type words = 301 cmdline::list_option::convert(""); 302 ATF_REQUIRE(words.empty()); 303 } 304 305 o.validate("foo"); 306 { 307 const cmdline::list_option::option_type words = 308 cmdline::list_option::convert("foo"); 309 ATF_REQUIRE_EQ(1, words.size()); 310 ATF_REQUIRE_EQ("foo", words[0]); 311 } 312 313 o.validate("foo,bar,baz"); 314 { 315 const cmdline::list_option::option_type words = 316 cmdline::list_option::convert("foo,bar,baz"); 317 ATF_REQUIRE_EQ(3, words.size()); 318 ATF_REQUIRE_EQ("foo", words[0]); 319 ATF_REQUIRE_EQ("bar", words[1]); 320 ATF_REQUIRE_EQ("baz", words[2]); 321 } 322 323 o.validate("foo,bar,"); 324 { 325 const cmdline::list_option::option_type words = 326 cmdline::list_option::convert("foo,bar,"); 327 ATF_REQUIRE_EQ(3, words.size()); 328 ATF_REQUIRE_EQ("foo", words[0]); 329 ATF_REQUIRE_EQ("bar", words[1]); 330 ATF_REQUIRE_EQ("", words[2]); 331 } 332 333 o.validate(",foo,bar"); 334 { 335 const cmdline::list_option::option_type words = 336 cmdline::list_option::convert(",foo,bar"); 337 ATF_REQUIRE_EQ(3, words.size()); 338 ATF_REQUIRE_EQ("", words[0]); 339 ATF_REQUIRE_EQ("foo", words[1]); 340 ATF_REQUIRE_EQ("bar", words[2]); 341 } 342 343 o.validate("foo,,bar"); 344 { 345 const cmdline::list_option::option_type words = 346 cmdline::list_option::convert("foo,,bar"); 347 ATF_REQUIRE_EQ(3, words.size()); 348 ATF_REQUIRE_EQ("foo", words[0]); 349 ATF_REQUIRE_EQ("", words[1]); 350 ATF_REQUIRE_EQ("bar", words[2]); 351 } 352 } 353 354 355 ATF_TEST_CASE_WITHOUT_HEAD(path_option__short_name); 356 ATF_TEST_CASE_BODY(path_option__short_name) 357 { 358 const cmdline::path_option o('p', "path", "The path", "arg", "value"); 359 ATF_REQUIRE(o.has_short_name()); 360 ATF_REQUIRE_EQ('p', o.short_name()); 361 ATF_REQUIRE_EQ("path", o.long_name()); 362 ATF_REQUIRE_EQ("The path", o.description()); 363 ATF_REQUIRE(o.needs_arg()); 364 ATF_REQUIRE_EQ("arg", o.arg_name()); 365 ATF_REQUIRE(o.has_default_value()); 366 ATF_REQUIRE_EQ("value", o.default_value()); 367 } 368 369 370 ATF_TEST_CASE_WITHOUT_HEAD(path_option__long_name); 371 ATF_TEST_CASE_BODY(path_option__long_name) 372 { 373 const cmdline::path_option o("path", "The path", "arg", "value"); 374 ATF_REQUIRE(!o.has_short_name()); 375 ATF_REQUIRE_EQ("path", o.long_name()); 376 ATF_REQUIRE_EQ("The path", o.description()); 377 ATF_REQUIRE(o.needs_arg()); 378 ATF_REQUIRE_EQ("arg", o.arg_name()); 379 ATF_REQUIRE(o.has_default_value()); 380 ATF_REQUIRE_EQ("value", o.default_value()); 381 } 382 383 384 ATF_TEST_CASE_WITHOUT_HEAD(path_option__type); 385 ATF_TEST_CASE_BODY(path_option__type) 386 { 387 const cmdline::path_option o("path", "The path", "arg"); 388 389 o.validate("/some/path"); 390 391 try { 392 o.validate(""); 393 fail("option_argument_value_error not raised"); 394 } catch (const cmdline::option_argument_value_error& e) { 395 // Expected; ignore. 396 } 397 398 const cmdline::path_option::option_type path = 399 cmdline::path_option::convert("/foo/bar"); 400 ATF_REQUIRE_EQ("bar", path.leaf_name()); // Ensure valid type. 401 } 402 403 404 ATF_TEST_CASE_WITHOUT_HEAD(property_option__short_name); 405 ATF_TEST_CASE_BODY(property_option__short_name) 406 { 407 const cmdline::property_option o('p', "property", "The property", "a=b"); 408 ATF_REQUIRE(o.has_short_name()); 409 ATF_REQUIRE_EQ('p', o.short_name()); 410 ATF_REQUIRE_EQ("property", o.long_name()); 411 ATF_REQUIRE_EQ("The property", o.description()); 412 ATF_REQUIRE(o.needs_arg()); 413 ATF_REQUIRE_EQ("a=b", o.arg_name()); 414 ATF_REQUIRE(!o.has_default_value()); 415 } 416 417 418 ATF_TEST_CASE_WITHOUT_HEAD(property_option__long_name); 419 ATF_TEST_CASE_BODY(property_option__long_name) 420 { 421 const cmdline::property_option o("property", "The property", "a=b"); 422 ATF_REQUIRE(!o.has_short_name()); 423 ATF_REQUIRE_EQ("property", o.long_name()); 424 ATF_REQUIRE_EQ("The property", o.description()); 425 ATF_REQUIRE(o.needs_arg()); 426 ATF_REQUIRE_EQ("a=b", o.arg_name()); 427 ATF_REQUIRE(!o.has_default_value()); 428 } 429 430 431 ATF_TEST_CASE_WITHOUT_HEAD(property_option__type); 432 ATF_TEST_CASE_BODY(property_option__type) 433 { 434 typedef std::pair< std::string, std::string > string_pair; 435 const cmdline::property_option o("property", "The property", "a=b"); 436 437 o.validate("foo=bar"); 438 ATF_REQUIRE(string_pair("foo", "bar") == 439 cmdline::property_option::convert("foo=bar")); 440 441 o.validate(" foo = bar baz"); 442 ATF_REQUIRE(string_pair(" foo ", " bar baz") == 443 cmdline::property_option::convert(" foo = bar baz")); 444 445 ATF_REQUIRE_THROW(cmdline::option_argument_value_error, o.validate("")); 446 ATF_REQUIRE_THROW(cmdline::option_argument_value_error, o.validate("=")); 447 ATF_REQUIRE_THROW(cmdline::option_argument_value_error, o.validate("a=")); 448 ATF_REQUIRE_THROW(cmdline::option_argument_value_error, o.validate("=b")); 449 } 450 451 452 ATF_TEST_CASE_WITHOUT_HEAD(string_option__short_name); 453 ATF_TEST_CASE_BODY(string_option__short_name) 454 { 455 const cmdline::string_option o('p', "string", "The string", "arg", "value"); 456 ATF_REQUIRE(o.has_short_name()); 457 ATF_REQUIRE_EQ('p', o.short_name()); 458 ATF_REQUIRE_EQ("string", o.long_name()); 459 ATF_REQUIRE_EQ("The string", o.description()); 460 ATF_REQUIRE(o.needs_arg()); 461 ATF_REQUIRE_EQ("arg", o.arg_name()); 462 ATF_REQUIRE(o.has_default_value()); 463 ATF_REQUIRE_EQ("value", o.default_value()); 464 } 465 466 467 ATF_TEST_CASE_WITHOUT_HEAD(string_option__long_name); 468 ATF_TEST_CASE_BODY(string_option__long_name) 469 { 470 const cmdline::string_option o("string", "The string", "arg", "value"); 471 ATF_REQUIRE(!o.has_short_name()); 472 ATF_REQUIRE_EQ("string", o.long_name()); 473 ATF_REQUIRE_EQ("The string", o.description()); 474 ATF_REQUIRE(o.needs_arg()); 475 ATF_REQUIRE_EQ("arg", o.arg_name()); 476 ATF_REQUIRE(o.has_default_value()); 477 ATF_REQUIRE_EQ("value", o.default_value()); 478 } 479 480 481 ATF_TEST_CASE_WITHOUT_HEAD(string_option__type); 482 ATF_TEST_CASE_BODY(string_option__type) 483 { 484 const cmdline::string_option o("string", "The string", "foo"); 485 486 o.validate(""); 487 o.validate("some string"); 488 489 const cmdline::string_option::option_type string = 490 cmdline::string_option::convert("foo"); 491 ATF_REQUIRE_EQ(3, string.length()); // Ensure valid type. 492 } 493 494 495 ATF_INIT_TEST_CASES(tcs) 496 { 497 ATF_ADD_TEST_CASE(tcs, base_option__short_name__no_arg); 498 ATF_ADD_TEST_CASE(tcs, base_option__short_name__with_arg__no_default); 499 ATF_ADD_TEST_CASE(tcs, base_option__short_name__with_arg__with_default); 500 ATF_ADD_TEST_CASE(tcs, base_option__long_name__no_arg); 501 ATF_ADD_TEST_CASE(tcs, base_option__long_name__with_arg__no_default); 502 ATF_ADD_TEST_CASE(tcs, base_option__long_name__with_arg__with_default); 503 504 ATF_ADD_TEST_CASE(tcs, bool_option__short_name); 505 ATF_ADD_TEST_CASE(tcs, bool_option__long_name); 506 507 ATF_ADD_TEST_CASE(tcs, int_option__short_name); 508 ATF_ADD_TEST_CASE(tcs, int_option__long_name); 509 ATF_ADD_TEST_CASE(tcs, int_option__type); 510 511 ATF_ADD_TEST_CASE(tcs, list_option__short_name); 512 ATF_ADD_TEST_CASE(tcs, list_option__long_name); 513 ATF_ADD_TEST_CASE(tcs, list_option__type); 514 515 ATF_ADD_TEST_CASE(tcs, path_option__short_name); 516 ATF_ADD_TEST_CASE(tcs, path_option__long_name); 517 ATF_ADD_TEST_CASE(tcs, path_option__type); 518 519 ATF_ADD_TEST_CASE(tcs, property_option__short_name); 520 ATF_ADD_TEST_CASE(tcs, property_option__long_name); 521 ATF_ADD_TEST_CASE(tcs, property_option__type); 522 523 ATF_ADD_TEST_CASE(tcs, string_option__short_name); 524 ATF_ADD_TEST_CASE(tcs, string_option__long_name); 525 ATF_ADD_TEST_CASE(tcs, string_option__type); 526 } 527