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 37namespace cmdline = utils::cmdline; 38 39namespace { 40 41 42/// Simple string-based option type for testing purposes. 43class mock_option : public cmdline::base_option { 44public: 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 104ATF_TEST_CASE_WITHOUT_HEAD(base_option__short_name__no_arg); 105ATF_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 118ATF_TEST_CASE_WITHOUT_HEAD(base_option__short_name__with_arg__no_default); 119ATF_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 134ATF_TEST_CASE_WITHOUT_HEAD(base_option__short_name__with_arg__with_default); 135ATF_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 152ATF_TEST_CASE_WITHOUT_HEAD(base_option__long_name__no_arg); 153ATF_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 164ATF_TEST_CASE_WITHOUT_HEAD(base_option__long_name__with_arg__no_default); 165ATF_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 178ATF_TEST_CASE_WITHOUT_HEAD(base_option__long_name__with_arg__with_default); 179ATF_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 193ATF_TEST_CASE_WITHOUT_HEAD(bool_option__short_name); 194ATF_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 205ATF_TEST_CASE_WITHOUT_HEAD(bool_option__long_name); 206ATF_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 216ATF_TEST_CASE_WITHOUT_HEAD(int_option__short_name); 217ATF_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 231ATF_TEST_CASE_WITHOUT_HEAD(int_option__long_name); 232ATF_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 245ATF_TEST_CASE_WITHOUT_HEAD(int_option__type); 246ATF_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 264ATF_TEST_CASE_WITHOUT_HEAD(list_option__short_name); 265ATF_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 279ATF_TEST_CASE_WITHOUT_HEAD(list_option__long_name); 280ATF_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 293ATF_TEST_CASE_WITHOUT_HEAD(list_option__type); 294ATF_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 355ATF_TEST_CASE_WITHOUT_HEAD(path_option__short_name); 356ATF_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 370ATF_TEST_CASE_WITHOUT_HEAD(path_option__long_name); 371ATF_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 384ATF_TEST_CASE_WITHOUT_HEAD(path_option__type); 385ATF_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 404ATF_TEST_CASE_WITHOUT_HEAD(property_option__short_name); 405ATF_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 418ATF_TEST_CASE_WITHOUT_HEAD(property_option__long_name); 419ATF_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 431ATF_TEST_CASE_WITHOUT_HEAD(property_option__type); 432ATF_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 452ATF_TEST_CASE_WITHOUT_HEAD(string_option__short_name); 453ATF_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 467ATF_TEST_CASE_WITHOUT_HEAD(string_option__long_name); 468ATF_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 481ATF_TEST_CASE_WITHOUT_HEAD(string_option__type); 482ATF_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 495ATF_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