Add portable option parser.
GitOrigin-RevId: 0d4f7e2f5bec4826e1c12e3aa1aee642fcf6da07
This commit is contained in:
parent
4bb6fe7e78
commit
c46910d75f
@ -4331,7 +4331,7 @@ void main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
return std::string();
|
return std::string();
|
||||||
}(std::getenv("TD_API_HASH"));
|
}(std::getenv("TD_API_HASH"));
|
||||||
// TODO port OptionsParser to Windows
|
// TODO use OptionParser
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
if (!std::strcmp(argv[i], "--test")) {
|
if (!std::strcmp(argv[i], "--test")) {
|
||||||
use_test_dc = true;
|
use_test_dc = true;
|
||||||
|
@ -4,14 +4,6 @@ if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
|||||||
set(CMAKE_INSTALL_LIBDIR "lib")
|
set(CMAKE_INSTALL_LIBDIR "lib")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
if (WINGETOPT_FOUND)
|
|
||||||
set(TD_HAVE_GETOPT 1)
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
set(TD_HAVE_GETOPT 1)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT ZLIB_FOUND)
|
if (NOT ZLIB_FOUND)
|
||||||
find_package(ZLIB)
|
find_package(ZLIB)
|
||||||
endif()
|
endif()
|
||||||
@ -104,7 +96,7 @@ set(TDUTILS_SOURCE
|
|||||||
td/utils/misc.cpp
|
td/utils/misc.cpp
|
||||||
td/utils/MimeType.cpp
|
td/utils/MimeType.cpp
|
||||||
td/utils/MpmcQueue.cpp
|
td/utils/MpmcQueue.cpp
|
||||||
td/utils/OptionsParser.cpp
|
td/utils/OptionParser.cpp
|
||||||
td/utils/PathView.cpp
|
td/utils/PathView.cpp
|
||||||
td/utils/Random.cpp
|
td/utils/Random.cpp
|
||||||
td/utils/SharedSlice.cpp
|
td/utils/SharedSlice.cpp
|
||||||
@ -222,7 +214,7 @@ set(TDUTILS_SOURCE
|
|||||||
td/utils/ObjectPool.h
|
td/utils/ObjectPool.h
|
||||||
td/utils/Observer.h
|
td/utils/Observer.h
|
||||||
td/utils/optional.h
|
td/utils/optional.h
|
||||||
td/utils/OptionsParser.h
|
td/utils/OptionParser.h
|
||||||
td/utils/OrderedEventsProcessor.h
|
td/utils/OrderedEventsProcessor.h
|
||||||
td/utils/overloaded.h
|
td/utils/overloaded.h
|
||||||
td/utils/Parser.h
|
td/utils/Parser.h
|
||||||
@ -280,6 +272,7 @@ set(TDUTILS_TEST_SOURCE
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/MpmcQueue.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test/MpmcQueue.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/MpmcWaiter.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test/MpmcWaiter.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/MpscLinkQueue.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test/MpscLinkQueue.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test/OptionParser.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/OrderedEventsProcessor.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test/OrderedEventsProcessor.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/port.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test/port.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/pq.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test/pq.cpp
|
||||||
@ -324,10 +317,6 @@ if (ABSL_FOUND)
|
|||||||
target_link_libraries(tdutils PUBLIC absl::flat_hash_map absl::flat_hash_set absl::hash)
|
target_link_libraries(tdutils PUBLIC absl::flat_hash_map absl::flat_hash_set absl::hash)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32 AND WINGETOPT_FOUND)
|
|
||||||
target_link_libraries(tdutils PRIVATE wingetopt)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
target_link_libraries(tdutils PRIVATE log)
|
target_link_libraries(tdutils PRIVATE log)
|
||||||
endif()
|
endif()
|
||||||
|
153
tdutils/td/utils/OptionParser.cpp
Normal file
153
tdutils/td/utils/OptionParser.cpp
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
//
|
||||||
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
#include "td/utils/OptionParser.h"
|
||||||
|
|
||||||
|
#include "td/utils/misc.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
void OptionParser::set_description(string description) {
|
||||||
|
description_ = std::move(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionParser::add_option(Option::Type type, char short_key, Slice long_key, Slice description,
|
||||||
|
std::function<Status(Slice)> callback) {
|
||||||
|
options_.push_back(Option{type, short_key, long_key.str(), description.str(), std::move(callback)});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionParser::add_option(char short_key, Slice long_key, Slice description,
|
||||||
|
std::function<Status(Slice)> callback) {
|
||||||
|
add_option(Option::Type::Arg, short_key, long_key, description, std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionParser::add_option(char short_key, Slice long_key, Slice description, std::function<Status(void)> callback) {
|
||||||
|
// Ouch. There must be some better way
|
||||||
|
add_option(Option::Type::NoArg, short_key, long_key, description,
|
||||||
|
std::bind([](std::function<Status(void)> &func, Slice) { return func(); }, std::move(callback),
|
||||||
|
std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<vector<char *>> OptionParser::run(int argc, char *argv[]) {
|
||||||
|
std::unordered_map<char, const Option *> short_options;
|
||||||
|
std::unordered_map<string, const Option *> long_options;
|
||||||
|
for (auto &opt : options_) {
|
||||||
|
if (opt.short_key != '\0') {
|
||||||
|
short_options[opt.short_key] = &opt;
|
||||||
|
}
|
||||||
|
if (!opt.long_key.empty()) {
|
||||||
|
long_options[opt.long_key] = &opt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<char *> non_options;
|
||||||
|
for (int arg_pos = 1; arg_pos < argc; arg_pos++) {
|
||||||
|
const char *arg = argv[arg_pos];
|
||||||
|
if (arg[0] != '-' || arg[1] == '\0') {
|
||||||
|
non_options.push_back(argv[arg_pos]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg[1] == '-' && arg[2] == '\0') {
|
||||||
|
// "--"; after it everything is non-option
|
||||||
|
while (++arg_pos < argc) {
|
||||||
|
non_options.push_back(argv[arg_pos]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg[1] == '-') {
|
||||||
|
// long option
|
||||||
|
Slice long_arg(arg + 2, std::strlen(arg + 2));
|
||||||
|
Slice param;
|
||||||
|
auto equal_pos = long_arg.find('=');
|
||||||
|
bool has_equal = equal_pos != Slice::npos;
|
||||||
|
if (has_equal) {
|
||||||
|
param = long_arg.substr(equal_pos + 1);
|
||||||
|
long_arg = long_arg.substr(0, equal_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = long_options.find(long_arg.str());
|
||||||
|
if (it == long_options.end()) {
|
||||||
|
return Status::Error(PSLICE() << "Option " << long_arg << " was unrecognized");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto option = it->second;
|
||||||
|
switch (option->type) {
|
||||||
|
case Option::Type::NoArg:
|
||||||
|
if (has_equal) {
|
||||||
|
return Status::Error(PSLICE() << "Option " << long_arg << " must not have argument");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Option::Type::Arg:
|
||||||
|
if (!has_equal) {
|
||||||
|
if (++arg_pos == argc) {
|
||||||
|
return Status::Error(PSLICE() << "Option " << long_arg << " must have argument");
|
||||||
|
}
|
||||||
|
param = Slice(argv[arg_pos], std::strlen(argv[arg_pos]));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY_STATUS(option->arg_callback(param));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t opt_pos = 1; arg[opt_pos] != '\0'; opt_pos++) {
|
||||||
|
auto it = short_options.find(arg[opt_pos]);
|
||||||
|
if (it == short_options.end()) {
|
||||||
|
return Status::Error(PSLICE() << "Option " << arg[opt_pos] << " was unrecognized");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto option = it->second;
|
||||||
|
Slice param;
|
||||||
|
switch (option->type) {
|
||||||
|
case Option::Type::NoArg:
|
||||||
|
// nothing to do
|
||||||
|
break;
|
||||||
|
case Option::Type::Arg:
|
||||||
|
if (arg[opt_pos + 1] == '\0') {
|
||||||
|
if (++arg_pos == argc) {
|
||||||
|
return Status::Error(PSLICE() << "Option " << arg[opt_pos] << " must have argument");
|
||||||
|
}
|
||||||
|
param = Slice(argv[arg_pos], std::strlen(argv[arg_pos]));
|
||||||
|
} else {
|
||||||
|
param = Slice(arg + opt_pos + 1, std::strlen(arg + opt_pos + 1));
|
||||||
|
opt_pos += param.size();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY_STATUS(option->arg_callback(param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(non_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder &operator<<(StringBuilder &sb, const OptionParser &o) {
|
||||||
|
sb << o.description_ << "\n";
|
||||||
|
for (auto &opt : o.options_) {
|
||||||
|
sb << "-" << opt.short_key;
|
||||||
|
if (!opt.long_key.empty()) {
|
||||||
|
sb << "|--" << opt.long_key;
|
||||||
|
}
|
||||||
|
if (opt.type != OptionParser::Option::Type::NoArg) {
|
||||||
|
sb << "<arg>";
|
||||||
|
}
|
||||||
|
sb << "\t" << opt.description;
|
||||||
|
sb << "\n";
|
||||||
|
}
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace td
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
class OptionsParser {
|
class OptionParser {
|
||||||
class Option {
|
class Option {
|
||||||
public:
|
public:
|
||||||
enum class Type { NoArg, Arg };
|
enum class Type { NoArg, Arg };
|
||||||
@ -36,9 +36,10 @@ class OptionsParser {
|
|||||||
|
|
||||||
void add_option(char short_key, Slice long_key, Slice description, std::function<Status(void)> callback);
|
void add_option(char short_key, Slice long_key, Slice description, std::function<Status(void)> callback);
|
||||||
|
|
||||||
Result<int> run(int argc, char *argv[]) TD_WARN_UNUSED_RESULT;
|
// returns found non-option parameters
|
||||||
|
Result<vector<char *>> run(int argc, char *argv[]) TD_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
friend StringBuilder &operator<<(StringBuilder &sb, const OptionsParser &o);
|
friend StringBuilder &operator<<(StringBuilder &sb, const OptionParser &o);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector<Option> options_;
|
vector<Option> options_;
|
@ -1,123 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
|
|
||||||
//
|
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
//
|
|
||||||
#include "td/utils/OptionsParser.h"
|
|
||||||
|
|
||||||
#if TD_HAVE_GETOPT
|
|
||||||
#include "getopt.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !TD_WINDOWS
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace td {
|
|
||||||
|
|
||||||
void OptionsParser::set_description(string description) {
|
|
||||||
description_ = std::move(description);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OptionsParser::add_option(Option::Type type, char short_key, Slice long_key, Slice description,
|
|
||||||
std::function<Status(Slice)> callback) {
|
|
||||||
options_.push_back(Option{type, short_key, long_key.str(), description.str(), std::move(callback)});
|
|
||||||
}
|
|
||||||
|
|
||||||
void OptionsParser::add_option(char short_key, Slice long_key, Slice description,
|
|
||||||
std::function<Status(Slice)> callback) {
|
|
||||||
add_option(Option::Type::Arg, short_key, long_key, description, std::move(callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OptionsParser::add_option(char short_key, Slice long_key, Slice description,
|
|
||||||
std::function<Status(void)> callback) {
|
|
||||||
// Ouch. There must be some better way
|
|
||||||
add_option(Option::Type::NoArg, short_key, long_key, description,
|
|
||||||
std::bind([](std::function<Status(void)> &func, Slice) { return func(); }, std::move(callback),
|
|
||||||
std::placeholders::_1));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<int> OptionsParser::run(int argc, char *argv[]) {
|
|
||||||
#if TD_HAVE_GETOPT
|
|
||||||
char buff[1024];
|
|
||||||
StringBuilder sb(MutableSlice{buff, sizeof(buff)});
|
|
||||||
for (auto &opt : options_) {
|
|
||||||
sb << opt.short_key;
|
|
||||||
if (opt.type == Option::Type::Arg) {
|
|
||||||
sb << ":";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sb.is_error()) {
|
|
||||||
return Status::Error("Can't parse options");
|
|
||||||
}
|
|
||||||
CSlice short_options = sb.as_cslice();
|
|
||||||
|
|
||||||
vector<option> long_options;
|
|
||||||
for (auto &opt : options_) {
|
|
||||||
if (opt.long_key.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
option o;
|
|
||||||
o.flag = nullptr;
|
|
||||||
o.val = opt.short_key;
|
|
||||||
o.has_arg = opt.type == Option::Type::Arg ? required_argument : no_argument;
|
|
||||||
o.name = opt.long_key.c_str();
|
|
||||||
long_options.push_back(o);
|
|
||||||
}
|
|
||||||
long_options.push_back({nullptr, 0, nullptr, 0});
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
int opt_i = getopt_long(argc, argv, short_options.c_str(), &long_options[0], nullptr);
|
|
||||||
if (opt_i == ':') {
|
|
||||||
return Status::Error("Missing argument");
|
|
||||||
}
|
|
||||||
if (opt_i == '?') {
|
|
||||||
return Status::Error("Unrecognized option");
|
|
||||||
}
|
|
||||||
if (opt_i == -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bool found = false;
|
|
||||||
for (auto &opt : options_) {
|
|
||||||
if (opt.short_key == opt_i) {
|
|
||||||
Slice arg;
|
|
||||||
if (opt.type == Option::Type::Arg) {
|
|
||||||
arg = Slice(optarg);
|
|
||||||
}
|
|
||||||
auto status = opt.arg_callback(arg);
|
|
||||||
if (status.is_error()) {
|
|
||||||
return std::move(status);
|
|
||||||
}
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
return Status::Error("Unknown argument");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return optind;
|
|
||||||
#else
|
|
||||||
return -1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder &operator<<(StringBuilder &sb, const OptionsParser &o) {
|
|
||||||
sb << o.description_ << "\n";
|
|
||||||
for (auto &opt : o.options_) {
|
|
||||||
sb << "-" << opt.short_key;
|
|
||||||
if (!opt.long_key.empty()) {
|
|
||||||
sb << "|--" << opt.long_key;
|
|
||||||
}
|
|
||||||
if (opt.type != OptionsParser::Option::Type::NoArg) {
|
|
||||||
sb << "<arg>";
|
|
||||||
}
|
|
||||||
sb << "\t" << opt.description;
|
|
||||||
sb << "\n";
|
|
||||||
}
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace td
|
|
@ -5,5 +5,4 @@
|
|||||||
#cmakedefine01 TD_HAVE_CRC32C
|
#cmakedefine01 TD_HAVE_CRC32C
|
||||||
#cmakedefine01 TD_HAVE_COROUTINES
|
#cmakedefine01 TD_HAVE_COROUTINES
|
||||||
#cmakedefine01 TD_HAVE_ABSL
|
#cmakedefine01 TD_HAVE_ABSL
|
||||||
#cmakedefine01 TD_HAVE_GETOPT
|
|
||||||
#cmakedefine01 TD_FD_DEBUG
|
#cmakedefine01 TD_FD_DEBUG
|
||||||
|
91
tdutils/test/OptionParser.cpp
Normal file
91
tdutils/test/OptionParser.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
//
|
||||||
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
#include "td/utils/common.h"
|
||||||
|
#include "td/utils/misc.h"
|
||||||
|
#include "td/utils/OptionParser.h"
|
||||||
|
#include "td/utils/Slice.h"
|
||||||
|
#include "td/utils/Status.h"
|
||||||
|
#include "td/utils/tests.h"
|
||||||
|
|
||||||
|
TEST(OptionParser, run) {
|
||||||
|
td::OptionParser options;
|
||||||
|
options.set_description("test description");
|
||||||
|
|
||||||
|
td::vector<td::string> args;
|
||||||
|
auto run_option_parser = [&](td::string command_line) {
|
||||||
|
args = td::full_split(command_line, ' ');
|
||||||
|
td::vector<char *> argv;
|
||||||
|
argv.push_back("exename");
|
||||||
|
for (auto &arg : args) {
|
||||||
|
argv.push_back(&arg[0]);
|
||||||
|
}
|
||||||
|
return options.run(static_cast<int>(argv.size()), &argv[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
td::uint64 chosen_options = 0;
|
||||||
|
td::vector<td::string> chosen_parameters;
|
||||||
|
auto test_success = [&](td::string command_line, td::uint64 expected_options,
|
||||||
|
td::vector<td::string> expected_parameters, td::vector<td::string> expected_result) {
|
||||||
|
chosen_options = 0;
|
||||||
|
chosen_parameters.clear();
|
||||||
|
auto result = run_option_parser(command_line);
|
||||||
|
ASSERT_TRUE(result.is_ok());
|
||||||
|
ASSERT_EQ(expected_options, chosen_options);
|
||||||
|
ASSERT_EQ(expected_parameters, chosen_parameters);
|
||||||
|
ASSERT_EQ(expected_result.size(), result.ok().size());
|
||||||
|
for (size_t i = 0; i < expected_result.size(); i++) {
|
||||||
|
ASSERT_STREQ(expected_result[i], td::string(result.ok()[i]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto test_fail = [&](td::string command_line) {
|
||||||
|
auto result = run_option_parser(command_line);
|
||||||
|
ASSERT_TRUE(result.is_error());
|
||||||
|
};
|
||||||
|
|
||||||
|
options.add_option('q', "", "", [&] {
|
||||||
|
chosen_options += 1;
|
||||||
|
return td::Status::OK();
|
||||||
|
});
|
||||||
|
options.add_option('\0', "http-port2", "", [&] {
|
||||||
|
chosen_options += 10;
|
||||||
|
return td::Status::OK();
|
||||||
|
});
|
||||||
|
options.add_option('p', "http-port", "", [&](td::Slice parameter) {
|
||||||
|
chosen_options += 100;
|
||||||
|
chosen_parameters.push_back(parameter.str());
|
||||||
|
return td::Status::OK();
|
||||||
|
});
|
||||||
|
options.add_option('v', "test", "", [&] {
|
||||||
|
chosen_options += 1000;
|
||||||
|
return td::Status::OK();
|
||||||
|
});
|
||||||
|
|
||||||
|
test_fail("-http-port2");
|
||||||
|
test_success("-", 0, {}, {"-"});
|
||||||
|
test_fail("--http-port");
|
||||||
|
test_fail("--http-port3");
|
||||||
|
test_fail("--http-por");
|
||||||
|
test_fail("--http-port2=1");
|
||||||
|
test_fail("--q");
|
||||||
|
test_fail("-qvp");
|
||||||
|
test_fail("-p");
|
||||||
|
test_fail("-u");
|
||||||
|
test_success("-q", 1, {}, {});
|
||||||
|
test_success("-vvvvvvvvvv", 10000, {}, {});
|
||||||
|
test_success("-qpv", 101, {"v"}, {});
|
||||||
|
test_success("-qp -v", 101, {"-v"}, {});
|
||||||
|
test_success("-qp --http-port2", 101, {"--http-port2"}, {});
|
||||||
|
test_success("-qp -- -v", 1101, {"--"}, {});
|
||||||
|
test_success("-qvqvpqv", 2102, {"qv"}, {});
|
||||||
|
test_success("aba --http-port2 caba --http-port2 dabacaba", 20, {}, {"aba", "caba", "dabacaba"});
|
||||||
|
test_success("das -pqwerty -- -v asd --http-port", 100, {"qwerty"}, {"das", "-v", "asd", "--http-port"});
|
||||||
|
test_success("-p option --http-port option2 --http-port=option3 --http-port=", 400,
|
||||||
|
{"option", "option2", "option3", ""}, {});
|
||||||
|
test_success("", 0, {}, {});
|
||||||
|
test_success("a", 0, {}, {"a"});
|
||||||
|
test_success("", 0, {}, {});
|
||||||
|
}
|
@ -19,7 +19,7 @@
|
|||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
td::init_openssl_threads();
|
td::init_openssl_threads();
|
||||||
|
|
||||||
// TODO port OptionsParser to Windows
|
// TODO use OptionParser
|
||||||
td::TestsRunner &runner = td::TestsRunner::get_default();
|
td::TestsRunner &runner = td::TestsRunner::get_default();
|
||||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user