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