summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2020-07-07 15:56:34 -0700
committerYabin Cui <yabinc@google.com>2020-07-08 15:02:56 -0700
commitacbdb2456da4837a143d096a8a0563ba1dfc0507 (patch)
tree9e07abefafc96e76fb9b065264fb67cb78c0d9ad
parent4f6808ce8d0a10cb4c8588ddd7ed275001da3154 (diff)
downloadextras-acbdb2456da4837a143d096a8a0563ba1dfc0507.tar.gz
simpleperf: add function to preprocess options.
Add Command::PreprocessOptions() to extracts options from the argument list. It splits options into different types. Instead of replying on the order in the argument list, it allows a command choosing the order to process each option. Also put whole command.h in simpleperf namespace. Bug: 160701181 Test: run simpleperf_unit_test. Change-Id: I9b20e21a94797c322c1371cbe1704b3e2ce1be28
-rw-r--r--simpleperf/cmd_api.cpp6
-rw-r--r--simpleperf/cmd_api_test.cpp2
-rw-r--r--simpleperf/cmd_debug_unwind.cpp4
-rw-r--r--simpleperf/cmd_debug_unwind_test.cpp2
-rw-r--r--simpleperf/cmd_dumprecord.cpp4
-rw-r--r--simpleperf/cmd_dumprecord_test.cpp2
-rw-r--r--simpleperf/cmd_help.cpp6
-rw-r--r--simpleperf/cmd_inject.cpp4
-rw-r--r--simpleperf/cmd_kmem.cpp4
-rw-r--r--simpleperf/cmd_kmem_test.cpp2
-rw-r--r--simpleperf/cmd_list.cpp4
-rw-r--r--simpleperf/cmd_list_test.cpp2
-rw-r--r--simpleperf/cmd_record.cpp4
-rw-r--r--simpleperf/cmd_report.cpp4
-rw-r--r--simpleperf/cmd_report_sample.cpp5
-rw-r--r--simpleperf/cmd_report_sample_test.cpp2
-rw-r--r--simpleperf/cmd_report_test.cpp2
-rw-r--r--simpleperf/cmd_stat.cpp4
-rw-r--r--simpleperf/cmd_trace_sched.cpp5
-rw-r--r--simpleperf/cmd_trace_sched_test.cpp1
-rw-r--r--simpleperf/command.cpp92
-rw-r--r--simpleperf/command.h100
-rw-r--r--simpleperf/command_test.cpp111
-rw-r--r--simpleperf/gtest_main.cpp2
-rw-r--r--simpleperf/main.cpp2
25 files changed, 370 insertions, 6 deletions
diff --git a/simpleperf/cmd_api.cpp b/simpleperf/cmd_api.cpp
index 7f933736..7235a250 100644
--- a/simpleperf/cmd_api.cpp
+++ b/simpleperf/cmd_api.cpp
@@ -34,6 +34,8 @@
#include "utils.h"
#include "workload.h"
+using namespace simpleperf;
+
namespace {
const std::string SIMPLEPERF_DATA_DIR = "simpleperf_data";
@@ -215,9 +217,13 @@ bool CollectCommand::RemoveRecordingData() {
}
} // namespace
+namespace simpleperf {
+
void RegisterAPICommands() {
RegisterCommand("api-prepare",
[]{ return std::unique_ptr<Command>(new PrepareCommand()); });
RegisterCommand("api-collect",
[]{ return std::unique_ptr<Command>(new CollectCommand()); });
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_api_test.cpp b/simpleperf/cmd_api_test.cpp
index 4157bdef..716b383b 100644
--- a/simpleperf/cmd_api_test.cpp
+++ b/simpleperf/cmd_api_test.cpp
@@ -24,6 +24,8 @@
#include "test_util.h"
#include "utils.h"
+using namespace simpleperf;
+
#if defined(__ANDROID__)
static bool WaitUntilAppExit(const std::string& package_name) {
diff --git a/simpleperf/cmd_debug_unwind.cpp b/simpleperf/cmd_debug_unwind.cpp
index b5df2da3..72f1ddbb 100644
--- a/simpleperf/cmd_debug_unwind.cpp
+++ b/simpleperf/cmd_debug_unwind.cpp
@@ -405,7 +405,11 @@ void DebugUnwindCommand::PrintStat() {
printf("Please use debug_unwind_reporter.py to get a report in details.\n");
}
+namespace simpleperf {
+
void RegisterDebugUnwindCommand() {
RegisterCommand("debug-unwind",
[]{ return std::unique_ptr<Command>(new DebugUnwindCommand()); });
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_debug_unwind_test.cpp b/simpleperf/cmd_debug_unwind_test.cpp
index 20a441ec..8b65d424 100644
--- a/simpleperf/cmd_debug_unwind_test.cpp
+++ b/simpleperf/cmd_debug_unwind_test.cpp
@@ -29,6 +29,8 @@
#include "record_file.h"
#include "test_util.h"
+using namespace simpleperf;
+
static std::unique_ptr<Command> DebugUnwindCmd() {
return CreateCommandInstance("debug-unwind");
}
diff --git a/simpleperf/cmd_dumprecord.cpp b/simpleperf/cmd_dumprecord.cpp
index 645a783a..c996832c 100644
--- a/simpleperf/cmd_dumprecord.cpp
+++ b/simpleperf/cmd_dumprecord.cpp
@@ -466,6 +466,10 @@ bool DumpRecordCommand::DumpFeatureSection() {
} // namespace
+namespace simpleperf {
+
void RegisterDumpRecordCommand() {
RegisterCommand("dump", [] { return std::unique_ptr<Command>(new DumpRecordCommand); });
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_dumprecord_test.cpp b/simpleperf/cmd_dumprecord_test.cpp
index e8632b87..dc33e719 100644
--- a/simpleperf/cmd_dumprecord_test.cpp
+++ b/simpleperf/cmd_dumprecord_test.cpp
@@ -20,6 +20,8 @@
#include "get_test_data.h"
#include "test_util.h"
+using namespace simpleperf;
+
static std::unique_ptr<Command> DumpCmd() {
return CreateCommandInstance("dump");
}
diff --git a/simpleperf/cmd_help.cpp b/simpleperf/cmd_help.cpp
index b51071b2..65bed775 100644
--- a/simpleperf/cmd_help.cpp
+++ b/simpleperf/cmd_help.cpp
@@ -22,6 +22,8 @@
#include "command.h"
+using namespace simpleperf;
+
class HelpCommand : public Command {
public:
HelpCommand()
@@ -84,7 +86,11 @@ void HelpCommand::PrintLongHelpForOneCommand(const Command& command) {
printf("%s\n", command.LongHelpString().c_str());
}
+namespace simpleperf {
+
void RegisterHelpCommand() {
RegisterCommand("help",
[] { return std::unique_ptr<Command>(new HelpCommand); });
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_inject.cpp b/simpleperf/cmd_inject.cpp
index 04abeed0..69b3452f 100644
--- a/simpleperf/cmd_inject.cpp
+++ b/simpleperf/cmd_inject.cpp
@@ -451,6 +451,10 @@ class InjectCommand : public Command {
} // namespace
+namespace simpleperf {
+
void RegisterInjectCommand() {
return RegisterCommand("inject", [] { return std::unique_ptr<Command>(new InjectCommand); });
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_kmem.cpp b/simpleperf/cmd_kmem.cpp
index 453a2768..454747b8 100644
--- a/simpleperf/cmd_kmem.cpp
+++ b/simpleperf/cmd_kmem.cpp
@@ -710,7 +710,11 @@ void KmemCommand::PrintSlabReportContext(FILE* fp) {
} // namespace
+namespace simpleperf {
+
void RegisterKmemCommand() {
RegisterCommand("kmem",
[] { return std::unique_ptr<Command>(new KmemCommand()); });
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_kmem_test.cpp b/simpleperf/cmd_kmem_test.cpp
index 4dab87ed..0fa30669 100644
--- a/simpleperf/cmd_kmem_test.cpp
+++ b/simpleperf/cmd_kmem_test.cpp
@@ -27,6 +27,8 @@
#include "record_file.h"
#include "test_util.h"
+using namespace simpleperf;
+
static std::unique_ptr<Command> KmemCmd() {
return CreateCommandInstance("kmem");
}
diff --git a/simpleperf/cmd_list.cpp b/simpleperf/cmd_list.cpp
index ef6ba86a..396d7a8e 100644
--- a/simpleperf/cmd_list.cpp
+++ b/simpleperf/cmd_list.cpp
@@ -223,6 +223,10 @@ void ListCommand::ShowFeatures() {
} // namespace
+namespace simpleperf {
+
void RegisterListCommand() {
RegisterCommand("list", [] { return std::unique_ptr<Command>(new ListCommand); });
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_list_test.cpp b/simpleperf/cmd_list_test.cpp
index 6712b0a4..e2f804da 100644
--- a/simpleperf/cmd_list_test.cpp
+++ b/simpleperf/cmd_list_test.cpp
@@ -19,6 +19,8 @@
#include "command.h"
#include "test_util.h"
+using namespace simpleperf;
+
class ListCommandTest : public ::testing::Test {
protected:
virtual void SetUp() {
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 2aa99407..5bb6c00b 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -1839,7 +1839,11 @@ void RecordCommand::CollectHitFileInfo(const SampleRecord& r) {
}
}
+namespace simpleperf {
+
void RegisterRecordCommand() {
RegisterCommand("record",
[] { return std::unique_ptr<Command>(new RecordCommand()); });
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp
index 5a509781..3d5fad90 100644
--- a/simpleperf/cmd_report.cpp
+++ b/simpleperf/cmd_report.cpp
@@ -974,7 +974,11 @@ void ReportCommand::PrintReportContext(FILE* report_fp) {
} // namespace
+namespace simpleperf {
+
void RegisterReportCommand() {
RegisterCommand("report",
[] { return std::unique_ptr<Command>(new ReportCommand()); });
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_report_sample.cpp b/simpleperf/cmd_report_sample.cpp
index e133fb28..2d9caf4b 100644
--- a/simpleperf/cmd_report_sample.cpp
+++ b/simpleperf/cmd_report_sample.cpp
@@ -33,6 +33,7 @@
#include "thread_tree.h"
#include "utils.h"
+using namespace simpleperf;
namespace proto = simpleperf_report_proto;
namespace {
@@ -690,8 +691,12 @@ void ReportSampleCommand::PrintLostSituation() {
} // namespace
+namespace simpleperf {
+
void RegisterReportSampleCommand() {
RegisterCommand("report-sample", [] {
return std::unique_ptr<Command>(new ReportSampleCommand());
});
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_report_sample_test.cpp b/simpleperf/cmd_report_sample_test.cpp
index 9543634d..c8529efc 100644
--- a/simpleperf/cmd_report_sample_test.cpp
+++ b/simpleperf/cmd_report_sample_test.cpp
@@ -21,6 +21,8 @@
#include "command.h"
#include "get_test_data.h"
+using namespace simpleperf;
+
static std::unique_ptr<Command> ReportSampleCmd() {
return CreateCommandInstance("report-sample");
}
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index 36837f9e..ae081148 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -28,6 +28,8 @@
#include "read_apk.h"
#include "test_util.h"
+using namespace simpleperf;
+
static std::unique_ptr<Command> ReportCmd() {
return CreateCommandInstance("report");
}
diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp
index f60bdd4d..66ac1b60 100644
--- a/simpleperf/cmd_stat.cpp
+++ b/simpleperf/cmd_stat.cpp
@@ -914,7 +914,11 @@ bool StatCommand::ShowCounters(const std::vector<CountersInfo>& counters,
} // namespace
+namespace simpleperf {
+
void RegisterStatCommand() {
RegisterCommand("stat",
[] { return std::unique_ptr<Command>(new StatCommand); });
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_trace_sched.cpp b/simpleperf/cmd_trace_sched.cpp
index a5961ec9..2977a756 100644
--- a/simpleperf/cmd_trace_sched.cpp
+++ b/simpleperf/cmd_trace_sched.cpp
@@ -33,6 +33,7 @@
#include "utils.h"
using android::base::StringPrintf;
+using namespace simpleperf;
namespace {
@@ -413,6 +414,10 @@ void TraceSchedCommand::ReportProcessInfo(const std::vector<ProcessInfo>& proces
} // namespace
+namespace simpleperf {
+
void RegisterTraceSchedCommand() {
RegisterCommand("trace-sched", [] { return std::unique_ptr<Command>(new TraceSchedCommand()); });
}
+
+} // namespace simpleperf
diff --git a/simpleperf/cmd_trace_sched_test.cpp b/simpleperf/cmd_trace_sched_test.cpp
index c7676491..b50e3a31 100644
--- a/simpleperf/cmd_trace_sched_test.cpp
+++ b/simpleperf/cmd_trace_sched_test.cpp
@@ -36,6 +36,7 @@
#include "test_util.h"
#include "thread_tree.h"
+using namespace simpleperf;
using namespace PerfFileFormat;
static std::unique_ptr<Command> TraceSchedCmd() {
diff --git a/simpleperf/command.cpp b/simpleperf/command.cpp
index d00fc224..a7b7eb5a 100644
--- a/simpleperf/command.cpp
+++ b/simpleperf/command.cpp
@@ -16,6 +16,8 @@
#include "command.h"
+#include <string.h>
+
#include <algorithm>
#include <map>
#include <string>
@@ -27,7 +29,7 @@
#include "utils.h"
-using namespace simpleperf;
+namespace simpleperf {
bool Command::NextArgumentOrError(const std::vector<std::string>& args, size_t* pi) {
if (*pi + 1 == args.size()) {
@@ -39,6 +41,90 @@ bool Command::NextArgumentOrError(const std::vector<std::string>& args, size_t*
return true;
}
+bool Command::PreprocessOptions(const std::vector<std::string>& args,
+ const std::unordered_map<OptionName, OptionFormat>& option_formats,
+ OptionValueMap* options,
+ std::vector<std::pair<OptionName, OptionValue>>* ordered_options,
+ std::vector<std::string>* non_option_args) {
+ options->values.clear();
+ ordered_options->clear();
+ size_t i;
+ for (i = 0; i < args.size() && !args[i].empty() && args[i][0] == '-'; i++) {
+ auto it = option_formats.find(args[i]);
+ if (it == option_formats.end()) {
+ if (args[i] == "--") {
+ i++;
+ break;
+ }
+ ReportUnknownOption(args, i);
+ return false;
+ }
+ const OptionName& name = it->first;
+ const OptionFormat& format = it->second;
+ OptionValue value;
+ memset(&value, 0, sizeof(value));
+
+ if (i + 1 == args.size()) {
+ if (format.value_type != OptionValueType::NONE &&
+ format.value_type != OptionValueType::OPT_STRING) {
+ LOG(ERROR) << "No argument following " << name << " option. Try `simpleperf help " << name_
+ << "`";
+ return false;
+ }
+ } else {
+ switch (format.value_type) {
+ case OptionValueType::NONE:
+ break;
+ case OptionValueType::STRING:
+ value.str_value = &args[++i];
+ break;
+ case OptionValueType::OPT_STRING:
+ if (!args[i + 1].empty() && args[i + 1][0] != '-') {
+ value.str_value = &args[++i];
+ }
+ break;
+ case OptionValueType::UINT:
+ if (!android::base::ParseUint(args[++i], &value.uint_value,
+ std::numeric_limits<uint64_t>::max(), true)) {
+ LOG(ERROR) << "Invalid argument for option " << name << ": " << args[i];
+ return false;
+ }
+ break;
+ case OptionValueType::DOUBLE:
+ if (!android::base::ParseDouble(args[++i], &value.double_value)) {
+ LOG(ERROR) << "Invalid argument for option " << name << ": " << args[i];
+ return false;
+ }
+ break;
+ }
+ }
+
+ switch (format.type) {
+ case OptionType::SINGLE:
+ if (auto it = options->values.find(name); it != options->values.end()) {
+ it->second = value;
+ } else {
+ options->values.emplace(name, value);
+ }
+ break;
+ case OptionType::MULTIPLE:
+ options->values.emplace(name, value);
+ break;
+ case OptionType::ORDERED:
+ ordered_options->emplace_back(name, value);
+ break;
+ }
+ }
+ if (i < args.size()) {
+ if (non_option_args == nullptr) {
+ LOG(ERROR) << "Invalid option " << args[i] << ". Try `simpleperf help " << name_ << "`";
+ return false;
+ }
+ non_option_args->assign(args.begin() + i, args.end());
+ }
+ return true;
+}
+
bool Command::GetDoubleOption(const std::vector<std::string>& args, size_t* pi, double* value,
double min, double max) {
if (!NextArgumentOrError(args, pi)) {
@@ -131,9 +217,7 @@ static void StderrLogger(android::base::LogId, android::base::LogSeverity severi
fprintf(stderr, "simpleperf %c %s:%u] %s\n", severity_char, file, line, message);
}
-namespace simpleperf {
bool log_to_android_buffer = false;
-}
bool RunSimpleperfCmd(int argc, char** argv) {
android::base::InitLogging(argv, StderrLogger);
@@ -190,3 +274,5 @@ bool RunSimpleperfCmd(int argc, char** argv) {
_Exit(result ? 0 : 1);
return result;
}
+
+} // namespace simpleperf
diff --git a/simpleperf/command.h b/simpleperf/command.h
index fe71a31a..2f0a038c 100644
--- a/simpleperf/command.h
+++ b/simpleperf/command.h
@@ -18,15 +18,103 @@
#define SIMPLE_PERF_COMMAND_H_
#include <functional>
-#include <memory>
#include <limits>
+#include <map>
+#include <memory>
+#include <optional>
#include <string>
+#include <unordered_map>
#include <vector>
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/parseint.h>
+namespace simpleperf {
+
+using OptionName = std::string;
+
+enum class OptionType {
+ SINGLE, // this option has a single value (use the last one in the arg list)
+ MULTIPLE, // this option can have multiple values (keep all values appeared in the arg list)
+ ORDERED, // keep the order of this option in the arg list
+};
+
+enum class OptionValueType {
+ NONE, // No value is needed
+ STRING,
+ OPT_STRING, // optional string
+ UINT,
+ DOUBLE,
+};
+
+struct OptionFormat {
+ OptionValueType value_type;
+ OptionType type;
+};
+
+union OptionValue {
+ const std::string* str_value;
+ uint64_t uint_value;
+ double double_value;
+};
+
+struct OptionValueMap {
+ std::multimap<OptionName, OptionValue> values;
+
+ bool PullBoolValue(const OptionName& name) {
+ return PullValue(name).has_value();
+ }
+
+ template <typename T>
+ bool PullUintValue(const OptionName& name, T* value, uint64_t min = 0,
+ uint64_t max = std::numeric_limits<T>::max()) {
+ if (auto option_value = PullValue(name); option_value) {
+ if (option_value->uint_value < min || option_value->uint_value > max) {
+ LOG(ERROR) << "invalid " << name << ": " << option_value->uint_value;
+ return false;
+ }
+ *value = option_value->uint_value;
+ }
+ return true;
+ }
+
+ bool PullDoubleValue(const OptionName& name, double* value,
+ double min = std::numeric_limits<double>::lowest(),
+ double max = std::numeric_limits<double>::max()) {
+ if (auto option_value = PullValue(name); option_value) {
+ if (option_value->double_value < min || option_value->double_value > max) {
+ LOG(ERROR) << "invalid " << name << ": " << option_value->double_value;
+ return false;
+ }
+ *value = option_value->double_value;
+ }
+ return true;
+ }
+
+ std::optional<OptionValue> PullValue(const OptionName& name) {
+ std::optional<OptionValue> res;
+ if (auto it = values.find(name); it != values.end()) {
+ res.emplace(it->second);
+ values.erase(it);
+ }
+ return res;
+ }
+
+ std::optional<std::vector<OptionValue>> PullValues(const OptionName& name) {
+ auto pair = values.equal_range(name);
+ if (pair.first != pair.second) {
+ std::vector<OptionValue> res;
+ for (auto it = pair.first; it != pair.second; ++it) {
+ res.emplace_back(it->second);
+ }
+ values.erase(name);
+ return res;
+ }
+ return {};
+ }
+};
+
class Command {
public:
Command(const std::string& name, const std::string& short_help_string,
@@ -51,6 +139,12 @@ class Command {
virtual bool Run(const std::vector<std::string>& args) = 0;
+ bool PreprocessOptions(const std::vector<std::string>& args,
+ const std::unordered_map<OptionName, OptionFormat>& option_formats,
+ OptionValueMap* options,
+ std::vector<std::pair<OptionName, OptionValue>>* ordered_options,
+ std::vector<std::string>* non_option_args = nullptr);
+
template <typename T>
bool GetUintOption(const std::vector<std::string>& args, size_t* pi, T* value, uint64_t min = 0,
uint64_t max = std::numeric_limits<T>::max(), bool allow_suffixes = false) {
@@ -88,8 +182,8 @@ std::unique_ptr<Command> CreateCommandInstance(const std::string& cmd_name);
const std::vector<std::string> GetAllCommandNames();
bool RunSimpleperfCmd(int argc, char** argv);
-namespace simpleperf {
extern bool log_to_android_buffer;
-}
+
+} // namespace simpleperf
#endif // SIMPLE_PERF_COMMAND_H_
diff --git a/simpleperf/command_test.cpp b/simpleperf/command_test.cpp
index 29c745e3..ab618e13 100644
--- a/simpleperf/command_test.cpp
+++ b/simpleperf/command_test.cpp
@@ -18,6 +18,8 @@
#include "command.h"
+using namespace simpleperf;
+
class MockCommand : public Command {
public:
MockCommand() : Command("mock", "mock_short_help", "mock_long_help") {
@@ -70,3 +72,112 @@ TEST(command, GetValueForOption) {
ASSERT_TRUE(command.GetDoubleOption({"-s", "3.2"}, &i, &double_value, 0, 4));
ASSERT_DOUBLE_EQ(double_value, 3.2);
}
+
+TEST(command, PreprocessOptions) {
+ MockCommand cmd;
+ OptionValueMap options;
+ std::vector<std::pair<OptionName, OptionValue>> ordered_options;
+ std::vector<std::string> non_option_args;
+
+ std::unordered_map<OptionName, OptionFormat> option_formats = {
+ {"--bool-option", {OptionValueType::NONE, OptionType::SINGLE}},
+ {"--str-option", {OptionValueType::STRING, OptionType::MULTIPLE}},
+ {"--opt-str-option", {OptionValueType::OPT_STRING, OptionType::MULTIPLE}},
+ {"--uint-option", {OptionValueType::UINT, OptionType::SINGLE}},
+ {"--double-option", {OptionValueType::DOUBLE, OptionType::SINGLE}},
+
+ // ordered options
+ {"--ord-str-option", {OptionValueType::STRING, OptionType::ORDERED}},
+ {"--ord-uint-option", {OptionValueType::UINT, OptionType::ORDERED}},
+ };
+
+ // Check options.
+ std::vector<std::string> args = {"--bool-option",
+ "--str-option",
+ "str1",
+ "--str-option",
+ "str2",
+ "--opt-str-option",
+ "--opt-str-option",
+ "opt_str",
+ "--uint-option",
+ "34",
+ "--double-option",
+ "-32.75"};
+ ASSERT_TRUE(cmd.PreprocessOptions(args, option_formats, &options, &ordered_options, nullptr));
+ ASSERT_TRUE(options.PullBoolValue("--bool-option"));
+ auto values = options.PullValues("--str-option").value();
+ ASSERT_EQ(values.size(), 2);
+ ASSERT_EQ(*values[0].str_value, "str1");
+ ASSERT_EQ(*values[1].str_value, "str2");
+ values = options.PullValues("--opt-str-option").value();
+ ASSERT_EQ(values.size(), 2);
+ ASSERT_TRUE(values[0].str_value == nullptr);
+ ASSERT_EQ(*values[1].str_value, "opt_str");
+ size_t uint_value;
+ ASSERT_TRUE(options.PullUintValue("--uint-option", &uint_value));
+ ASSERT_EQ(uint_value, 34);
+ double double_value;
+ ASSERT_TRUE(options.PullDoubleValue("--double-option", &double_value));
+ ASSERT_DOUBLE_EQ(double_value, -32.75);
+ ASSERT_TRUE(options.values.empty());
+
+ // Check ordered options.
+ args = {"--ord-str-option", "str1", "--ord-uint-option", "32", "--ord-str-option", "str2"};
+ ASSERT_TRUE(cmd.PreprocessOptions(args, option_formats, &options, &ordered_options, nullptr));
+ ASSERT_EQ(ordered_options.size(), 3);
+ ASSERT_EQ(ordered_options[0].first, "--ord-str-option");
+ ASSERT_EQ(*(ordered_options[0].second.str_value), "str1");
+ ASSERT_EQ(ordered_options[1].first, "--ord-uint-option");
+ ASSERT_EQ(ordered_options[1].second.uint_value, 32);
+ ASSERT_EQ(ordered_options[2].first, "--ord-str-option");
+ ASSERT_EQ(*(ordered_options[2].second.str_value), "str2");
+
+ // Check non_option_args.
+ ASSERT_TRUE(cmd.PreprocessOptions({"arg1", "--arg2"}, option_formats, &options, &ordered_options,
+ &non_option_args));
+ ASSERT_EQ(non_option_args, std::vector<std::string>({"arg1", "--arg2"}));
+ // "--" can force following args to be non_option_args.
+ ASSERT_TRUE(cmd.PreprocessOptions({"--", "--bool-option"}, option_formats, &options,
+ &ordered_options, &non_option_args));
+ ASSERT_EQ(non_option_args, std::vector<std::string>({"--bool-option"}));
+
+ // Check different errors.
+ // unknown option
+ ASSERT_FALSE(cmd.PreprocessOptions({"--unknown-option"}, option_formats, &options,
+ &ordered_options, nullptr));
+ // no option value
+ ASSERT_FALSE(
+ cmd.PreprocessOptions({"--str-option"}, option_formats, &options, &ordered_options, nullptr));
+ // wrong option value format
+ ASSERT_FALSE(cmd.PreprocessOptions({"--uint-option", "-2"}, option_formats, &options,
+ &ordered_options, nullptr));
+ ASSERT_FALSE(cmd.PreprocessOptions({"--double-option", "str"}, option_formats, &options,
+ &ordered_options, nullptr));
+ // unexpected non_option_args
+ ASSERT_FALSE(cmd.PreprocessOptions({"non_option_args"}, option_formats, &options,
+ &ordered_options, nullptr));
+}
+
+TEST(command, OptionValueMap) {
+ OptionValue value;
+ value.uint_value = 10;
+
+ OptionValueMap options;
+ uint64_t uint_value;
+ options.values.emplace("--uint-option", value);
+ ASSERT_FALSE(options.PullUintValue("--uint-option", &uint_value, 11));
+ options.values.emplace("--uint-option", value);
+ ASSERT_FALSE(options.PullUintValue("--uint-option", &uint_value, 0, 9));
+ options.values.emplace("--uint-option", value);
+ ASSERT_TRUE(options.PullUintValue("--uint-option", &uint_value, 10, 10));
+
+ double double_value;
+ value.double_value = 0.0;
+ options.values.emplace("--double-option", value);
+ ASSERT_FALSE(options.PullDoubleValue("--double-option", &double_value, 1.0));
+ options.values.emplace("--double-option", value);
+ ASSERT_FALSE(options.PullDoubleValue("--double-option", &double_value, -2.0, -1.0));
+ options.values.emplace("--double-option", value);
+ ASSERT_TRUE(options.PullDoubleValue("--double-option", &double_value, 0.0, 0.0));
+}
diff --git a/simpleperf/gtest_main.cpp b/simpleperf/gtest_main.cpp
index a6062281..013ec603 100644
--- a/simpleperf/gtest_main.cpp
+++ b/simpleperf/gtest_main.cpp
@@ -36,6 +36,8 @@
#include "utils.h"
#include "workload.h"
+using namespace simpleperf;
+
static std::string testdata_dir;
#if defined(__ANDROID__)
diff --git a/simpleperf/main.cpp b/simpleperf/main.cpp
index 49d25481..d5906a25 100644
--- a/simpleperf/main.cpp
+++ b/simpleperf/main.cpp
@@ -21,6 +21,8 @@
#include "command.h"
#include "environment.h"
+using namespace simpleperf;
+
#if defined(__ANDROID__)
bool AndroidSecurityCheck() {