147
|
1 //===- 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"
|
|
11 #include <unordered_set>
|
|
12
|
|
13 using namespace llvm;
|
|
14 namespace {
|
|
15
|
|
16 class FileCheckTest : public ::testing::Test {};
|
|
17
|
|
18 TEST_F(FileCheckTest, Literal) {
|
|
19 // Eval returns the literal's value.
|
|
20 FileCheckExpressionLiteral Ten(10);
|
|
21 Expected<uint64_t> Value = Ten.eval();
|
|
22 ASSERT_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 ASSERT_TRUE(bool(Value));
|
|
29 EXPECT_EQ(std::numeric_limits<uint64_t>::max(), *Value);
|
|
30 }
|
|
31
|
|
32 static 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
|
|
43 static void
|
|
44 expectUndefErrors(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
|
|
52 // Return whether Err contains any FileCheckUndefVarError whose associated name
|
|
53 // is not ExpectedUndefVarName.
|
|
54 static void expectUndefError(const Twine &ExpectedUndefVarName, Error Err) {
|
|
55 expectUndefErrors({ExpectedUndefVarName.str()}, std::move(Err));
|
|
56 }
|
|
57
|
|
58 uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
|
|
59
|
|
60 TEST_F(FileCheckTest, NumericVariable) {
|
|
61 // Undefined variable: isValueKnownAtMatchTime returns false, getValue and
|
|
62 // eval fail, error returned by eval holds the name of the undefined
|
|
63 // variable.
|
|
64 FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 1);
|
|
65 EXPECT_EQ("FOO", FooVar.getName());
|
|
66 EXPECT_FALSE(FooVar.isValueKnownAtMatchTime());
|
|
67 FileCheckNumericVariableUse FooVarUse =
|
|
68 FileCheckNumericVariableUse("FOO", &FooVar);
|
|
69 EXPECT_FALSE(FooVar.getValue());
|
|
70 Expected<uint64_t> EvalResult = FooVarUse.eval();
|
|
71 ASSERT_FALSE(EvalResult);
|
|
72 expectUndefError("FOO", EvalResult.takeError());
|
|
73
|
|
74 FooVar.setValue(42);
|
|
75
|
|
76 // Defined variable: isValueKnownAtMatchTime returns true, getValue and eval
|
|
77 // return value set.
|
|
78 EXPECT_TRUE(FooVar.isValueKnownAtMatchTime());
|
|
79 Optional<uint64_t> Value = FooVar.getValue();
|
|
80 ASSERT_TRUE(bool(Value));
|
|
81 EXPECT_EQ(42U, *Value);
|
|
82 EvalResult = FooVarUse.eval();
|
|
83 ASSERT_TRUE(bool(EvalResult));
|
|
84 EXPECT_EQ(42U, *EvalResult);
|
|
85
|
|
86 // Variable defined by numeric expression: isValueKnownAtMatchTime
|
|
87 // returns true, getValue and eval return value of expression, setValue
|
|
88 // clears expression.
|
|
89 std::unique_ptr<FileCheckNumericVariableUse> FooVarUsePtr =
|
|
90 llvm::make_unique<FileCheckNumericVariableUse>("FOO", &FooVar);
|
|
91 std::unique_ptr<FileCheckExpressionLiteral> One =
|
|
92 llvm::make_unique<FileCheckExpressionLiteral>(1);
|
|
93 FileCheckASTBinop Binop =
|
|
94 FileCheckASTBinop(doAdd, std::move(FooVarUsePtr), std::move(One));
|
|
95 FileCheckNumericVariable FoobarExprVar =
|
|
96 FileCheckNumericVariable("FOOBAR", 2, &Binop);
|
|
97 EXPECT_TRUE(FoobarExprVar.isValueKnownAtMatchTime());
|
|
98 ASSERT_FALSE(FoobarExprVar.getValue());
|
|
99 FileCheckNumericVariableUse FoobarExprVarUse =
|
|
100 FileCheckNumericVariableUse("FOOBAR", &FoobarExprVar);
|
|
101 EvalResult = FoobarExprVarUse.eval();
|
|
102 ASSERT_TRUE(bool(EvalResult));
|
|
103 EXPECT_EQ(43U, *EvalResult);
|
|
104 EXPECT_TRUE(FoobarExprVar.getExpressionAST());
|
|
105 FoobarExprVar.setValue(43);
|
|
106 EXPECT_FALSE(FoobarExprVar.getExpressionAST());
|
|
107 FoobarExprVar = FileCheckNumericVariable("FOOBAR", 2, &Binop);
|
|
108 EXPECT_TRUE(FoobarExprVar.getExpressionAST());
|
|
109
|
|
110 // Clearing variable: getValue and eval fail. Error returned by eval holds
|
|
111 // the name of the cleared variable.
|
|
112 FooVar.clearValue();
|
|
113 FoobarExprVar.clearValue();
|
|
114 EXPECT_FALSE(FoobarExprVar.getExpressionAST());
|
|
115 EXPECT_FALSE(FooVar.getValue());
|
|
116 EXPECT_FALSE(FoobarExprVar.getValue());
|
|
117 EvalResult = FooVarUse.eval();
|
|
118 ASSERT_FALSE(EvalResult);
|
|
119 expectUndefError("FOO", EvalResult.takeError());
|
|
120 EvalResult = FoobarExprVarUse.eval();
|
|
121 ASSERT_FALSE(EvalResult);
|
|
122 expectUndefError("FOOBAR", EvalResult.takeError());
|
|
123 }
|
|
124
|
|
125 TEST_F(FileCheckTest, Binop) {
|
|
126 FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 1);
|
|
127 FooVar.setValue(42);
|
|
128 std::unique_ptr<FileCheckNumericVariableUse> FooVarUse =
|
|
129 llvm::make_unique<FileCheckNumericVariableUse>("FOO", &FooVar);
|
|
130 FileCheckNumericVariable BarVar = FileCheckNumericVariable("BAR", 2);
|
|
131 BarVar.setValue(18);
|
|
132 std::unique_ptr<FileCheckNumericVariableUse> BarVarUse =
|
|
133 llvm::make_unique<FileCheckNumericVariableUse>("BAR", &BarVar);
|
|
134 FileCheckASTBinop Binop =
|
|
135 FileCheckASTBinop(doAdd, std::move(FooVarUse), std::move(BarVarUse));
|
|
136
|
|
137 // Defined variable: eval returns right value.
|
|
138 Expected<uint64_t> Value = Binop.eval();
|
|
139 ASSERT_TRUE(bool(Value));
|
|
140 EXPECT_EQ(60U, *Value);
|
|
141
|
|
142 // 1 undefined variable: eval fails, error contains name of undefined
|
|
143 // variable.
|
|
144 FooVar.clearValue();
|
|
145 Value = Binop.eval();
|
|
146 ASSERT_FALSE(Value);
|
|
147 expectUndefError("FOO", Value.takeError());
|
|
148
|
|
149 // 2 undefined variables: eval fails, error contains names of all undefined
|
|
150 // variables.
|
|
151 BarVar.clearValue();
|
|
152 Value = Binop.eval();
|
|
153 ASSERT_FALSE(Value);
|
|
154 expectUndefErrors({"FOO", "BAR"}, Value.takeError());
|
|
155 }
|
|
156
|
|
157 TEST_F(FileCheckTest, ValidVarNameStart) {
|
|
158 EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('a'));
|
|
159 EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('G'));
|
|
160 EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('_'));
|
|
161 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('2'));
|
|
162 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('$'));
|
|
163 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('@'));
|
|
164 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('+'));
|
|
165 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('-'));
|
|
166 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart(':'));
|
|
167 }
|
|
168
|
|
169 static StringRef bufferize(SourceMgr &SM, StringRef Str) {
|
|
170 std::unique_ptr<MemoryBuffer> Buffer =
|
|
171 MemoryBuffer::getMemBufferCopy(Str, "TestBuffer");
|
|
172 StringRef StrBufferRef = Buffer->getBuffer();
|
|
173 SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
|
|
174 return StrBufferRef;
|
|
175 }
|
|
176
|
|
177 TEST_F(FileCheckTest, ParseVar) {
|
|
178 SourceMgr SM;
|
|
179 StringRef OrigVarName = bufferize(SM, "GoodVar42");
|
|
180 StringRef VarName = OrigVarName;
|
|
181 Expected<FileCheckPattern::VariableProperties> ParsedVarResult =
|
|
182 FileCheckPattern::parseVariable(VarName, SM);
|
|
183 ASSERT_TRUE(bool(ParsedVarResult));
|
|
184 EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
|
|
185 EXPECT_TRUE(VarName.empty());
|
|
186 EXPECT_FALSE(ParsedVarResult->IsPseudo);
|
|
187
|
|
188 VarName = OrigVarName = bufferize(SM, "$GoodGlobalVar");
|
|
189 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
|
|
190 ASSERT_TRUE(bool(ParsedVarResult));
|
|
191 EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
|
|
192 EXPECT_TRUE(VarName.empty());
|
|
193 EXPECT_FALSE(ParsedVarResult->IsPseudo);
|
|
194
|
|
195 VarName = OrigVarName = bufferize(SM, "@GoodPseudoVar");
|
|
196 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
|
|
197 ASSERT_TRUE(bool(ParsedVarResult));
|
|
198 EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
|
|
199 EXPECT_TRUE(VarName.empty());
|
|
200 EXPECT_TRUE(ParsedVarResult->IsPseudo);
|
|
201
|
|
202 VarName = bufferize(SM, "42BadVar");
|
|
203 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
|
|
204 EXPECT_TRUE(errorToBool(ParsedVarResult.takeError()));
|
|
205
|
|
206 VarName = bufferize(SM, "$@");
|
|
207 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
|
|
208 EXPECT_TRUE(errorToBool(ParsedVarResult.takeError()));
|
|
209
|
|
210 VarName = OrigVarName = bufferize(SM, "B@dVar");
|
|
211 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
|
|
212 ASSERT_TRUE(bool(ParsedVarResult));
|
|
213 EXPECT_EQ(VarName, OrigVarName.substr(1));
|
|
214 EXPECT_EQ(ParsedVarResult->Name, "B");
|
|
215 EXPECT_FALSE(ParsedVarResult->IsPseudo);
|
|
216
|
|
217 VarName = OrigVarName = bufferize(SM, "B$dVar");
|
|
218 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
|
|
219 ASSERT_TRUE(bool(ParsedVarResult));
|
|
220 EXPECT_EQ(VarName, OrigVarName.substr(1));
|
|
221 EXPECT_EQ(ParsedVarResult->Name, "B");
|
|
222 EXPECT_FALSE(ParsedVarResult->IsPseudo);
|
|
223
|
|
224 VarName = bufferize(SM, "BadVar+");
|
|
225 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
|
|
226 ASSERT_TRUE(bool(ParsedVarResult));
|
|
227 EXPECT_EQ(VarName, "+");
|
|
228 EXPECT_EQ(ParsedVarResult->Name, "BadVar");
|
|
229 EXPECT_FALSE(ParsedVarResult->IsPseudo);
|
|
230
|
|
231 VarName = bufferize(SM, "BadVar-");
|
|
232 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
|
|
233 ASSERT_TRUE(bool(ParsedVarResult));
|
|
234 EXPECT_EQ(VarName, "-");
|
|
235 EXPECT_EQ(ParsedVarResult->Name, "BadVar");
|
|
236 EXPECT_FALSE(ParsedVarResult->IsPseudo);
|
|
237
|
|
238 VarName = bufferize(SM, "BadVar:");
|
|
239 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
|
|
240 ASSERT_TRUE(bool(ParsedVarResult));
|
|
241 EXPECT_EQ(VarName, ":");
|
|
242 EXPECT_EQ(ParsedVarResult->Name, "BadVar");
|
|
243 EXPECT_FALSE(ParsedVarResult->IsPseudo);
|
|
244 }
|
|
245
|
|
246 class PatternTester {
|
|
247 private:
|
|
248 size_t LineNumber = 1;
|
|
249 SourceMgr SM;
|
|
250 FileCheckRequest Req;
|
|
251 FileCheckPatternContext Context;
|
|
252 FileCheckPattern P =
|
|
253 FileCheckPattern(Check::CheckPlain, &Context, LineNumber++);
|
|
254
|
|
255 public:
|
|
256 PatternTester() {
|
|
257 std::vector<std::string> GlobalDefines;
|
|
258 GlobalDefines.emplace_back(std::string("#FOO=42"));
|
|
259 GlobalDefines.emplace_back(std::string("BAR=BAZ"));
|
|
260 // An ASSERT_FALSE would make more sense but cannot be used in a
|
|
261 // constructor.
|
|
262 EXPECT_FALSE(
|
|
263 errorToBool(Context.defineCmdlineVariables(GlobalDefines, SM)));
|
|
264 Context.createLineVariable();
|
|
265 // Call parsePattern to have @LINE defined.
|
|
266 P.parsePattern("N/A", "CHECK", SM, Req);
|
|
267 // parsePattern does not expect to be called twice for the same line and
|
|
268 // will set FixedStr and RegExStr incorrectly if it is. Therefore prepare
|
|
269 // a pattern for a different line.
|
|
270 initNextPattern();
|
|
271 }
|
|
272
|
|
273 void initNextPattern() {
|
|
274 P = FileCheckPattern(Check::CheckPlain, &Context, LineNumber++);
|
|
275 }
|
|
276
|
|
277 bool parseSubstExpect(StringRef Expr) {
|
|
278 StringRef ExprBufferRef = bufferize(SM, Expr);
|
|
279 Optional<FileCheckNumericVariable *> DefinedNumericVariable;
|
|
280 return errorToBool(
|
|
281 P.parseNumericSubstitutionBlock(ExprBufferRef, DefinedNumericVariable,
|
|
282 false, LineNumber - 1, &Context, SM)
|
|
283 .takeError());
|
|
284 }
|
|
285
|
|
286 bool parsePatternExpect(StringRef Pattern) {
|
|
287 StringRef PatBufferRef = bufferize(SM, Pattern);
|
|
288 return P.parsePattern(PatBufferRef, "CHECK", SM, Req);
|
|
289 }
|
|
290
|
|
291 bool matchExpect(StringRef Buffer) {
|
|
292 StringRef BufferRef = bufferize(SM, Buffer);
|
|
293 size_t MatchLen;
|
|
294 return errorToBool(P.match(BufferRef, MatchLen, SM).takeError());
|
|
295 }
|
|
296 };
|
|
297
|
|
298 TEST_F(FileCheckTest, ParseExpr) {
|
|
299 PatternTester Tester;
|
|
300
|
|
301 // Variable definition.
|
|
302
|
|
303 // Definition of invalid variable.
|
|
304 EXPECT_TRUE(Tester.parseSubstExpect("10VAR:"));
|
|
305 EXPECT_TRUE(Tester.parseSubstExpect("@FOO:"));
|
|
306 EXPECT_TRUE(Tester.parseSubstExpect("@LINE:"));
|
|
307
|
|
308 // Conflict with pattern variable.
|
|
309 EXPECT_TRUE(Tester.parseSubstExpect("BAR:"));
|
|
310
|
|
311 // Garbage after name of variable being defined.
|
|
312 EXPECT_TRUE(Tester.parseSubstExpect("VAR GARBAGE:"));
|
|
313
|
|
314 // Acceptable variable definition.
|
|
315 EXPECT_FALSE(Tester.parseSubstExpect("VAR1:"));
|
|
316 EXPECT_FALSE(Tester.parseSubstExpect(" VAR2:"));
|
|
317 EXPECT_FALSE(Tester.parseSubstExpect("VAR3 :"));
|
|
318 EXPECT_FALSE(Tester.parseSubstExpect("VAR3: "));
|
|
319 EXPECT_FALSE(Tester.parsePatternExpect("[[#FOOBAR: FOO+1]]"));
|
|
320
|
|
321 // Numeric expression.
|
|
322
|
|
323 // Unacceptable variable.
|
|
324 EXPECT_TRUE(Tester.parseSubstExpect("10VAR"));
|
|
325 EXPECT_TRUE(Tester.parseSubstExpect("@FOO"));
|
|
326
|
|
327 // Only valid variable.
|
|
328 EXPECT_FALSE(Tester.parseSubstExpect("@LINE"));
|
|
329 EXPECT_FALSE(Tester.parseSubstExpect("FOO"));
|
|
330 EXPECT_FALSE(Tester.parseSubstExpect("UNDEF"));
|
|
331
|
|
332 // Valid empty expression.
|
|
333 EXPECT_FALSE(Tester.parseSubstExpect(""));
|
|
334
|
|
335 // Valid use of variable defined on the same line from expression. Note that
|
|
336 // the same pattern object is used for the parsePatternExpect and
|
|
337 // parseSubstExpect since no initNextPattern is called, thus appearing as
|
|
338 // being on the same line from the pattern's point of view.
|
|
339 ASSERT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:FOO+1]]"));
|
|
340 EXPECT_FALSE(Tester.parseSubstExpect("LINE1VAR"));
|
|
341
|
|
342 // Invalid use of variable defined on same line from input. As above, the
|
|
343 // absence of a call to initNextPattern makes it appear to be on the same
|
|
344 // line from the pattern's point of view.
|
|
345 ASSERT_FALSE(Tester.parsePatternExpect("[[#LINE2VAR:]]"));
|
|
346 EXPECT_TRUE(Tester.parseSubstExpect("LINE2VAR"));
|
|
347
|
|
348 // Unsupported operator.
|
|
349 EXPECT_TRUE(Tester.parseSubstExpect("@LINE/2"));
|
|
350
|
|
351 // Missing offset operand.
|
|
352 EXPECT_TRUE(Tester.parseSubstExpect("@LINE+"));
|
|
353
|
|
354 // Valid expression.
|
|
355 EXPECT_FALSE(Tester.parseSubstExpect("@LINE+5"));
|
|
356 EXPECT_FALSE(Tester.parseSubstExpect("FOO+4"));
|
|
357 EXPECT_FALSE(Tester.parseSubstExpect("FOOBAR"));
|
|
358 Tester.initNextPattern();
|
|
359 EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+FOO]]"));
|
|
360 EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+3-FOO]]"));
|
|
361 }
|
|
362
|
|
363 TEST_F(FileCheckTest, ParsePattern) {
|
|
364 PatternTester Tester;
|
|
365
|
|
366 // Space in pattern variable expression.
|
|
367 EXPECT_TRUE(Tester.parsePatternExpect("[[ BAR]]"));
|
|
368
|
|
369 // Invalid variable name.
|
|
370 EXPECT_TRUE(Tester.parsePatternExpect("[[42INVALID]]"));
|
|
371
|
|
372 // Invalid pattern variable definition.
|
|
373 EXPECT_TRUE(Tester.parsePatternExpect("[[@PAT:]]"));
|
|
374 EXPECT_TRUE(Tester.parsePatternExpect("[[PAT+2:]]"));
|
|
375
|
|
376 // Collision with numeric variable.
|
|
377 EXPECT_TRUE(Tester.parsePatternExpect("[[FOO:]]"));
|
|
378
|
|
379 // Valid use of pattern variable.
|
|
380 EXPECT_FALSE(Tester.parsePatternExpect("[[BAR]]"));
|
|
381
|
|
382 // Valid pattern variable definition.
|
|
383 EXPECT_FALSE(Tester.parsePatternExpect("[[PAT:[0-9]+]]"));
|
|
384
|
|
385 // Invalid numeric expressions.
|
|
386 EXPECT_TRUE(Tester.parsePatternExpect("[[#42INVALID]]"));
|
|
387 EXPECT_TRUE(Tester.parsePatternExpect("[[#@FOO]]"));
|
|
388 EXPECT_TRUE(Tester.parsePatternExpect("[[#@LINE/2]]"));
|
|
389
|
|
390 // Valid numeric expressions and numeric variable definition.
|
|
391 EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO]]"));
|
|
392 EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE+2]]"));
|
|
393 EXPECT_FALSE(Tester.parsePatternExpect("[[#NUMVAR:]]"));
|
|
394 }
|
|
395
|
|
396 TEST_F(FileCheckTest, Match) {
|
|
397 PatternTester Tester;
|
|
398
|
|
399 // Check matching an empty expression only matches a number.
|
|
400 Tester.parsePatternExpect("[[#]]");
|
|
401 EXPECT_TRUE(Tester.matchExpect("FAIL"));
|
|
402 EXPECT_FALSE(Tester.matchExpect("18"));
|
|
403
|
|
404 // Check matching a definition only matches a number.
|
|
405 Tester.initNextPattern();
|
|
406 Tester.parsePatternExpect("[[#NUMVAR:]]");
|
|
407 EXPECT_TRUE(Tester.matchExpect("FAIL"));
|
|
408 EXPECT_TRUE(Tester.matchExpect(""));
|
|
409 EXPECT_FALSE(Tester.matchExpect("18"));
|
|
410
|
|
411 // Check matching the variable defined matches the correct number only
|
|
412 Tester.initNextPattern();
|
|
413 Tester.parsePatternExpect("[[#NUMVAR]] [[#NUMVAR+2]]");
|
|
414 EXPECT_TRUE(Tester.matchExpect("19 21"));
|
|
415 EXPECT_TRUE(Tester.matchExpect("18 21"));
|
|
416 EXPECT_FALSE(Tester.matchExpect("18 20"));
|
|
417
|
|
418 // Check matching a numeric expression using @LINE after match failure uses
|
|
419 // the correct value for @LINE.
|
|
420 Tester.initNextPattern();
|
|
421 EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
|
|
422 // Ok, @LINE is 5 now.
|
|
423 EXPECT_FALSE(Tester.matchExpect("5"));
|
|
424 Tester.initNextPattern();
|
|
425 // @LINE is now 6, match with substitution failure.
|
|
426 EXPECT_FALSE(Tester.parsePatternExpect("[[#UNKNOWN]]"));
|
|
427 EXPECT_TRUE(Tester.matchExpect("FOO"));
|
|
428 Tester.initNextPattern();
|
|
429 // Check that @LINE is 7 as expected.
|
|
430 EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
|
|
431 EXPECT_FALSE(Tester.matchExpect("7"));
|
|
432 }
|
|
433
|
|
434 TEST_F(FileCheckTest, Substitution) {
|
|
435 SourceMgr SM;
|
|
436 FileCheckPatternContext Context;
|
|
437 std::vector<std::string> GlobalDefines;
|
|
438 GlobalDefines.emplace_back(std::string("FOO=BAR"));
|
|
439 EXPECT_FALSE(errorToBool(Context.defineCmdlineVariables(GlobalDefines, SM)));
|
|
440
|
|
441 // Substitution of an undefined string variable fails and error holds that
|
|
442 // variable's name.
|
|
443 FileCheckStringSubstitution StringSubstitution =
|
|
444 FileCheckStringSubstitution(&Context, "VAR404", 42);
|
|
445 Expected<std::string> SubstValue = StringSubstitution.getResult();
|
|
446 ASSERT_FALSE(bool(SubstValue));
|
|
447 expectUndefError("VAR404", SubstValue.takeError());
|
|
448
|
|
449 // Substitutions of defined pseudo and non-pseudo numeric variables return
|
|
450 // the right value.
|
|
451 FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 1);
|
|
452 FileCheckNumericVariable NVar = FileCheckNumericVariable("N", 1);
|
|
453 LineVar.setValue(42);
|
|
454 NVar.setValue(10);
|
|
455 auto LineVarUse =
|
|
456 llvm::make_unique<FileCheckNumericVariableUse>("@LINE", &LineVar);
|
|
457 auto NVarUse = llvm::make_unique<FileCheckNumericVariableUse>("N", &NVar);
|
|
458 FileCheckNumericSubstitution SubstitutionLine = FileCheckNumericSubstitution(
|
|
459 &Context, "@LINE", std::move(LineVarUse), 12);
|
|
460 FileCheckNumericSubstitution SubstitutionN =
|
|
461 FileCheckNumericSubstitution(&Context, "N", std::move(NVarUse), 30);
|
|
462 SubstValue = SubstitutionLine.getResult();
|
|
463 ASSERT_TRUE(bool(SubstValue));
|
|
464 EXPECT_EQ("42", *SubstValue);
|
|
465 SubstValue = SubstitutionN.getResult();
|
|
466 ASSERT_TRUE(bool(SubstValue));
|
|
467 EXPECT_EQ("10", *SubstValue);
|
|
468
|
|
469 // Substitution of an undefined numeric variable fails, error holds name of
|
|
470 // undefined variable.
|
|
471 LineVar.clearValue();
|
|
472 SubstValue = SubstitutionLine.getResult();
|
|
473 ASSERT_FALSE(bool(SubstValue));
|
|
474 expectUndefError("@LINE", SubstValue.takeError());
|
|
475 NVar.clearValue();
|
|
476 SubstValue = SubstitutionN.getResult();
|
|
477 ASSERT_FALSE(bool(SubstValue));
|
|
478 expectUndefError("N", SubstValue.takeError());
|
|
479
|
|
480 // Substitution of a defined string variable returns the right value.
|
|
481 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context, 1);
|
|
482 StringSubstitution = FileCheckStringSubstitution(&Context, "FOO", 42);
|
|
483 SubstValue = StringSubstitution.getResult();
|
|
484 ASSERT_TRUE(bool(SubstValue));
|
|
485 EXPECT_EQ("BAR", *SubstValue);
|
|
486 }
|
|
487
|
|
488 TEST_F(FileCheckTest, FileCheckContext) {
|
|
489 FileCheckPatternContext Cxt = FileCheckPatternContext();
|
|
490 std::vector<std::string> GlobalDefines;
|
|
491 SourceMgr SM;
|
|
492
|
|
493 // Missing equal sign.
|
|
494 GlobalDefines.emplace_back(std::string("LocalVar"));
|
|
495 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
|
496 GlobalDefines.clear();
|
|
497 GlobalDefines.emplace_back(std::string("#LocalNumVar"));
|
|
498 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
|
499
|
|
500 // Empty variable name.
|
|
501 GlobalDefines.clear();
|
|
502 GlobalDefines.emplace_back(std::string("=18"));
|
|
503 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
|
504 GlobalDefines.clear();
|
|
505 GlobalDefines.emplace_back(std::string("#=18"));
|
|
506 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
|
507
|
|
508 // Invalid variable name.
|
|
509 GlobalDefines.clear();
|
|
510 GlobalDefines.emplace_back(std::string("18LocalVar=18"));
|
|
511 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
|
512 GlobalDefines.clear();
|
|
513 GlobalDefines.emplace_back(std::string("#18LocalNumVar=18"));
|
|
514 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
|
515
|
|
516 // Name conflict between pattern and numeric variable.
|
|
517 GlobalDefines.clear();
|
|
518 GlobalDefines.emplace_back(std::string("LocalVar=18"));
|
|
519 GlobalDefines.emplace_back(std::string("#LocalVar=36"));
|
|
520 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
|
521 Cxt = FileCheckPatternContext();
|
|
522 GlobalDefines.clear();
|
|
523 GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
|
|
524 GlobalDefines.emplace_back(std::string("LocalNumVar=36"));
|
|
525 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
|
526 Cxt = FileCheckPatternContext();
|
|
527
|
|
528 // Invalid numeric value for numeric variable.
|
|
529 GlobalDefines.clear();
|
|
530 GlobalDefines.emplace_back(std::string("#LocalNumVar=x"));
|
|
531 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
|
532
|
|
533 // Define local variables from command-line.
|
|
534 GlobalDefines.clear();
|
|
535 // Clear local variables to remove dummy numeric variable x that
|
|
536 // parseNumericSubstitutionBlock would have created and stored in
|
|
537 // GlobalNumericVariableTable.
|
|
538 Cxt.clearLocalVars();
|
|
539 GlobalDefines.emplace_back(std::string("LocalVar=FOO"));
|
|
540 GlobalDefines.emplace_back(std::string("EmptyVar="));
|
|
541 GlobalDefines.emplace_back(std::string("#LocalNumVar1=18"));
|
|
542 GlobalDefines.emplace_back(std::string("#LocalNumVar2=LocalNumVar1+2"));
|
|
543 ASSERT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
|
544
|
|
545 // Check defined variables are present and undefined is absent.
|
|
546 StringRef LocalVarStr = "LocalVar";
|
|
547 StringRef LocalNumVar1Ref = bufferize(SM, "LocalNumVar1");
|
|
548 StringRef LocalNumVar2Ref = bufferize(SM, "LocalNumVar2");
|
|
549 StringRef EmptyVarStr = "EmptyVar";
|
|
550 StringRef UnknownVarStr = "UnknownVar";
|
|
551 Expected<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
|
|
552 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1);
|
|
553 Optional<FileCheckNumericVariable *> DefinedNumericVariable;
|
|
554 Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionAST =
|
|
555 P.parseNumericSubstitutionBlock(LocalNumVar1Ref, DefinedNumericVariable,
|
|
556 /*IsLegacyLineExpr=*/false,
|
|
557 /*LineNumber=*/1, &Cxt, SM);
|
|
558 ASSERT_TRUE(bool(LocalVar));
|
|
559 EXPECT_EQ(*LocalVar, "FOO");
|
|
560 Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
|
|
561 Expected<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
|
|
562 ASSERT_TRUE(bool(ExpressionAST));
|
|
563 Expected<uint64_t> ExpressionVal = (*ExpressionAST)->eval();
|
|
564 ASSERT_TRUE(bool(ExpressionVal));
|
|
565 EXPECT_EQ(*ExpressionVal, 18U);
|
|
566 ExpressionAST =
|
|
567 P.parseNumericSubstitutionBlock(LocalNumVar2Ref, DefinedNumericVariable,
|
|
568 /*IsLegacyLineExpr=*/false,
|
|
569 /*LineNumber=*/1, &Cxt, SM);
|
|
570 ASSERT_TRUE(bool(ExpressionAST));
|
|
571 ExpressionVal = (*ExpressionAST)->eval();
|
|
572 ASSERT_TRUE(bool(ExpressionVal));
|
|
573 EXPECT_EQ(*ExpressionVal, 20U);
|
|
574 ASSERT_TRUE(bool(EmptyVar));
|
|
575 EXPECT_EQ(*EmptyVar, "");
|
|
576 EXPECT_TRUE(errorToBool(UnknownVar.takeError()));
|
|
577
|
|
578 // Clear local variables and check they become absent.
|
|
579 Cxt.clearLocalVars();
|
|
580 LocalVar = Cxt.getPatternVarValue(LocalVarStr);
|
|
581 EXPECT_TRUE(errorToBool(LocalVar.takeError()));
|
|
582 // Check a numeric expression's evaluation fails if called after clearing of
|
|
583 // local variables, if it was created before. This is important because local
|
|
584 // variable clearing due to --enable-var-scope happens after numeric
|
|
585 // expressions are linked to the numeric variables they use.
|
|
586 EXPECT_TRUE(errorToBool((*ExpressionAST)->eval().takeError()));
|
|
587 P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);
|
|
588 ExpressionAST = P.parseNumericSubstitutionBlock(
|
|
589 LocalNumVar1Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
|
|
590 /*LineNumber=*/2, &Cxt, SM);
|
|
591 ASSERT_TRUE(bool(ExpressionAST));
|
|
592 ExpressionVal = (*ExpressionAST)->eval();
|
|
593 EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
|
|
594 ExpressionAST = P.parseNumericSubstitutionBlock(
|
|
595 LocalNumVar2Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
|
|
596 /*LineNumber=*/2, &Cxt, SM);
|
|
597 ASSERT_TRUE(bool(ExpressionAST));
|
|
598 ExpressionVal = (*ExpressionAST)->eval();
|
|
599 EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
|
|
600 EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
|
|
601 EXPECT_TRUE(errorToBool(EmptyVar.takeError()));
|
|
602 // Clear again because parseNumericSubstitutionBlock would have created a
|
|
603 // dummy variable and stored it in GlobalNumericVariableTable.
|
|
604 Cxt.clearLocalVars();
|
|
605
|
|
606 // Redefine global variables and check variables are defined again.
|
|
607 GlobalDefines.emplace_back(std::string("$GlobalVar=BAR"));
|
|
608 GlobalDefines.emplace_back(std::string("#$GlobalNumVar=36"));
|
|
609 ASSERT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
|
610 StringRef GlobalVarStr = "$GlobalVar";
|
|
611 StringRef GlobalNumVarRef = bufferize(SM, "$GlobalNumVar");
|
|
612 Expected<StringRef> GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
|
|
613 ASSERT_TRUE(bool(GlobalVar));
|
|
614 EXPECT_EQ(*GlobalVar, "BAR");
|
|
615 P = FileCheckPattern(Check::CheckPlain, &Cxt, 3);
|
|
616 ExpressionAST = P.parseNumericSubstitutionBlock(
|
|
617 GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
|
|
618 /*LineNumber=*/3, &Cxt, SM);
|
|
619 ASSERT_TRUE(bool(ExpressionAST));
|
|
620 ExpressionVal = (*ExpressionAST)->eval();
|
|
621 ASSERT_TRUE(bool(ExpressionVal));
|
|
622 EXPECT_EQ(*ExpressionVal, 36U);
|
|
623
|
|
624 // Clear local variables and check global variables remain defined.
|
|
625 Cxt.clearLocalVars();
|
|
626 EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError()));
|
|
627 P = FileCheckPattern(Check::CheckPlain, &Cxt, 4);
|
|
628 ExpressionAST = P.parseNumericSubstitutionBlock(
|
|
629 GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
|
|
630 /*LineNumber=*/4, &Cxt, SM);
|
|
631 ASSERT_TRUE(bool(ExpressionAST));
|
|
632 ExpressionVal = (*ExpressionAST)->eval();
|
|
633 ASSERT_TRUE(bool(ExpressionVal));
|
|
634 EXPECT_EQ(*ExpressionVal, 36U);
|
|
635 }
|
|
636 } // namespace
|