Home | History | Annotate | Download | only in cmdline
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "cmdline_parser.h"
     18 #include "runtime/runtime_options.h"
     19 #include "runtime/parsed_options.h"
     20 
     21 #include "utils.h"
     22 #include <numeric>
     23 #include "gtest/gtest.h"
     24 #include "runtime/experimental_flags.h"
     25 #include "runtime/runtime.h"
     26 
     27 #define EXPECT_NULL(expected) EXPECT_EQ(reinterpret_cast<const void*>(expected), \
     28                                         reinterpret_cast<void*>(nullptr));
     29 
     30 namespace art {
     31   bool UsuallyEquals(double expected, double actual);
     32 
     33   // This has a gtest dependency, which is why it's in the gtest only.
     34   bool operator==(const ProfileSaverOptions& lhs, const ProfileSaverOptions& rhs) {
     35     return lhs.enabled_ == rhs.enabled_ &&
     36         lhs.min_save_period_ms_ == rhs.min_save_period_ms_ &&
     37         lhs.save_resolved_classes_delay_ms_ == rhs.save_resolved_classes_delay_ms_ &&
     38         lhs.hot_startup_method_samples_ == rhs.hot_startup_method_samples_ &&
     39         lhs.min_methods_to_save_ == rhs.min_methods_to_save_ &&
     40         lhs.min_classes_to_save_ == rhs.min_classes_to_save_ &&
     41         lhs.min_notification_before_wake_ == rhs.min_notification_before_wake_ &&
     42         lhs.max_notification_before_wake_ == rhs.max_notification_before_wake_;
     43   }
     44 
     45   bool UsuallyEquals(double expected, double actual) {
     46     using FloatingPoint = ::testing::internal::FloatingPoint<double>;
     47 
     48     FloatingPoint exp(expected);
     49     FloatingPoint act(actual);
     50 
     51     // Compare with ULPs instead of comparing with ==
     52     return exp.AlmostEquals(act);
     53   }
     54 
     55   template <typename T>
     56   bool UsuallyEquals(const T& expected, const T& actual,
     57                      typename std::enable_if<
     58                          detail::SupportsEqualityOperator<T>::value>::type* = 0) {
     59     return expected == actual;
     60   }
     61 
     62   // Try to use memcmp to compare simple plain-old-data structs.
     63   //
     64   // This should *not* generate false positives, but it can generate false negatives.
     65   // This will mostly work except for fields like float which can have different bit patterns
     66   // that are nevertheless equal.
     67   // If a test is failing because the structs aren't "equal" when they really are
     68   // then it's recommended to implement operator== for it instead.
     69   template <typename T, typename ... Ignore>
     70   bool UsuallyEquals(const T& expected, const T& actual,
     71                      const Ignore& ... more ATTRIBUTE_UNUSED,
     72                      typename std::enable_if<std::is_pod<T>::value>::type* = 0,
     73                      typename std::enable_if<!detail::SupportsEqualityOperator<T>::value>::type* = 0
     74                      ) {
     75     return memcmp(std::addressof(expected), std::addressof(actual), sizeof(T)) == 0;
     76   }
     77 
     78   bool UsuallyEquals(const XGcOption& expected, const XGcOption& actual) {
     79     return memcmp(std::addressof(expected), std::addressof(actual), sizeof(expected)) == 0;
     80   }
     81 
     82   bool UsuallyEquals(const char* expected, const std::string& actual) {
     83     return std::string(expected) == actual;
     84   }
     85 
     86   template <typename TMap, typename TKey, typename T>
     87   ::testing::AssertionResult IsExpectedKeyValue(const T& expected,
     88                                                 const TMap& map,
     89                                                 const TKey& key) {
     90     auto* actual = map.Get(key);
     91     if (actual != nullptr) {
     92       if (!UsuallyEquals(expected, *actual)) {
     93         return ::testing::AssertionFailure()
     94           << "expected " << detail::ToStringAny(expected) << " but got "
     95           << detail::ToStringAny(*actual);
     96       }
     97       return ::testing::AssertionSuccess();
     98     }
     99 
    100     return ::testing::AssertionFailure() << "key was not in the map";
    101   }
    102 
    103   template <typename TMap, typename TKey, typename T>
    104   ::testing::AssertionResult IsExpectedDefaultKeyValue(const T& expected,
    105                                                        const TMap& map,
    106                                                        const TKey& key) {
    107     const T& actual = map.GetOrDefault(key);
    108     if (!UsuallyEquals(expected, actual)) {
    109       return ::testing::AssertionFailure()
    110           << "expected " << detail::ToStringAny(expected) << " but got "
    111           << detail::ToStringAny(actual);
    112      }
    113     return ::testing::AssertionSuccess();
    114   }
    115 
    116 class CmdlineParserTest : public ::testing::Test {
    117  public:
    118   CmdlineParserTest() = default;
    119   ~CmdlineParserTest() = default;
    120 
    121  protected:
    122   using M = RuntimeArgumentMap;
    123   using RuntimeParser = ParsedOptions::RuntimeParser;
    124 
    125   static void SetUpTestCase() {
    126     art::InitLogging(nullptr, art::Runtime::Abort);  // argv = null
    127   }
    128 
    129   virtual void SetUp() {
    130     parser_ = ParsedOptions::MakeParser(false);  // do not ignore unrecognized options
    131   }
    132 
    133   static ::testing::AssertionResult IsResultSuccessful(const CmdlineResult& result) {
    134     if (result.IsSuccess()) {
    135       return ::testing::AssertionSuccess();
    136     } else {
    137       return ::testing::AssertionFailure()
    138         << result.GetStatus() << " with: " << result.GetMessage();
    139     }
    140   }
    141 
    142   static ::testing::AssertionResult IsResultFailure(const CmdlineResult& result,
    143                                                     CmdlineResult::Status failure_status) {
    144     if (result.IsSuccess()) {
    145       return ::testing::AssertionFailure() << " got success but expected failure: "
    146           << failure_status;
    147     } else if (result.GetStatus() == failure_status) {
    148       return ::testing::AssertionSuccess();
    149     }
    150 
    151     return ::testing::AssertionFailure() << " expected failure " << failure_status
    152         << " but got " << result.GetStatus();
    153   }
    154 
    155   std::unique_ptr<RuntimeParser> parser_;
    156 };
    157 
    158 #define EXPECT_KEY_EXISTS(map, key) EXPECT_TRUE((map).Exists(key))
    159 #define EXPECT_KEY_VALUE(map, key, expected) EXPECT_TRUE(IsExpectedKeyValue(expected, map, key))
    160 #define EXPECT_DEFAULT_KEY_VALUE(map, key, expected) EXPECT_TRUE(IsExpectedDefaultKeyValue(expected, map, key))
    161 
    162 #define _EXPECT_SINGLE_PARSE_EMPTY_SUCCESS(argv)              \
    163   do {                                                        \
    164     EXPECT_TRUE(IsResultSuccessful(parser_->Parse(argv)));    \
    165     EXPECT_EQ(0u, parser_->GetArgumentsMap().Size());         \
    166 
    167 #define EXPECT_SINGLE_PARSE_EMPTY_SUCCESS(argv)               \
    168   _EXPECT_SINGLE_PARSE_EMPTY_SUCCESS(argv);                   \
    169   } while (false)
    170 
    171 #define EXPECT_SINGLE_PARSE_DEFAULT_VALUE(expected, argv, key)\
    172   _EXPECT_SINGLE_PARSE_EMPTY_SUCCESS(argv);                   \
    173     RuntimeArgumentMap args = parser_->ReleaseArgumentsMap(); \
    174     EXPECT_DEFAULT_KEY_VALUE(args, key, expected);            \
    175   } while (false)                                             // NOLINT [readability/namespace] [5]
    176 
    177 #define _EXPECT_SINGLE_PARSE_EXISTS(argv, key)                \
    178   do {                                                        \
    179     EXPECT_TRUE(IsResultSuccessful(parser_->Parse(argv)));    \
    180     RuntimeArgumentMap args = parser_->ReleaseArgumentsMap(); \
    181     EXPECT_EQ(1u, args.Size());                               \
    182     EXPECT_KEY_EXISTS(args, key);                             \
    183 
    184 #define EXPECT_SINGLE_PARSE_EXISTS(argv, key)                 \
    185     _EXPECT_SINGLE_PARSE_EXISTS(argv, key);                   \
    186   } while (false)
    187 
    188 #define EXPECT_SINGLE_PARSE_VALUE(expected, argv, key)        \
    189     _EXPECT_SINGLE_PARSE_EXISTS(argv, key);                   \
    190     EXPECT_KEY_VALUE(args, key, expected);                    \
    191   } while (false)                                             // NOLINT [readability/namespace] [5]
    192 
    193 #define EXPECT_SINGLE_PARSE_VALUE_STR(expected, argv, key)    \
    194   EXPECT_SINGLE_PARSE_VALUE(std::string(expected), argv, key)
    195 
    196 #define EXPECT_SINGLE_PARSE_FAIL(argv, failure_status)         \
    197     do {                                                       \
    198       EXPECT_TRUE(IsResultFailure(parser_->Parse(argv), failure_status));\
    199       RuntimeArgumentMap args = parser_->ReleaseArgumentsMap();\
    200       EXPECT_EQ(0u, args.Size());                              \
    201     } while (false)
    202 
    203 TEST_F(CmdlineParserTest, TestSimpleSuccesses) {
    204   auto& parser = *parser_;
    205 
    206   EXPECT_LT(0u, parser.CountDefinedArguments());
    207 
    208   {
    209     // Test case 1: No command line arguments
    210     EXPECT_TRUE(IsResultSuccessful(parser.Parse("")));
    211     RuntimeArgumentMap args = parser.ReleaseArgumentsMap();
    212     EXPECT_EQ(0u, args.Size());
    213   }
    214 
    215   EXPECT_SINGLE_PARSE_EXISTS("-Xzygote", M::Zygote);
    216   EXPECT_SINGLE_PARSE_VALUE_STR("/hello/world", "-Xbootclasspath:/hello/world", M::BootClassPath);
    217   EXPECT_SINGLE_PARSE_VALUE("/hello/world", "-Xbootclasspath:/hello/world", M::BootClassPath);
    218   EXPECT_SINGLE_PARSE_VALUE(Memory<1>(234), "-Xss234", M::StackSize);
    219   EXPECT_SINGLE_PARSE_VALUE(MemoryKiB(1234*MB), "-Xms1234m", M::MemoryInitialSize);
    220   EXPECT_SINGLE_PARSE_VALUE(true, "-XX:EnableHSpaceCompactForOOM", M::EnableHSpaceCompactForOOM);
    221   EXPECT_SINGLE_PARSE_VALUE(false, "-XX:DisableHSpaceCompactForOOM", M::EnableHSpaceCompactForOOM);
    222   EXPECT_SINGLE_PARSE_VALUE(0.5, "-XX:HeapTargetUtilization=0.5", M::HeapTargetUtilization);
    223   EXPECT_SINGLE_PARSE_VALUE(5u, "-XX:ParallelGCThreads=5", M::ParallelGCThreads);
    224   EXPECT_SINGLE_PARSE_EXISTS("-Xno-dex-file-fallback", M::NoDexFileFallback);
    225 }  // TEST_F
    226 
    227 TEST_F(CmdlineParserTest, TestSimpleFailures) {
    228   // Test argument is unknown to the parser
    229   EXPECT_SINGLE_PARSE_FAIL("abcdefg^%@#*(@#", CmdlineResult::kUnknown);
    230   // Test value map substitution fails
    231   EXPECT_SINGLE_PARSE_FAIL("-Xverify:whatever", CmdlineResult::kFailure);
    232   // Test value type parsing failures
    233   EXPECT_SINGLE_PARSE_FAIL("-Xsswhatever", CmdlineResult::kFailure);  // invalid memory value
    234   EXPECT_SINGLE_PARSE_FAIL("-Xms123", CmdlineResult::kFailure);       // memory value too small
    235   EXPECT_SINGLE_PARSE_FAIL("-XX:HeapTargetUtilization=0.0", CmdlineResult::kOutOfRange);  // toosmal
    236   EXPECT_SINGLE_PARSE_FAIL("-XX:HeapTargetUtilization=2.0", CmdlineResult::kOutOfRange);  // toolarg
    237   EXPECT_SINGLE_PARSE_FAIL("-XX:ParallelGCThreads=-5", CmdlineResult::kOutOfRange);  // too small
    238   EXPECT_SINGLE_PARSE_FAIL("-Xgc:blablabla", CmdlineResult::kUsage);  // not a valid suboption
    239 }  // TEST_F
    240 
    241 TEST_F(CmdlineParserTest, TestLogVerbosity) {
    242   {
    243     const char* log_args = "-verbose:"
    244         "class,compiler,gc,heap,jdwp,jni,monitor,profiler,signals,simulator,startup,"
    245         "third-party-jni,threads,verifier";
    246 
    247     LogVerbosity log_verbosity = LogVerbosity();
    248     log_verbosity.class_linker = true;
    249     log_verbosity.compiler = true;
    250     log_verbosity.gc = true;
    251     log_verbosity.heap = true;
    252     log_verbosity.jdwp = true;
    253     log_verbosity.jni = true;
    254     log_verbosity.monitor = true;
    255     log_verbosity.profiler = true;
    256     log_verbosity.signals = true;
    257     log_verbosity.simulator = true;
    258     log_verbosity.startup = true;
    259     log_verbosity.third_party_jni = true;
    260     log_verbosity.threads = true;
    261     log_verbosity.verifier = true;
    262 
    263     EXPECT_SINGLE_PARSE_VALUE(log_verbosity, log_args, M::Verbose);
    264   }
    265 
    266   {
    267     const char* log_args = "-verbose:"
    268         "class,compiler,gc,heap,jdwp,jni,monitor";
    269 
    270     LogVerbosity log_verbosity = LogVerbosity();
    271     log_verbosity.class_linker = true;
    272     log_verbosity.compiler = true;
    273     log_verbosity.gc = true;
    274     log_verbosity.heap = true;
    275     log_verbosity.jdwp = true;
    276     log_verbosity.jni = true;
    277     log_verbosity.monitor = true;
    278 
    279     EXPECT_SINGLE_PARSE_VALUE(log_verbosity, log_args, M::Verbose);
    280   }
    281 
    282   EXPECT_SINGLE_PARSE_FAIL("-verbose:blablabla", CmdlineResult::kUsage);  // invalid verbose opt
    283 
    284   {
    285     const char* log_args = "-verbose:deopt";
    286     LogVerbosity log_verbosity = LogVerbosity();
    287     log_verbosity.deopt = true;
    288     EXPECT_SINGLE_PARSE_VALUE(log_verbosity, log_args, M::Verbose);
    289   }
    290 
    291   {
    292     const char* log_args = "-verbose:collector";
    293     LogVerbosity log_verbosity = LogVerbosity();
    294     log_verbosity.collector = true;
    295     EXPECT_SINGLE_PARSE_VALUE(log_verbosity, log_args, M::Verbose);
    296   }
    297 
    298   {
    299     const char* log_args = "-verbose:oat";
    300     LogVerbosity log_verbosity = LogVerbosity();
    301     log_verbosity.oat = true;
    302     EXPECT_SINGLE_PARSE_VALUE(log_verbosity, log_args, M::Verbose);
    303   }
    304 
    305   {
    306     const char* log_args = "-verbose:dex";
    307     LogVerbosity log_verbosity = LogVerbosity();
    308     log_verbosity.dex = true;
    309     EXPECT_SINGLE_PARSE_VALUE(log_verbosity, log_args, M::Verbose);
    310   }
    311 }  // TEST_F
    312 
    313 // TODO: Enable this b/19274810
    314 TEST_F(CmdlineParserTest, DISABLED_TestXGcOption) {
    315   /*
    316    * Test success
    317    */
    318   {
    319     XGcOption option_all_true{};  // NOLINT [readability/braces] [4]
    320     option_all_true.collector_type_ = gc::CollectorType::kCollectorTypeCMS;
    321     option_all_true.verify_pre_gc_heap_ = true;
    322     option_all_true.verify_pre_sweeping_heap_ = true;
    323     option_all_true.verify_post_gc_heap_ = true;
    324     option_all_true.verify_pre_gc_rosalloc_ = true;
    325     option_all_true.verify_pre_sweeping_rosalloc_ = true;
    326     option_all_true.verify_post_gc_rosalloc_ = true;
    327 
    328     const char * xgc_args_all_true = "-Xgc:concurrent,"
    329         "preverify,presweepingverify,postverify,"
    330         "preverify_rosalloc,presweepingverify_rosalloc,"
    331         "postverify_rosalloc,precise,"
    332         "verifycardtable";
    333 
    334     EXPECT_SINGLE_PARSE_VALUE(option_all_true, xgc_args_all_true, M::GcOption);
    335 
    336     XGcOption option_all_false{};  // NOLINT [readability/braces] [4]
    337     option_all_false.collector_type_ = gc::CollectorType::kCollectorTypeMS;
    338     option_all_false.verify_pre_gc_heap_ = false;
    339     option_all_false.verify_pre_sweeping_heap_ = false;
    340     option_all_false.verify_post_gc_heap_ = false;
    341     option_all_false.verify_pre_gc_rosalloc_ = false;
    342     option_all_false.verify_pre_sweeping_rosalloc_ = false;
    343     option_all_false.verify_post_gc_rosalloc_ = false;
    344 
    345     const char* xgc_args_all_false = "-Xgc:nonconcurrent,"
    346         "nopreverify,nopresweepingverify,nopostverify,nopreverify_rosalloc,"
    347         "nopresweepingverify_rosalloc,nopostverify_rosalloc,noprecise,noverifycardtable";
    348 
    349     EXPECT_SINGLE_PARSE_VALUE(option_all_false, xgc_args_all_false, M::GcOption);
    350 
    351     XGcOption option_all_default{};  // NOLINT [readability/braces] [4]
    352 
    353     const char* xgc_args_blank = "-Xgc:";
    354     EXPECT_SINGLE_PARSE_VALUE(option_all_default, xgc_args_blank, M::GcOption);
    355   }
    356 
    357   /*
    358    * Test failures
    359    */
    360   EXPECT_SINGLE_PARSE_FAIL("-Xgc:blablabla", CmdlineResult::kUsage);  // invalid Xgc opt
    361 }  // TEST_F
    362 
    363 /*
    364  * {"-Xrunjdwp:_", "-agentlib:jdwp=_"}
    365  */
    366 TEST_F(CmdlineParserTest, TestJdwpOptions) {
    367   /*
    368    * Test success
    369    */
    370   {
    371     /*
    372      * "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n"
    373      */
    374     JDWP::JdwpOptions opt = JDWP::JdwpOptions();
    375     opt.transport = JDWP::JdwpTransportType::kJdwpTransportSocket;
    376     opt.port = 8000;
    377     opt.server = true;
    378 
    379     const char *opt_args = "-Xrunjdwp:transport=dt_socket,address=8000,server=y";
    380 
    381     EXPECT_SINGLE_PARSE_VALUE(opt, opt_args, M::JdwpOptions);
    382   }
    383 
    384   {
    385     /*
    386      * "Example: -agentlib:jdwp=transport=dt_socket,address=localhost:6500,server=n\n");
    387      */
    388     JDWP::JdwpOptions opt = JDWP::JdwpOptions();
    389     opt.transport = JDWP::JdwpTransportType::kJdwpTransportSocket;
    390     opt.host = "localhost";
    391     opt.port = 6500;
    392     opt.server = false;
    393 
    394     const char *opt_args = "-agentlib:jdwp=transport=dt_socket,address=localhost:6500,server=n";
    395 
    396     EXPECT_SINGLE_PARSE_VALUE(opt, opt_args, M::JdwpOptions);
    397   }
    398 
    399   /*
    400    * Test failures
    401    */
    402   EXPECT_SINGLE_PARSE_FAIL("-Xrunjdwp:help", CmdlineResult::kUsage);  // usage for help only
    403   EXPECT_SINGLE_PARSE_FAIL("-Xrunjdwp:blabla", CmdlineResult::kFailure);  // invalid subarg
    404   EXPECT_SINGLE_PARSE_FAIL("-agentlib:jdwp=help", CmdlineResult::kUsage);  // usage for help only
    405   EXPECT_SINGLE_PARSE_FAIL("-agentlib:jdwp=blabla", CmdlineResult::kFailure);  // invalid subarg
    406 }  // TEST_F
    407 
    408 /*
    409  * -D_ -D_ -D_ ...
    410  */
    411 TEST_F(CmdlineParserTest, TestPropertiesList) {
    412   /*
    413    * Test successes
    414    */
    415   {
    416     std::vector<std::string> opt = {"hello"};
    417 
    418     EXPECT_SINGLE_PARSE_VALUE(opt, "-Dhello", M::PropertiesList);
    419   }
    420 
    421   {
    422     std::vector<std::string> opt = {"hello", "world"};
    423 
    424     EXPECT_SINGLE_PARSE_VALUE(opt, "-Dhello -Dworld", M::PropertiesList);
    425   }
    426 
    427   {
    428     std::vector<std::string> opt = {"one", "two", "three"};
    429 
    430     EXPECT_SINGLE_PARSE_VALUE(opt, "-Done -Dtwo -Dthree", M::PropertiesList);
    431   }
    432 }  // TEST_F
    433 
    434 /*
    435 * -Xcompiler-option foo -Xcompiler-option bar ...
    436 */
    437 TEST_F(CmdlineParserTest, TestCompilerOption) {
    438  /*
    439   * Test successes
    440   */
    441   {
    442     std::vector<std::string> opt = {"hello"};
    443     EXPECT_SINGLE_PARSE_VALUE(opt, "-Xcompiler-option hello", M::CompilerOptions);
    444   }
    445 
    446   {
    447     std::vector<std::string> opt = {"hello", "world"};
    448     EXPECT_SINGLE_PARSE_VALUE(opt,
    449                               "-Xcompiler-option hello -Xcompiler-option world",
    450                               M::CompilerOptions);
    451   }
    452 
    453   {
    454     std::vector<std::string> opt = {"one", "two", "three"};
    455     EXPECT_SINGLE_PARSE_VALUE(opt,
    456                               "-Xcompiler-option one -Xcompiler-option two -Xcompiler-option three",
    457                               M::CompilerOptions);
    458   }
    459 }  // TEST_F
    460 
    461 /*
    462 * -Xjit, -Xnojit, -Xjitcodecachesize, Xjitcompilethreshold
    463 */
    464 TEST_F(CmdlineParserTest, TestJitOptions) {
    465  /*
    466   * Test successes
    467   */
    468   {
    469     EXPECT_SINGLE_PARSE_VALUE(true, "-Xusejit:true", M::UseJitCompilation);
    470     EXPECT_SINGLE_PARSE_VALUE(false, "-Xusejit:false", M::UseJitCompilation);
    471   }
    472   {
    473     EXPECT_SINGLE_PARSE_VALUE(
    474         MemoryKiB(16 * KB), "-Xjitinitialsize:16K", M::JITCodeCacheInitialCapacity);
    475     EXPECT_SINGLE_PARSE_VALUE(
    476         MemoryKiB(16 * MB), "-Xjitmaxsize:16M", M::JITCodeCacheMaxCapacity);
    477   }
    478   {
    479     EXPECT_SINGLE_PARSE_VALUE(12345u, "-Xjitthreshold:12345", M::JITCompileThreshold);
    480   }
    481 }  // TEST_F
    482 
    483 /*
    484 * -Xps-*
    485 */
    486 TEST_F(CmdlineParserTest, ProfileSaverOptions) {
    487   ProfileSaverOptions opt = ProfileSaverOptions(true, 1, 2, 3, 4, 5, 6, 7, "abc", true);
    488 
    489   EXPECT_SINGLE_PARSE_VALUE(opt,
    490                             "-Xjitsaveprofilinginfo "
    491                             "-Xps-min-save-period-ms:1 "
    492                             "-Xps-save-resolved-classes-delay-ms:2 "
    493                             "-Xps-hot-startup-method-samples:3 "
    494                             "-Xps-min-methods-to-save:4 "
    495                             "-Xps-min-classes-to-save:5 "
    496                             "-Xps-min-notification-before-wake:6 "
    497                             "-Xps-max-notification-before-wake:7 "
    498                             "-Xps-profile-path:abc "
    499                             "-Xps-profile-boot-class-path",
    500                             M::ProfileSaverOpts);
    501 }  // TEST_F
    502 
    503 /* -Xexperimental:_ */
    504 TEST_F(CmdlineParserTest, TestExperimentalFlags) {
    505   // Default
    506   EXPECT_SINGLE_PARSE_DEFAULT_VALUE(ExperimentalFlags::kNone,
    507                                     "",
    508                                     M::Experimental);
    509 
    510   // Disabled explicitly
    511   EXPECT_SINGLE_PARSE_VALUE(ExperimentalFlags::kNone,
    512                             "-Xexperimental:none",
    513                             M::Experimental);
    514 }
    515 
    516 // -Xverify:_
    517 TEST_F(CmdlineParserTest, TestVerify) {
    518   EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kNone,     "-Xverify:none",     M::Verify);
    519   EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kEnable,   "-Xverify:remote",   M::Verify);
    520   EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kEnable,   "-Xverify:all",      M::Verify);
    521   EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kSoftFail, "-Xverify:softfail", M::Verify);
    522 }
    523 
    524 TEST_F(CmdlineParserTest, TestIgnoreUnrecognized) {
    525   RuntimeParser::Builder parserBuilder;
    526 
    527   parserBuilder
    528       .Define("-help")
    529           .IntoKey(M::Help)
    530       .IgnoreUnrecognized(true);
    531 
    532   parser_.reset(new RuntimeParser(parserBuilder.Build()));
    533 
    534   EXPECT_SINGLE_PARSE_EMPTY_SUCCESS("-non-existent-option");
    535   EXPECT_SINGLE_PARSE_EMPTY_SUCCESS("-non-existent-option1 --non-existent-option-2");
    536 }  //  TEST_F
    537 
    538 TEST_F(CmdlineParserTest, TestIgnoredArguments) {
    539   std::initializer_list<const char*> ignored_args = {
    540       "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
    541       "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:abdef",
    542       "-Xdexopt:foobar", "-Xnoquithandler", "-Xjnigreflimit:ixnay", "-Xgenregmap", "-Xnogenregmap",
    543       "-Xverifyopt:never", "-Xcheckdexsum", "-Xincludeselectedop", "-Xjitop:noop",
    544       "-Xincludeselectedmethod", "-Xjitblocking", "-Xjitmethod:_", "-Xjitclass:nosuchluck",
    545       "-Xjitoffset:none", "-Xjitconfig:yes", "-Xjitcheckcg", "-Xjitverbose", "-Xjitprofile",
    546       "-Xjitdisableopt", "-Xjitsuspendpoll", "-XX:mainThreadStackSize=1337"
    547   };
    548 
    549   // Check they are ignored when parsed one at a time
    550   for (auto&& arg : ignored_args) {
    551     SCOPED_TRACE(arg);
    552     EXPECT_SINGLE_PARSE_EMPTY_SUCCESS(arg);
    553   }
    554 
    555   // Check they are ignored when we pass it all together at once
    556   std::vector<const char*> argv = ignored_args;
    557   EXPECT_SINGLE_PARSE_EMPTY_SUCCESS(argv);
    558 }  //  TEST_F
    559 
    560 TEST_F(CmdlineParserTest, MultipleArguments) {
    561   EXPECT_TRUE(IsResultSuccessful(parser_->Parse(
    562       "-help -XX:ForegroundHeapGrowthMultiplier=0.5 "
    563       "-Xnodex2oat -Xmethod-trace -XX:LargeObjectSpace=map")));
    564 
    565   auto&& map = parser_->ReleaseArgumentsMap();
    566   EXPECT_EQ(5u, map.Size());
    567   EXPECT_KEY_VALUE(map, M::Help, Unit{});  // NOLINT [whitespace/braces] [5]
    568   EXPECT_KEY_VALUE(map, M::ForegroundHeapGrowthMultiplier, 0.5);
    569   EXPECT_KEY_VALUE(map, M::Dex2Oat, false);
    570   EXPECT_KEY_VALUE(map, M::MethodTrace, Unit{});  // NOLINT [whitespace/braces] [5]
    571   EXPECT_KEY_VALUE(map, M::LargeObjectSpace, gc::space::LargeObjectSpaceType::kMap);
    572 }  //  TEST_F
    573 }  // namespace art
    574