Skip to content

Commit c6ea4d5

Browse files
committed
[clang][cli] Implement ContainsN Google Test matcher
This allows us to verify that we don't emit options multiple times. In most cases, that would be benign, but for options with `MarshallingInfoVectorString`, emitting wrong number of arguments might change the semantics. Reviewed By: Bigcheese Differential Revision: https://reviews.llvm.org/D93636
1 parent 77db83a commit c6ea4d5

File tree

1 file changed

+65
-5
lines changed

1 file changed

+65
-5
lines changed

clang/unittests/Frontend/CompilerInvocationTest.cpp

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,61 @@ class CommandLineTest : public ::testing::Test {
3939
}
4040
};
4141

42+
template <typename M>
43+
std::string describeContainsN(M InnerMatcher, unsigned N, bool Negation) {
44+
StringRef Contains = Negation ? "doesn't contain" : "contains";
45+
StringRef Instance = N == 1 ? " instance " : " instances ";
46+
StringRef Element = "of element that ";
47+
48+
std::ostringstream Inner;
49+
InnerMatcher.impl().DescribeTo(&Inner);
50+
51+
return (Contains + " exactly " + Twine(N) + Instance + Element + Inner.str())
52+
.str();
53+
}
54+
55+
MATCHER_P2(ContainsN, InnerMatcher, N,
56+
describeContainsN(InnerMatcher, N, negation)) {
57+
auto InnerMatches = [this](const auto &Element) {
58+
::testing::internal::DummyMatchResultListener InnerListener;
59+
return InnerMatcher.impl().MatchAndExplain(Element, &InnerListener);
60+
};
61+
62+
return count_if(arg, InnerMatches) == N;
63+
}
64+
65+
TEST(ContainsN, Empty) {
66+
const char *Array[] = {""};
67+
68+
ASSERT_THAT(Array, ContainsN(StrEq("x"), 0));
69+
ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
70+
ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
71+
}
72+
73+
TEST(ContainsN, Zero) {
74+
const char *Array[] = {"y"};
75+
76+
ASSERT_THAT(Array, ContainsN(StrEq("x"), 0));
77+
ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
78+
ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
79+
}
80+
81+
TEST(ContainsN, One) {
82+
const char *Array[] = {"a", "b", "x", "z"};
83+
84+
ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 0)));
85+
ASSERT_THAT(Array, ContainsN(StrEq("x"), 1));
86+
ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
87+
}
88+
89+
TEST(ContainsN, Two) {
90+
const char *Array[] = {"x", "a", "b", "x"};
91+
92+
ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 0)));
93+
ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
94+
ASSERT_THAT(Array, ContainsN(StrEq("x"), 2));
95+
}
96+
4297
// Boolean option with a keypath that defaults to true.
4398
// The only flag with a negative spelling can set the keypath to false.
4499

@@ -270,7 +325,7 @@ TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentPos) {
270325

271326
Invocation.generateCC1CommandLine(GeneratedArgs, *this);
272327

273-
ASSERT_EQ(count(GeneratedArgs, StringRef("-fdebug-pass-manager")), 1);
328+
ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fdebug-pass-manager"), 1));
274329
ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
275330
}
276331

@@ -418,7 +473,8 @@ TEST_F(CommandLineTest, StringVectorEmpty) {
418473
ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles.empty());
419474

420475
Invocation.generateCC1CommandLine(GeneratedArgs, *this);
421-
ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-fmodule-map-file="))));
476+
477+
ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-fmodule-map-file"))));
422478
}
423479

424480
TEST_F(CommandLineTest, StringVectorSingle) {
@@ -431,7 +487,9 @@ TEST_F(CommandLineTest, StringVectorSingle) {
431487
std::vector<std::string>({"a"}));
432488

433489
Invocation.generateCC1CommandLine(GeneratedArgs, *this);
434-
ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=a")), 1);
490+
491+
ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1));
492+
ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 1));
435493
}
436494

437495
TEST_F(CommandLineTest, StringVectorMultiple) {
@@ -444,8 +502,10 @@ TEST_F(CommandLineTest, StringVectorMultiple) {
444502
std::vector<std::string>({"a", "b"}));
445503

446504
Invocation.generateCC1CommandLine(GeneratedArgs, *this);
447-
ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=a")), 1);
448-
ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=b")), 1);
505+
506+
ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1));
507+
ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=b"), 1));
508+
ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 2));
449509
}
450510

451511
// A flag that should be parsed only if a condition is met.

0 commit comments

Comments
 (0)