aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlightqwant <lightqwant@yandex-team.com>2022-09-01 20:05:05 +0300
committerlightqwant <lightqwant@yandex-team.com>2022-09-01 20:05:05 +0300
commit7cfd122cb661b485fb0fb4139573a0beac97ae48 (patch)
tree5f205aaa2d0cdbc28370858218ff766fff8646a5
parentc1f7f3324e630e845df52ba0d4ac0a7e0e7f0f9d (diff)
downloadydb-7cfd122cb661b485fb0fb4139573a0beac97ae48.tar.gz
[getopt] Add typo check for long options
-rw-r--r--library/cpp/getopt/small/last_getopt_opts.h9
-rw-r--r--library/cpp/getopt/small/last_getopt_parse_result.cpp20
-rw-r--r--library/cpp/getopt/ut/last_getopt_ut.cpp25
3 files changed, 54 insertions, 0 deletions
diff --git a/library/cpp/getopt/small/last_getopt_opts.h b/library/cpp/getopt/small/last_getopt_opts.h
index 825b99c871..718dbfcb89 100644
--- a/library/cpp/getopt/small/last_getopt_opts.h
+++ b/library/cpp/getopt/small/last_getopt_opts.h
@@ -54,6 +54,7 @@ namespace NLastGetopt {
bool AllowUnknownLongOptions_ = false;
ui32 Wrap_ = 80;
+ bool CheckUserTypos_ = false;
private:
ui32 FreeArgsMin_; // minimal number of free args
@@ -341,6 +342,14 @@ namespace NLastGetopt {
}
/**
+ * Set check user typos or not
+ * @param check bool flag for chosing
+ */
+ void SetCheckUserTypos(bool check = true) {
+ CheckUserTypos_ = check;
+ }
+
+ /**
* Creates new [option description (TOpt)] for svn-revision printing,
* adds appropriate handler for it.
* If "svnversion" option already exist, will add given short name to it.
diff --git a/library/cpp/getopt/small/last_getopt_parse_result.cpp b/library/cpp/getopt/small/last_getopt_parse_result.cpp
index f4b5607a90..60effba41b 100644
--- a/library/cpp/getopt/small/last_getopt_parse_result.cpp
+++ b/library/cpp/getopt/small/last_getopt_parse_result.cpp
@@ -119,6 +119,20 @@ namespace NLastGetopt {
return Parser_->Argc_ - GetFreeArgsPos();
}
+ void FindUserTypos(const TString& arg, const TOpts* options) {
+ if (arg.size() < 4 || !arg.StartsWith("-")) {
+ return;
+ }
+
+ for (auto opt: options->Opts_) {
+ for (auto name: opt->GetLongNames()) {
+ if ("-" + name == arg) {
+ throw TUsageException() << "did you mean `-" << arg << "` (with two dashes)?";
+ }
+ }
+ }
+ }
+
void TOptsParseResult::Init(const TOpts* options, int argc, const char** argv) {
try {
Parser_.Reset(new TOptsParser(options, argc, argv));
@@ -136,6 +150,12 @@ namespace NLastGetopt {
options->ArgBindings_[i](freeArgs[i]);
}
+
+ if (options->CheckUserTypos_) {
+ for (auto arg: TVector<TString>(argv, std::next(argv, argc))) {
+ FindUserTypos(arg, options);
+ }
+ }
} catch (...) {
HandleError();
}
diff --git a/library/cpp/getopt/ut/last_getopt_ut.cpp b/library/cpp/getopt/ut/last_getopt_ut.cpp
index 6606000ca6..c2ee4f0c40 100644
--- a/library/cpp/getopt/ut/last_getopt_ut.cpp
+++ b/library/cpp/getopt/ut/last_getopt_ut.cpp
@@ -825,4 +825,29 @@ Y_UNIT_TEST_SUITE(TLastGetoptTests) {
UNIT_ASSERT_VALUES_EQUAL(25, number);
UNIT_ASSERT_VALUES_EQUAL(2, r.GetFreeArgCount());
}
+
+ Y_UNIT_TEST(TestCheckUserTypos) {
+ {
+ TOptsNoDefault opts;
+ opts.SetCheckUserTypos();
+ opts.AddLongOption("from");
+ opts.AddLongOption("to");
+
+ UNIT_ASSERT_EXCEPTION(
+ TOptsParseResultTestWrapper(&opts, V({"copy", "-from", "/home", "--to=/etc"})),
+ TUsageException);
+ UNIT_ASSERT_NO_EXCEPTION(
+ TOptsParseResultTestWrapper(&opts, V({"copy", "--from", "from", "--to=/etc"})));
+ }
+
+ {
+ TOptsNoDefault opts;
+ opts.SetCheckUserTypos();
+ opts.AddLongOption('f', "file", "");
+ opts.AddLongOption('r', "read", "");
+ opts.AddLongOption("fr");
+ UNIT_ASSERT_NO_EXCEPTION(
+ TOptsParseResultTestWrapper(&opts, V({"copy", "-fr"})));
+ }
+ }
}