2012-12-05 01:29:32 +01:00
|
|
|
//===- unittest/Support/OptionParsingTest.cpp - OptTable tests ------------===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2012-12-05 01:29:32 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-07-19 20:05:13 +02:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2012-12-05 01:29:32 +01:00
|
|
|
#include "llvm/Option/Arg.h"
|
|
|
|
#include "llvm/Option/ArgList.h"
|
|
|
|
#include "llvm/Option/Option.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::opt;
|
|
|
|
|
|
|
|
enum ID {
|
|
|
|
OPT_INVALID = 0, // This is not an option ID.
|
2017-06-20 18:31:31 +02:00
|
|
|
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES) \
|
|
|
|
OPT_##ID,
|
2012-12-05 01:29:32 +01:00
|
|
|
#include "Opts.inc"
|
|
|
|
LastOption
|
|
|
|
#undef OPTION
|
|
|
|
};
|
|
|
|
|
|
|
|
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
|
|
|
|
#include "Opts.inc"
|
|
|
|
#undef PREFIX
|
|
|
|
|
2013-07-19 20:05:13 +02:00
|
|
|
enum OptionFlags {
|
|
|
|
OptFlag1 = (1 << 4),
|
|
|
|
OptFlag2 = (1 << 5),
|
|
|
|
OptFlag3 = (1 << 6)
|
|
|
|
};
|
|
|
|
|
2012-12-05 01:29:32 +01:00
|
|
|
static const OptTable::Info InfoTable[] = {
|
2017-06-20 18:31:31 +02:00
|
|
|
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES) \
|
|
|
|
{PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
|
|
|
|
PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
|
2012-12-05 01:29:32 +01:00
|
|
|
#include "Opts.inc"
|
|
|
|
#undef OPTION
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class TestOptTable : public OptTable {
|
|
|
|
public:
|
2013-08-28 22:04:31 +02:00
|
|
|
TestOptTable(bool IgnoreCase = false)
|
2015-10-21 18:30:42 +02:00
|
|
|
: OptTable(InfoTable, IgnoreCase) {}
|
2012-12-05 01:29:32 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *Args[] = {
|
|
|
|
"-A",
|
|
|
|
"-Bhi",
|
|
|
|
"--C=desu",
|
|
|
|
"-C", "bye",
|
|
|
|
"-D,adena",
|
|
|
|
"-E", "apple", "bloom",
|
|
|
|
"-Fblarg",
|
|
|
|
"-F", "42",
|
|
|
|
"-Gchuu", "2"
|
|
|
|
};
|
|
|
|
|
2013-07-19 20:05:13 +02:00
|
|
|
TEST(Option, OptionParsing) {
|
2012-12-05 01:29:32 +01:00
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
2015-06-23 00:06:37 +02:00
|
|
|
InputArgList AL = T.ParseArgs(Args, MAI, MAC);
|
2013-01-23 09:30:15 +01:00
|
|
|
|
2012-12-05 01:29:32 +01:00
|
|
|
// Check they all exist.
|
2015-06-23 00:06:37 +02:00
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_A));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_B));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_C));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_D));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_E));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_F));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_G));
|
2012-12-05 01:29:32 +01:00
|
|
|
|
|
|
|
// Check the values.
|
2016-04-15 02:23:15 +02:00
|
|
|
EXPECT_EQ("hi", AL.getLastArgValue(OPT_B));
|
|
|
|
EXPECT_EQ("bye", AL.getLastArgValue(OPT_C));
|
|
|
|
EXPECT_EQ("adena", AL.getLastArgValue(OPT_D));
|
2015-06-23 00:06:37 +02:00
|
|
|
std::vector<std::string> Es = AL.getAllArgValues(OPT_E);
|
2016-04-15 02:23:15 +02:00
|
|
|
EXPECT_EQ("apple", Es[0]);
|
|
|
|
EXPECT_EQ("bloom", Es[1]);
|
|
|
|
EXPECT_EQ("42", AL.getLastArgValue(OPT_F));
|
2015-06-23 00:06:37 +02:00
|
|
|
std::vector<std::string> Gs = AL.getAllArgValues(OPT_G);
|
2016-04-15 02:23:15 +02:00
|
|
|
EXPECT_EQ("chuu", Gs[0]);
|
|
|
|
EXPECT_EQ("2", Gs[1]);
|
2012-12-05 01:29:32 +01:00
|
|
|
|
|
|
|
// Check the help text.
|
|
|
|
std::string Help;
|
|
|
|
raw_string_ostream RSO(Help);
|
2021-06-24 23:47:03 +02:00
|
|
|
T.printHelp(RSO, "test", "title!");
|
2016-04-15 02:23:15 +02:00
|
|
|
EXPECT_NE(std::string::npos, Help.find("-A"));
|
2012-12-05 01:29:32 +01:00
|
|
|
|
2018-10-10 02:15:31 +02:00
|
|
|
// Check usage line.
|
2021-06-24 23:47:03 +02:00
|
|
|
T.printHelp(RSO, "name [options] file...", "title!");
|
2018-10-10 02:15:31 +02:00
|
|
|
EXPECT_NE(std::string::npos, Help.find("USAGE: name [options] file...\n"));
|
|
|
|
|
2012-12-05 01:29:32 +01:00
|
|
|
// Test aliases.
|
2017-04-13 01:43:58 +02:00
|
|
|
auto Cs = AL.filtered(OPT_C);
|
|
|
|
ASSERT_NE(Cs.begin(), Cs.end());
|
|
|
|
EXPECT_EQ("desu", StringRef((*Cs.begin())->getValue()));
|
2012-12-05 01:29:32 +01:00
|
|
|
ArgStringList ASL;
|
2017-04-13 01:43:58 +02:00
|
|
|
(*Cs.begin())->render(AL, ASL);
|
2016-04-15 02:23:15 +02:00
|
|
|
ASSERT_EQ(2u, ASL.size());
|
|
|
|
EXPECT_EQ("-C", StringRef(ASL[0]));
|
|
|
|
EXPECT_EQ("desu", StringRef(ASL[1]));
|
2012-12-05 01:29:32 +01:00
|
|
|
}
|
2013-07-19 20:05:13 +02:00
|
|
|
|
|
|
|
TEST(Option, ParseWithFlagExclusions) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
// Exclude flag3 to avoid parsing as OPT_SLASH_C.
|
2015-06-23 00:06:37 +02:00
|
|
|
InputArgList AL = T.ParseArgs(Args, MAI, MAC,
|
|
|
|
/*FlagsToInclude=*/0,
|
|
|
|
/*FlagsToExclude=*/OptFlag3);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_A));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_C));
|
|
|
|
EXPECT_FALSE(AL.hasArg(OPT_SLASH_C));
|
2013-07-19 20:05:13 +02:00
|
|
|
|
|
|
|
// Exclude flag1 to avoid parsing as OPT_C.
|
2015-06-23 00:06:37 +02:00
|
|
|
AL = T.ParseArgs(Args, MAI, MAC,
|
|
|
|
/*FlagsToInclude=*/0,
|
|
|
|
/*FlagsToExclude=*/OptFlag1);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_B));
|
|
|
|
EXPECT_FALSE(AL.hasArg(OPT_C));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_SLASH_C));
|
2013-07-19 20:05:13 +02:00
|
|
|
|
|
|
|
const char *NewArgs[] = { "/C", "foo", "--C=bar" };
|
2015-06-23 00:06:37 +02:00
|
|
|
AL = T.ParseArgs(NewArgs, MAI, MAC);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_SLASH_C));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_C));
|
2016-04-15 02:23:15 +02:00
|
|
|
EXPECT_EQ("foo", AL.getLastArgValue(OPT_SLASH_C));
|
|
|
|
EXPECT_EQ("bar", AL.getLastArgValue(OPT_C));
|
2013-07-19 20:05:13 +02:00
|
|
|
}
|
2013-07-22 18:18:13 +02:00
|
|
|
|
|
|
|
TEST(Option, ParseAliasInGroup) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
const char *MyArgs[] = { "-I" };
|
2015-06-23 00:06:37 +02:00
|
|
|
InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_H));
|
2013-07-22 18:18:13 +02:00
|
|
|
}
|
2013-08-01 00:44:41 +02:00
|
|
|
|
|
|
|
TEST(Option, AliasArgs) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
const char *MyArgs[] = { "-J", "-Joo" };
|
2015-06-23 00:06:37 +02:00
|
|
|
InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_B));
|
2016-04-15 02:23:15 +02:00
|
|
|
EXPECT_EQ("foo", AL.getAllArgValues(OPT_B)[0]);
|
|
|
|
EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]);
|
2013-08-01 00:44:41 +02:00
|
|
|
}
|
2013-08-02 23:20:27 +02:00
|
|
|
|
2013-08-28 22:04:31 +02:00
|
|
|
TEST(Option, IgnoreCase) {
|
|
|
|
TestOptTable T(true);
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
const char *MyArgs[] = { "-a", "-joo" };
|
2015-06-23 00:06:37 +02:00
|
|
|
InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_A));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_B));
|
2013-08-28 22:04:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Option, DoNotIgnoreCase) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
const char *MyArgs[] = { "-a", "-joo" };
|
2015-06-23 00:06:37 +02:00
|
|
|
InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
|
|
|
|
EXPECT_FALSE(AL.hasArg(OPT_A));
|
|
|
|
EXPECT_FALSE(AL.hasArg(OPT_B));
|
2013-08-28 22:04:31 +02:00
|
|
|
}
|
|
|
|
|
2013-08-13 23:09:50 +02:00
|
|
|
TEST(Option, SlurpEmpty) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
const char *MyArgs[] = { "-A", "-slurp" };
|
2015-06-23 00:06:37 +02:00
|
|
|
InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_A));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_Slurp));
|
2016-04-15 02:23:15 +02:00
|
|
|
EXPECT_EQ(0U, AL.getAllArgValues(OPT_Slurp).size());
|
2013-08-13 23:09:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Option, Slurp) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" };
|
2015-06-23 00:06:37 +02:00
|
|
|
InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
|
|
|
|
EXPECT_EQ(AL.size(), 2U);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_A));
|
|
|
|
EXPECT_FALSE(AL.hasArg(OPT_B));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_Slurp));
|
2016-04-15 02:23:15 +02:00
|
|
|
EXPECT_EQ(3U, AL.getAllArgValues(OPT_Slurp).size());
|
|
|
|
EXPECT_EQ("-B", AL.getAllArgValues(OPT_Slurp)[0]);
|
|
|
|
EXPECT_EQ("--", AL.getAllArgValues(OPT_Slurp)[1]);
|
|
|
|
EXPECT_EQ("foo", AL.getAllArgValues(OPT_Slurp)[2]);
|
2013-08-13 23:09:50 +02:00
|
|
|
}
|
2015-05-04 20:00:13 +02:00
|
|
|
|
2016-04-15 02:23:30 +02:00
|
|
|
TEST(Option, SlurpJoinedEmpty) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
const char *MyArgs[] = { "-A", "-slurpjoined" };
|
|
|
|
InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_A));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
|
|
|
|
EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 0U);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Option, SlurpJoinedOneJoined) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
const char *MyArgs[] = { "-A", "-slurpjoinedfoo" };
|
|
|
|
InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_A));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
|
|
|
|
EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 1U);
|
|
|
|
EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined)[0], "foo");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Option, SlurpJoinedAndSeparate) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
const char *MyArgs[] = { "-A", "-slurpjoinedfoo", "bar", "baz" };
|
|
|
|
InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_A));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
|
|
|
|
EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size());
|
|
|
|
EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]);
|
|
|
|
EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]);
|
|
|
|
EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Option, SlurpJoinedButSeparate) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
const char *MyArgs[] = { "-A", "-slurpjoined", "foo", "bar", "baz" };
|
|
|
|
InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_A));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined));
|
|
|
|
EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size());
|
|
|
|
EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]);
|
|
|
|
EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]);
|
|
|
|
EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
|
|
|
|
}
|
|
|
|
|
2015-05-04 20:00:13 +02:00
|
|
|
TEST(Option, FlagAliasToJoined) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
// Check that a flag alias provides an empty argument to a joined option.
|
|
|
|
const char *MyArgs[] = { "-K" };
|
2015-06-23 00:06:37 +02:00
|
|
|
InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC);
|
|
|
|
EXPECT_EQ(AL.size(), 1U);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_B));
|
2016-04-15 02:23:15 +02:00
|
|
|
EXPECT_EQ(1U, AL.getAllArgValues(OPT_B).size());
|
|
|
|
EXPECT_EQ("", AL.getAllArgValues(OPT_B)[0]);
|
2015-05-04 20:00:13 +02:00
|
|
|
}
|
[Option] Add 'findNearest' method to catch typos
Summary:
Add a method `OptTable::findNearest`, which allows users of OptTable to
check user input for misspelled options. In addition, have llvm-mt
check for misspelled options. For example, if a user invokes
`llvm-mt /oyt:foo`, the error message will indicate that while an
option named `/oyt:` does not exist, `/out:` does.
The method ports the functionality of the `LookupNearestOption` method
from LLVM CommandLine to libLLVMOption. This allows tools like Clang
and Swift, which do not use CommandLine, to use this functionality to
suggest similarly spelled options.
As room for future improvement, the new method as-is cannot yet properly suggest
nearby "joined" options -- that is, for an option string "-FozBar", where
"-Foo" is the correct option name and "Bar" is the value being passed along
with the misspelled option, this method will calculate an edit distance of 4,
by deleting "Bar" and changing "z" to "o". It should instead calculate an edit
distance of just 1, by changing "z" to "o" and recognizing "Bar" as a
value. This commit includes a disabled test that expresses this limitation.
Test Plan: `check-llvm`
Reviewers: yamaguchi, v.g.vassilev, teemperor, ruiu, jroelofs
Reviewed By: jroelofs
Subscribers: jroelofs, llvm-commits
Differential Revision: https://reviews.llvm.org/D41732
llvm-svn: 321877
2018-01-05 18:10:39 +01:00
|
|
|
|
|
|
|
TEST(Option, FindNearest) {
|
|
|
|
TestOptTable T;
|
|
|
|
std::string Nearest;
|
|
|
|
|
|
|
|
// Options that are too short should not be considered
|
|
|
|
// "near" other short options.
|
|
|
|
EXPECT_GT(T.findNearest("-A", Nearest), 4U);
|
|
|
|
EXPECT_GT(T.findNearest("/C", Nearest), 4U);
|
|
|
|
EXPECT_GT(T.findNearest("--C=foo", Nearest), 4U);
|
|
|
|
|
|
|
|
// The nearest candidate should mirror the amount of prefix
|
|
|
|
// characters used in the original string.
|
|
|
|
EXPECT_EQ(1U, T.findNearest("-blorb", Nearest));
|
|
|
|
EXPECT_EQ(Nearest, "-blorp");
|
|
|
|
EXPECT_EQ(1U, T.findNearest("--blorm", Nearest));
|
|
|
|
EXPECT_EQ(Nearest, "--blorp");
|
2019-04-30 19:46:00 +02:00
|
|
|
EXPECT_EQ(1U, T.findNearest("-blarg", Nearest));
|
|
|
|
EXPECT_EQ(Nearest, "-blarn");
|
|
|
|
EXPECT_EQ(1U, T.findNearest("--blarm", Nearest));
|
|
|
|
EXPECT_EQ(Nearest, "--blarn");
|
[Option] For typo '-foo', suggest '--foo'
Summary:
https://reviews.llvm.org/rL321877 introduced the `OptTable::findNearest`
method, to find the closest edit distance option for a given string.
However, the implementation contained a bug: for a typo `-foo` with an
edit distance of 1 away from a valid option `--foo`, `findNearest`
would suggest a nearby option of `foo`. That is, the result would not
include the `--` prefix, and so was not a valid option.
Fix the bug by ensuring that the prefix string is initialized to one of
the valid prefixes for the option.
Test Plan: `check-llvm-unit`
Reviewers: v.g.vassilev, teemperor, ruiu, jroelofs, yamaguchi
Reviewed By: jroelofs
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D41873
llvm-svn: 322109
2018-01-09 20:38:04 +01:00
|
|
|
EXPECT_EQ(1U, T.findNearest("-fjormp", Nearest));
|
|
|
|
EXPECT_EQ(Nearest, "--fjormp");
|
[Option] Add 'findNearest' method to catch typos
Summary:
Add a method `OptTable::findNearest`, which allows users of OptTable to
check user input for misspelled options. In addition, have llvm-mt
check for misspelled options. For example, if a user invokes
`llvm-mt /oyt:foo`, the error message will indicate that while an
option named `/oyt:` does not exist, `/out:` does.
The method ports the functionality of the `LookupNearestOption` method
from LLVM CommandLine to libLLVMOption. This allows tools like Clang
and Swift, which do not use CommandLine, to use this functionality to
suggest similarly spelled options.
As room for future improvement, the new method as-is cannot yet properly suggest
nearby "joined" options -- that is, for an option string "-FozBar", where
"-Foo" is the correct option name and "Bar" is the value being passed along
with the misspelled option, this method will calculate an edit distance of 4,
by deleting "Bar" and changing "z" to "o". It should instead calculate an edit
distance of just 1, by changing "z" to "o" and recognizing "Bar" as a
value. This commit includes a disabled test that expresses this limitation.
Test Plan: `check-llvm`
Reviewers: yamaguchi, v.g.vassilev, teemperor, ruiu, jroelofs
Reviewed By: jroelofs
Subscribers: jroelofs, llvm-commits
Differential Revision: https://reviews.llvm.org/D41732
llvm-svn: 321877
2018-01-05 18:10:39 +01:00
|
|
|
|
|
|
|
// The nearest candidate respects the prefix and value delimiter
|
|
|
|
// of the original string.
|
|
|
|
EXPECT_EQ(1U, T.findNearest("/framb:foo", Nearest));
|
|
|
|
EXPECT_EQ(Nearest, "/cramb:foo");
|
|
|
|
|
2019-05-01 18:45:15 +02:00
|
|
|
// `--glormp` should have an editing distance > 0 from `--glormp=`.
|
|
|
|
EXPECT_GT(T.findNearest("--glorrmp", Nearest), 0U);
|
|
|
|
EXPECT_EQ(Nearest, "--glorrmp=");
|
|
|
|
EXPECT_EQ(0U, T.findNearest("--glorrmp=foo", Nearest));
|
|
|
|
|
|
|
|
// `--blurmps` should correct to `--blurmp`, not `--blurmp=`, even though
|
|
|
|
// both naively have an editing distance of 1.
|
|
|
|
EXPECT_EQ(1U, T.findNearest("--blurmps", Nearest));
|
|
|
|
EXPECT_EQ(Nearest, "--blurmp");
|
|
|
|
|
|
|
|
// ...but `--blurmps=foo` should correct to `--blurmp=foo`.
|
|
|
|
EXPECT_EQ(1U, T.findNearest("--blurmps=foo", Nearest));
|
|
|
|
EXPECT_EQ(Nearest, "--blurmp=foo");
|
2019-05-01 16:46:17 +02:00
|
|
|
|
[Option] Add 'findNearest' method to catch typos
Summary:
Add a method `OptTable::findNearest`, which allows users of OptTable to
check user input for misspelled options. In addition, have llvm-mt
check for misspelled options. For example, if a user invokes
`llvm-mt /oyt:foo`, the error message will indicate that while an
option named `/oyt:` does not exist, `/out:` does.
The method ports the functionality of the `LookupNearestOption` method
from LLVM CommandLine to libLLVMOption. This allows tools like Clang
and Swift, which do not use CommandLine, to use this functionality to
suggest similarly spelled options.
As room for future improvement, the new method as-is cannot yet properly suggest
nearby "joined" options -- that is, for an option string "-FozBar", where
"-Foo" is the correct option name and "Bar" is the value being passed along
with the misspelled option, this method will calculate an edit distance of 4,
by deleting "Bar" and changing "z" to "o". It should instead calculate an edit
distance of just 1, by changing "z" to "o" and recognizing "Bar" as a
value. This commit includes a disabled test that expresses this limitation.
Test Plan: `check-llvm`
Reviewers: yamaguchi, v.g.vassilev, teemperor, ruiu, jroelofs
Reviewed By: jroelofs
Subscribers: jroelofs, llvm-commits
Differential Revision: https://reviews.llvm.org/D41732
llvm-svn: 321877
2018-01-05 18:10:39 +01:00
|
|
|
// Flags should be included and excluded as specified.
|
|
|
|
EXPECT_EQ(1U, T.findNearest("-doopf", Nearest, /*FlagsToInclude=*/OptFlag2));
|
|
|
|
EXPECT_EQ(Nearest, "-doopf2");
|
|
|
|
EXPECT_EQ(1U, T.findNearest("-doopf", Nearest,
|
|
|
|
/*FlagsToInclude=*/0,
|
|
|
|
/*FlagsToExclude=*/OptFlag2));
|
|
|
|
EXPECT_EQ(Nearest, "-doopf1");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(DISABLED_Option, FindNearestFIXME) {
|
|
|
|
TestOptTable T;
|
|
|
|
std::string Nearest;
|
|
|
|
|
|
|
|
// FIXME: Options with joined values should not have those values considered
|
|
|
|
// when calculating distance. The test below would fail if run, but it should
|
|
|
|
// succeed.
|
|
|
|
EXPECT_EQ(1U, T.findNearest("--erbghFoo", Nearest));
|
|
|
|
EXPECT_EQ(Nearest, "--ermghFoo");
|
|
|
|
|
|
|
|
}
|
2020-07-17 18:18:24 +02:00
|
|
|
|
|
|
|
TEST(Option, ParseGroupedShortOptions) {
|
|
|
|
TestOptTable T;
|
|
|
|
T.setGroupedShortOptions(true);
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
|
|
|
|
// Grouped short options can be followed by a long Flag (-Joo), or a non-Flag
|
|
|
|
// option (-C=1).
|
|
|
|
const char *Args1[] = {"-AIJ", "-AIJoo", "-AC=1"};
|
|
|
|
InputArgList AL = T.ParseArgs(Args1, MAI, MAC);
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_A));
|
|
|
|
EXPECT_TRUE(AL.hasArg(OPT_H));
|
|
|
|
ASSERT_EQ((size_t)2, AL.getAllArgValues(OPT_B).size());
|
|
|
|
EXPECT_EQ("foo", AL.getAllArgValues(OPT_B)[0]);
|
|
|
|
EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]);
|
|
|
|
ASSERT_TRUE(AL.hasArg(OPT_C));
|
|
|
|
EXPECT_EQ("1", AL.getAllArgValues(OPT_C)[0]);
|
|
|
|
|
|
|
|
// Prefer a long option to a short option.
|
|
|
|
const char *Args2[] = {"-AB"};
|
|
|
|
InputArgList AL2 = T.ParseArgs(Args2, MAI, MAC);
|
|
|
|
EXPECT_TRUE(!AL2.hasArg(OPT_A));
|
|
|
|
EXPECT_TRUE(AL2.hasArg(OPT_AB));
|
|
|
|
|
|
|
|
// Short options followed by a long option. We probably should disallow this.
|
|
|
|
const char *Args3[] = {"-AIblorp"};
|
|
|
|
InputArgList AL3 = T.ParseArgs(Args3, MAI, MAC);
|
|
|
|
EXPECT_TRUE(AL3.hasArg(OPT_A));
|
|
|
|
EXPECT_TRUE(AL3.hasArg(OPT_Blorp));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Option, UnknownOptions) {
|
|
|
|
TestOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
|
|
|
const char *Args[] = {"-u", "--long", "0"};
|
|
|
|
for (int I = 0; I < 2; ++I) {
|
|
|
|
T.setGroupedShortOptions(I != 0);
|
|
|
|
InputArgList AL = T.ParseArgs(Args, MAI, MAC);
|
|
|
|
const std::vector<std::string> Unknown = AL.getAllArgValues(OPT_UNKNOWN);
|
|
|
|
ASSERT_EQ((size_t)2, Unknown.size());
|
|
|
|
EXPECT_EQ("-u", Unknown[0]);
|
|
|
|
EXPECT_EQ("--long", Unknown[1]);
|
|
|
|
}
|
|
|
|
}
|