blob: 8df4603dbd11877102ca1ae68476fe6074f227c4 [file] [log] [blame]
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001//===- llvm/unittest/Support/FileCheckTest.cpp - FileCheck tests --===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/Support/FileCheck.h"
10#include "gtest/gtest.h"
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000011#include <unordered_set>
Thomas Preud'hommee038fa72019-04-15 10:10:11 +000012
13using namespace llvm;
14namespace {
15
16class FileCheckTest : public ::testing::Test {};
17
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000018TEST_F(FileCheckTest, Literal) {
19 // Eval returns the literal's value.
20 FileCheckExpressionLiteral Ten(10);
21 Expected<uint64_t> Value = Ten.eval();
22 EXPECT_TRUE(bool(Value));
23 EXPECT_EQ(10U, *Value);
24
25 // Max value can be correctly represented.
26 FileCheckExpressionLiteral Max(std::numeric_limits<uint64_t>::max());
27 Value = Max.eval();
28 EXPECT_TRUE(bool(Value));
29 EXPECT_EQ(std::numeric_limits<uint64_t>::max(), *Value);
30}
31
32static std::string toString(const std::unordered_set<std::string> &Set) {
33 bool First = true;
34 std::string Str;
35 for (StringRef S : Set) {
36 Str += Twine(First ? "{" + S : ", " + S).str();
37 First = false;
38 }
39 Str += '}';
40 return Str;
41}
42
43static void
44expectUndefErrors(std::unordered_set<std::string> ExpectedUndefVarNames,
45 Error Err) {
46 handleAllErrors(std::move(Err), [&](const FileCheckUndefVarError &E) {
47 ExpectedUndefVarNames.erase(E.getVarName());
48 });
49 EXPECT_TRUE(ExpectedUndefVarNames.empty()) << toString(ExpectedUndefVarNames);
50}
51
52static void expectUndefError(const Twine &ExpectedUndefVarName, Error Err) {
53 expectUndefErrors({ExpectedUndefVarName.str()}, std::move(Err));
54}
55
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000056TEST_F(FileCheckTest, NumericVariable) {
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000057 // Undefined variable: getValue and eval fail, error returned by eval holds
58 // the name of the undefined variable and setValue does not trigger assert.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +000059 FileCheckNumericVariable FooVar = FileCheckNumericVariable(1, "FOO");
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000060 EXPECT_EQ("FOO", FooVar.getName());
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000061 FileCheckNumericVariableUse FooVarUse =
62 FileCheckNumericVariableUse("FOO", &FooVar);
63 EXPECT_FALSE(FooVar.getValue());
64 Expected<uint64_t> EvalResult = FooVarUse.eval();
65 EXPECT_FALSE(EvalResult);
66 expectUndefError("FOO", EvalResult.takeError());
Thomas Preud'homme2bf04f22019-07-10 12:49:28 +000067 FooVar.setValue(42);
Thomas Preud'homme71d3f222019-06-06 13:21:06 +000068
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000069 // Defined variable: getValue and eval return value set.
70 Optional<uint64_t> Value = FooVar.getValue();
71 EXPECT_TRUE(bool(Value));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000072 EXPECT_EQ(42U, *Value);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000073 EvalResult = FooVarUse.eval();
74 EXPECT_TRUE(bool(EvalResult));
75 EXPECT_EQ(42U, *EvalResult);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000076
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000077 // Clearing variable: getValue and eval fail. Error returned by eval holds
78 // the name of the cleared variable.
Thomas Preud'homme2bf04f22019-07-10 12:49:28 +000079 FooVar.clearValue();
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000080 Value = FooVar.getValue();
81 EXPECT_FALSE(Value);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000082 EvalResult = FooVarUse.eval();
83 EXPECT_FALSE(EvalResult);
84 expectUndefError("FOO", EvalResult.takeError());
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000085}
86
87uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
88
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000089TEST_F(FileCheckTest, Binop) {
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000090 FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000091 std::unique_ptr<FileCheckNumericVariableUse> FooVarUse =
92 llvm::make_unique<FileCheckNumericVariableUse>("FOO", &FooVar);
93 FileCheckNumericVariable BarVar = FileCheckNumericVariable("BAR", 18);
94 std::unique_ptr<FileCheckNumericVariableUse> BarVarUse =
95 llvm::make_unique<FileCheckNumericVariableUse>("BAR", &BarVar);
96 FileCheckASTBinop Binop =
97 FileCheckASTBinop(doAdd, std::move(FooVarUse), std::move(BarVarUse));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000098
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000099 // Defined variable: eval returns right value.
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000100 Expected<uint64_t> Value = Binop.eval();
Thomas Preud'hommef64b7f62019-07-10 15:31:19 +0000101 EXPECT_TRUE(bool(Value));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000102 EXPECT_EQ(60U, *Value);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000103
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000104 // 1 undefined variable: eval fails, error contains name of undefined
105 // variable.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000106 FooVar.clearValue();
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000107 Value = Binop.eval();
108 EXPECT_FALSE(Value);
109 expectUndefError("FOO", Value.takeError());
110
111 // 2 undefined variables: eval fails, error contains names of all undefined
112 // variables.
113 BarVar.clearValue();
114 Value = Binop.eval();
115 EXPECT_FALSE(Value);
116 expectUndefErrors({"FOO", "BAR"}, Value.takeError());
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000117}
118
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000119TEST_F(FileCheckTest, ValidVarNameStart) {
120 EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('a'));
121 EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('G'));
122 EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('_'));
123 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('2'));
124 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('$'));
125 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('@'));
126 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('+'));
127 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('-'));
128 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart(':'));
129}
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000130
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000131static StringRef bufferize(SourceMgr &SM, StringRef Str) {
132 std::unique_ptr<MemoryBuffer> Buffer =
133 MemoryBuffer::getMemBufferCopy(Str, "TestBuffer");
134 StringRef StrBufferRef = Buffer->getBuffer();
135 SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
136 return StrBufferRef;
137}
138
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000139TEST_F(FileCheckTest, ParseVar) {
140 SourceMgr SM;
141 StringRef OrigVarName = bufferize(SM, "GoodVar42");
142 StringRef VarName = OrigVarName;
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000143 Expected<FileCheckPattern::VariableProperties> ParsedVarResult =
144 FileCheckPattern::parseVariable(VarName, SM);
145 EXPECT_TRUE(bool(ParsedVarResult));
146 EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000147 EXPECT_TRUE(VarName.empty());
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000148 EXPECT_FALSE(ParsedVarResult->IsPseudo);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000149
150 VarName = OrigVarName = bufferize(SM, "$GoodGlobalVar");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000151 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
152 EXPECT_TRUE(bool(ParsedVarResult));
153 EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000154 EXPECT_TRUE(VarName.empty());
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000155 EXPECT_FALSE(ParsedVarResult->IsPseudo);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000156
157 VarName = OrigVarName = bufferize(SM, "@GoodPseudoVar");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000158 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
159 EXPECT_TRUE(bool(ParsedVarResult));
160 EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000161 EXPECT_TRUE(VarName.empty());
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000162 EXPECT_TRUE(ParsedVarResult->IsPseudo);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000163
164 VarName = bufferize(SM, "42BadVar");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000165 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
166 EXPECT_TRUE(errorToBool(ParsedVarResult.takeError()));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000167
168 VarName = bufferize(SM, "$@");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000169 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
170 EXPECT_TRUE(errorToBool(ParsedVarResult.takeError()));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000171
172 VarName = OrigVarName = bufferize(SM, "B@dVar");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000173 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
174 EXPECT_TRUE(bool(ParsedVarResult));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000175 EXPECT_EQ(VarName, OrigVarName.substr(1));
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000176 EXPECT_EQ(ParsedVarResult->Name, "B");
177 EXPECT_FALSE(ParsedVarResult->IsPseudo);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000178
179 VarName = OrigVarName = bufferize(SM, "B$dVar");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000180 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
181 EXPECT_TRUE(bool(ParsedVarResult));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000182 EXPECT_EQ(VarName, OrigVarName.substr(1));
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000183 EXPECT_EQ(ParsedVarResult->Name, "B");
184 EXPECT_FALSE(ParsedVarResult->IsPseudo);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000185
186 VarName = bufferize(SM, "BadVar+");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000187 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
188 EXPECT_TRUE(bool(ParsedVarResult));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000189 EXPECT_EQ(VarName, "+");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000190 EXPECT_EQ(ParsedVarResult->Name, "BadVar");
191 EXPECT_FALSE(ParsedVarResult->IsPseudo);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000192
193 VarName = bufferize(SM, "BadVar-");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000194 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
195 EXPECT_TRUE(bool(ParsedVarResult));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000196 EXPECT_EQ(VarName, "-");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000197 EXPECT_EQ(ParsedVarResult->Name, "BadVar");
198 EXPECT_FALSE(ParsedVarResult->IsPseudo);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000199
200 VarName = bufferize(SM, "BadVar:");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000201 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
202 EXPECT_TRUE(bool(ParsedVarResult));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000203 EXPECT_EQ(VarName, ":");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000204 EXPECT_EQ(ParsedVarResult->Name, "BadVar");
205 EXPECT_FALSE(ParsedVarResult->IsPseudo);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000206}
207
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000208class PatternTester {
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000209private:
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000210 size_t LineNumber = 1;
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000211 SourceMgr SM;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000212 FileCheckRequest Req;
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000213 FileCheckPatternContext Context;
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000214 FileCheckPattern P =
215 FileCheckPattern(Check::CheckPlain, &Context, LineNumber++);
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000216
217public:
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000218 PatternTester() {
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000219 std::vector<std::string> GlobalDefines;
220 GlobalDefines.emplace_back(std::string("#FOO=42"));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000221 GlobalDefines.emplace_back(std::string("BAR=BAZ"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000222 EXPECT_FALSE(
223 errorToBool(Context.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme56f63082019-07-05 16:25:46 +0000224 Context.createLineVariable();
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000225 // Call parsePattern to have @LINE defined.
226 P.parsePattern("N/A", "CHECK", SM, Req);
227 // parsePattern does not expect to be called twice for the same line and
228 // will set FixedStr and RegExStr incorrectly if it is. Therefore prepare
229 // a pattern for a different line.
230 initNextPattern();
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000231 }
232
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000233 void initNextPattern() {
234 P = FileCheckPattern(Check::CheckPlain, &Context, LineNumber++);
235 }
236
237 bool parseNumVarDefExpect(StringRef Expr) {
238 StringRef ExprBufferRef = bufferize(SM, Expr);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000239 return errorToBool(FileCheckPattern::parseNumericVariableDefinition(
Thomas Preud'homme56f63082019-07-05 16:25:46 +0000240 ExprBufferRef, &Context, LineNumber, SM)
241 .takeError());
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000242 }
243
244 bool parseSubstExpect(StringRef Expr) {
245 StringRef ExprBufferRef = bufferize(SM, Expr);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000246 Optional<FileCheckNumericVariable *> DefinedNumericVariable;
247 return errorToBool(P.parseNumericSubstitutionBlock(
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000248 ExprBufferRef, DefinedNumericVariable, false, SM)
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000249 .takeError());
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000250 }
251
252 bool parsePatternExpect(StringRef Pattern) {
253 StringRef PatBufferRef = bufferize(SM, Pattern);
254 return P.parsePattern(PatBufferRef, "CHECK", SM, Req);
255 }
256
257 bool matchExpect(StringRef Buffer) {
258 StringRef BufferRef = bufferize(SM, Buffer);
259 size_t MatchLen;
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000260 return errorToBool(P.match(BufferRef, MatchLen, SM).takeError());
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000261 }
262};
263
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000264TEST_F(FileCheckTest, ParseNumericVariableDefinition) {
265 PatternTester Tester;
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000266
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000267 // Invalid definition of pseudo.
268 EXPECT_TRUE(Tester.parseNumVarDefExpect("@LINE"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000269
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000270 // Conflict with pattern variable.
271 EXPECT_TRUE(Tester.parseNumVarDefExpect("BAR"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000272
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000273 // Defined variable.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000274 EXPECT_FALSE(Tester.parseNumVarDefExpect("FOO"));
275}
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000276
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000277TEST_F(FileCheckTest, ParseExpr) {
278 PatternTester Tester;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000279
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000280 // Variable definition.
281
282 // Definition of invalid variable.
283 EXPECT_TRUE(Tester.parseSubstExpect("10VAR:"));
284 EXPECT_TRUE(Tester.parseSubstExpect("@FOO:"));
285 EXPECT_TRUE(Tester.parseSubstExpect("@LINE:"));
286
287 // Garbage after name of variable being defined.
288 EXPECT_TRUE(Tester.parseSubstExpect("VAR GARBAGE:"));
289
290 // Variable defined to numeric expression.
291 EXPECT_TRUE(Tester.parseSubstExpect("VAR1: FOO"));
292
293 // Acceptable variable definition.
294 EXPECT_FALSE(Tester.parseSubstExpect("VAR1:"));
295 EXPECT_FALSE(Tester.parseSubstExpect(" VAR2:"));
296 EXPECT_FALSE(Tester.parseSubstExpect("VAR3 :"));
297 EXPECT_FALSE(Tester.parseSubstExpect("VAR3: "));
298
299 // Numeric expression.
300
301 // Unacceptable variable.
302 EXPECT_TRUE(Tester.parseSubstExpect("10VAR"));
303 EXPECT_TRUE(Tester.parseSubstExpect("@FOO"));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000304
305 // Only valid variable.
306 EXPECT_FALSE(Tester.parseSubstExpect("@LINE"));
307 EXPECT_FALSE(Tester.parseSubstExpect("FOO"));
Thomas Preud'hommefe7ac172019-07-05 16:25:33 +0000308 EXPECT_FALSE(Tester.parseSubstExpect("UNDEF"));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000309
310 // Use variable defined on same line.
311 EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:]]"));
312 EXPECT_TRUE(Tester.parseSubstExpect("LINE1VAR"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000313
314 // Unsupported operator.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000315 EXPECT_TRUE(Tester.parseSubstExpect("@LINE/2"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000316
317 // Missing offset operand.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000318 EXPECT_TRUE(Tester.parseSubstExpect("@LINE+"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000319
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000320 // Valid expression.
321 EXPECT_FALSE(Tester.parseSubstExpect("@LINE+5"));
322 EXPECT_FALSE(Tester.parseSubstExpect("FOO+4"));
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000323 Tester.initNextPattern();
324 EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+FOO]]"));
325 EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+3-FOO]]"));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000326}
327
328TEST_F(FileCheckTest, ParsePattern) {
329 PatternTester Tester;
330
331 // Space in pattern variable expression.
332 EXPECT_TRUE(Tester.parsePatternExpect("[[ BAR]]"));
333
334 // Invalid variable name.
335 EXPECT_TRUE(Tester.parsePatternExpect("[[42INVALID]]"));
336
337 // Invalid pattern variable definition.
338 EXPECT_TRUE(Tester.parsePatternExpect("[[@PAT:]]"));
339 EXPECT_TRUE(Tester.parsePatternExpect("[[PAT+2:]]"));
340
341 // Collision with numeric variable.
342 EXPECT_TRUE(Tester.parsePatternExpect("[[FOO:]]"));
343
344 // Valid use of pattern variable.
345 EXPECT_FALSE(Tester.parsePatternExpect("[[BAR]]"));
346
347 // Valid pattern variable definition.
348 EXPECT_FALSE(Tester.parsePatternExpect("[[PAT:[0-9]+]]"));
349
350 // Invalid numeric expressions.
351 EXPECT_TRUE(Tester.parsePatternExpect("[[#42INVALID]]"));
352 EXPECT_TRUE(Tester.parsePatternExpect("[[#@FOO]]"));
353 EXPECT_TRUE(Tester.parsePatternExpect("[[#@LINE/2]]"));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000354 EXPECT_TRUE(Tester.parsePatternExpect("[[#YUP:@LINE]]"));
355
356 // Valid numeric expressions and numeric variable definition.
357 EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO]]"));
358 EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE+2]]"));
359 EXPECT_FALSE(Tester.parsePatternExpect("[[#NUMVAR:]]"));
360}
361
362TEST_F(FileCheckTest, Match) {
363 PatternTester Tester;
364
365 // Check matching a definition only matches a number.
366 Tester.parsePatternExpect("[[#NUMVAR:]]");
367 EXPECT_TRUE(Tester.matchExpect("FAIL"));
368 EXPECT_FALSE(Tester.matchExpect("18"));
369
370 // Check matching the variable defined matches the correct number only
371 Tester.initNextPattern();
372 Tester.parsePatternExpect("[[#NUMVAR]] [[#NUMVAR+2]]");
373 EXPECT_TRUE(Tester.matchExpect("19 21"));
374 EXPECT_TRUE(Tester.matchExpect("18 21"));
375 EXPECT_FALSE(Tester.matchExpect("18 20"));
Thomas Preud'hommef6ea43b2019-07-10 12:49:17 +0000376
377 // Check matching a numeric expression using @LINE after match failure uses
378 // the correct value for @LINE.
379 Tester.initNextPattern();
380 EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
381 // Ok, @LINE is 4 now.
382 EXPECT_FALSE(Tester.matchExpect("4"));
383 Tester.initNextPattern();
384 // @LINE is now 5, match with substitution failure.
385 EXPECT_FALSE(Tester.parsePatternExpect("[[#UNKNOWN]]"));
386 EXPECT_TRUE(Tester.matchExpect("FOO"));
387 Tester.initNextPattern();
388 // Check that @LINE is 6 as expected.
389 EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
390 EXPECT_FALSE(Tester.matchExpect("6"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000391}
392
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000393TEST_F(FileCheckTest, Substitution) {
394 SourceMgr SM;
395 FileCheckPatternContext Context;
396 std::vector<std::string> GlobalDefines;
397 GlobalDefines.emplace_back(std::string("FOO=BAR"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000398 EXPECT_FALSE(errorToBool(Context.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000399
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000400 // Substitution of an undefined string variable fails and error holds that
401 // variable's name.
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000402 FileCheckStringSubstitution StringSubstitution =
403 FileCheckStringSubstitution(&Context, "VAR404", 42);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000404 Expected<std::string> SubstValue = StringSubstitution.getResult();
Thomas Preud'hommef64b7f62019-07-10 15:31:19 +0000405 EXPECT_FALSE(bool(SubstValue));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000406 expectUndefError("VAR404", SubstValue.takeError());
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000407
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000408 // Substitutions of defined pseudo and non-pseudo numeric variables return
409 // the right value.
410 FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000411 FileCheckNumericVariable NVar = FileCheckNumericVariable("N", 10);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000412 auto LineVarUse =
413 llvm::make_unique<FileCheckNumericVariableUse>("@LINE", &LineVar);
414 auto NVarUse = llvm::make_unique<FileCheckNumericVariableUse>("N", &NVar);
415 FileCheckNumericSubstitution SubstitutionLine = FileCheckNumericSubstitution(
416 &Context, "@LINE", std::move(LineVarUse), 12);
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000417 FileCheckNumericSubstitution SubstitutionN =
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000418 FileCheckNumericSubstitution(&Context, "N", std::move(NVarUse), 30);
419 SubstValue = SubstitutionLine.getResult();
420 EXPECT_TRUE(bool(SubstValue));
421 EXPECT_EQ("42", *SubstValue);
422 SubstValue = SubstitutionN.getResult();
423 EXPECT_TRUE(bool(SubstValue));
424 EXPECT_EQ("10", *SubstValue);
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000425
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000426 // Substitution of an undefined numeric variable fails, error holds name of
427 // undefined variable.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000428 LineVar.clearValue();
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000429 SubstValue = SubstitutionLine.getResult();
Thomas Preud'hommef64b7f62019-07-10 15:31:19 +0000430 EXPECT_FALSE(bool(SubstValue));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000431 expectUndefError("@LINE", SubstValue.takeError());
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000432 NVar.clearValue();
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000433 SubstValue = SubstitutionN.getResult();
Thomas Preud'hommef64b7f62019-07-10 15:31:19 +0000434 EXPECT_FALSE(bool(SubstValue));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000435 expectUndefError("N", SubstValue.takeError());
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000436
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000437 // Substitution of a defined string variable returns the right value.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000438 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context, 1);
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000439 StringSubstitution = FileCheckStringSubstitution(&Context, "FOO", 42);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000440 SubstValue = StringSubstitution.getResult();
441 EXPECT_TRUE(bool(SubstValue));
442 EXPECT_EQ("BAR", *SubstValue);
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000443}
444
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000445TEST_F(FileCheckTest, FileCheckContext) {
446 FileCheckPatternContext Cxt = FileCheckPatternContext();
447 std::vector<std::string> GlobalDefines;
448 SourceMgr SM;
449
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000450 // Missing equal sign.
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000451 GlobalDefines.emplace_back(std::string("LocalVar"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000452 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000453 GlobalDefines.clear();
454 GlobalDefines.emplace_back(std::string("#LocalNumVar"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000455 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000456
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000457 // Empty variable name.
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000458 GlobalDefines.clear();
459 GlobalDefines.emplace_back(std::string("=18"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000460 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000461 GlobalDefines.clear();
462 GlobalDefines.emplace_back(std::string("#=18"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000463 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000464
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000465 // Invalid variable name.
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000466 GlobalDefines.clear();
467 GlobalDefines.emplace_back(std::string("18LocalVar=18"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000468 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000469 GlobalDefines.clear();
470 GlobalDefines.emplace_back(std::string("#18LocalNumVar=18"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000471 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000472
473 // Name conflict between pattern and numeric variable.
474 GlobalDefines.clear();
475 GlobalDefines.emplace_back(std::string("LocalVar=18"));
476 GlobalDefines.emplace_back(std::string("#LocalVar=36"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000477 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000478 Cxt = FileCheckPatternContext();
479 GlobalDefines.clear();
480 GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
481 GlobalDefines.emplace_back(std::string("LocalNumVar=36"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000482 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000483 Cxt = FileCheckPatternContext();
484
485 // Invalid numeric value for numeric variable.
486 GlobalDefines.clear();
487 GlobalDefines.emplace_back(std::string("#LocalNumVar=x"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000488 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000489
490 // Define local variables from command-line.
491 GlobalDefines.clear();
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000492 GlobalDefines.emplace_back(std::string("LocalVar=FOO"));
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000493 GlobalDefines.emplace_back(std::string("EmptyVar="));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000494 GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000495 EXPECT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000496
497 // Check defined variables are present and undefined is absent.
498 StringRef LocalVarStr = "LocalVar";
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000499 StringRef LocalNumVarRef = bufferize(SM, "LocalNumVar");
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000500 StringRef EmptyVarStr = "EmptyVar";
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000501 StringRef UnknownVarStr = "UnknownVar";
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000502 Expected<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000503 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000504 Optional<FileCheckNumericVariable *> DefinedNumericVariable;
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000505 Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionAST =
506 P.parseNumericSubstitutionBlock(LocalNumVarRef, DefinedNumericVariable,
507 /*IsLegacyLineExpr=*/false, SM);
Thomas Preud'hommef64b7f62019-07-10 15:31:19 +0000508 EXPECT_TRUE(bool(LocalVar));
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000509 EXPECT_EQ(*LocalVar, "FOO");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000510 Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
511 Expected<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
512 EXPECT_TRUE(bool(ExpressionAST));
513 Expected<uint64_t> ExpressionVal = (*ExpressionAST)->eval();
Thomas Preud'hommef64b7f62019-07-10 15:31:19 +0000514 EXPECT_TRUE(bool(ExpressionVal));
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000515 EXPECT_EQ(*ExpressionVal, 18U);
Thomas Preud'hommef64b7f62019-07-10 15:31:19 +0000516 EXPECT_TRUE(bool(EmptyVar));
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000517 EXPECT_EQ(*EmptyVar, "");
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000518 EXPECT_TRUE(errorToBool(UnknownVar.takeError()));
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000519
520 // Clear local variables and check they become absent.
521 Cxt.clearLocalVars();
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000522 LocalVar = Cxt.getPatternVarValue(LocalVarStr);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000523 EXPECT_TRUE(errorToBool(LocalVar.takeError()));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000524 // Check a numeric expression's evaluation fails if called after clearing of
525 // local variables, if it was created before. This is important because local
526 // variable clearing due to --enable-var-scope happens after numeric
527 // expressions are linked to the numeric variables they use.
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000528 EXPECT_TRUE(errorToBool((*ExpressionAST)->eval().takeError()));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000529 P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000530 ExpressionAST = P.parseNumericSubstitutionBlock(
531 LocalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
532 EXPECT_TRUE(bool(ExpressionAST));
533 ExpressionVal = (*ExpressionAST)->eval();
Thomas Preud'hommefe7ac172019-07-05 16:25:33 +0000534 EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000535 EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000536 EXPECT_TRUE(errorToBool(EmptyVar.takeError()));
Thomas Preud'hommefe7ac172019-07-05 16:25:33 +0000537 // Clear again because parseNumericSubstitutionBlock would have created a
538 // dummy variable and stored it in GlobalNumericVariableTable.
539 Cxt.clearLocalVars();
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000540
541 // Redefine global variables and check variables are defined again.
542 GlobalDefines.emplace_back(std::string("$GlobalVar=BAR"));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000543 GlobalDefines.emplace_back(std::string("#$GlobalNumVar=36"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000544 EXPECT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000545 StringRef GlobalVarStr = "$GlobalVar";
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000546 StringRef GlobalNumVarRef = bufferize(SM, "$GlobalNumVar");
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000547 Expected<StringRef> GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
Thomas Preud'hommef64b7f62019-07-10 15:31:19 +0000548 EXPECT_TRUE(bool(GlobalVar));
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000549 EXPECT_EQ(*GlobalVar, "BAR");
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000550 P = FileCheckPattern(Check::CheckPlain, &Cxt, 3);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000551 ExpressionAST = P.parseNumericSubstitutionBlock(
552 GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
553 EXPECT_TRUE(bool(ExpressionAST));
554 ExpressionVal = (*ExpressionAST)->eval();
Thomas Preud'hommef64b7f62019-07-10 15:31:19 +0000555 EXPECT_TRUE(bool(ExpressionVal));
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000556 EXPECT_EQ(*ExpressionVal, 36U);
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000557
558 // Clear local variables and check global variables remain defined.
559 Cxt.clearLocalVars();
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000560 EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError()));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000561 P = FileCheckPattern(Check::CheckPlain, &Cxt, 4);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000562 ExpressionAST = P.parseNumericSubstitutionBlock(
563 GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
564 EXPECT_TRUE(bool(ExpressionAST));
565 ExpressionVal = (*ExpressionAST)->eval();
Thomas Preud'hommef64b7f62019-07-10 15:31:19 +0000566 EXPECT_TRUE(bool(ExpressionVal));
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000567 EXPECT_EQ(*ExpressionVal, 36U);
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000568}
569} // namespace