blob: 848ab15116bde43c6b10ed330c87f550a1e25755 [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"
11
12using namespace llvm;
13namespace {
14
15class FileCheckTest : public ::testing::Test {};
16
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000017TEST_F(FileCheckTest, NumericVariable) {
Thomas Preud'homme2bf04f22019-07-10 12:49:28 +000018 // Undefined variable: getValue fails, setValue does not trigger assert.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +000019 FileCheckNumericVariable FooVar = FileCheckNumericVariable(1, "FOO");
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000020 EXPECT_EQ("FOO", FooVar.getName());
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000021 llvm::Optional<uint64_t> Value = FooVar.getValue();
Thomas Preud'homme71d3f222019-06-06 13:21:06 +000022 EXPECT_FALSE(Value);
Thomas Preud'homme2bf04f22019-07-10 12:49:28 +000023 FooVar.clearValue();
24 FooVar.setValue(42);
Thomas Preud'homme71d3f222019-06-06 13:21:06 +000025
Thomas Preud'homme2bf04f22019-07-10 12:49:28 +000026 // Defined variable: getValue returns value set.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000027 Value = FooVar.getValue();
28 EXPECT_TRUE(Value);
29 EXPECT_EQ(42U, *Value);
30
Thomas Preud'homme2bf04f22019-07-10 12:49:28 +000031 // Clearing variable: getValue fails.
32 FooVar.clearValue();
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000033 Value = FooVar.getValue();
34 EXPECT_FALSE(Value);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000035}
36
37uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
38
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000039static void expectUndefError(const Twine &ExpectedStr, Error Err) {
40 handleAllErrors(std::move(Err), [&](const FileCheckUndefVarError &E) {
41 EXPECT_EQ(ExpectedStr.str(), E.getVarName());
42 });
43}
44
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +000045TEST_F(FileCheckTest, Expression) {
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000046 FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +000047 FileCheckExpression Expression = FileCheckExpression(doAdd, &FooVar, 18);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000048
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000049 // Defined variable: eval returns right value.
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +000050 Expected<uint64_t> Value = Expression.eval();
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000051 EXPECT_TRUE(static_cast<bool>(Value));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000052 EXPECT_EQ(60U, *Value);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000053
54 // Undefined variable: eval fails, undefined variable returned. We call
55 // getUndefVarName first to check that it can be called without calling
56 // eval() first.
57 FooVar.clearValue();
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +000058 Error EvalError = Expression.eval().takeError();
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000059 EXPECT_TRUE(errorToBool(std::move(EvalError)));
60 expectUndefError("FOO", std::move(EvalError));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000061}
62
Thomas Preud'homme5a330472019-04-29 13:32:36 +000063TEST_F(FileCheckTest, ValidVarNameStart) {
64 EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('a'));
65 EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('G'));
66 EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('_'));
67 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('2'));
68 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('$'));
69 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('@'));
70 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('+'));
71 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('-'));
72 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart(':'));
73}
Thomas Preud'hommee038fa72019-04-15 10:10:11 +000074
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000075static StringRef bufferize(SourceMgr &SM, StringRef Str) {
76 std::unique_ptr<MemoryBuffer> Buffer =
77 MemoryBuffer::getMemBufferCopy(Str, "TestBuffer");
78 StringRef StrBufferRef = Buffer->getBuffer();
79 SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
80 return StrBufferRef;
81}
82
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000083TEST_F(FileCheckTest, ParseVar) {
84 SourceMgr SM;
85 StringRef OrigVarName = bufferize(SM, "GoodVar42");
86 StringRef VarName = OrigVarName;
87 bool IsPseudo = true;
88 Expected<StringRef> ParsedName =
89 FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
90 EXPECT_TRUE(static_cast<bool>(ParsedName));
91 EXPECT_EQ(*ParsedName, OrigVarName);
92 EXPECT_TRUE(VarName.empty());
93 EXPECT_FALSE(IsPseudo);
94
95 VarName = OrigVarName = bufferize(SM, "$GoodGlobalVar");
96 IsPseudo = true;
97 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
98 EXPECT_TRUE(static_cast<bool>(ParsedName));
99 EXPECT_EQ(*ParsedName, OrigVarName);
100 EXPECT_TRUE(VarName.empty());
101 EXPECT_FALSE(IsPseudo);
102
103 VarName = OrigVarName = bufferize(SM, "@GoodPseudoVar");
104 IsPseudo = true;
105 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
106 EXPECT_TRUE(static_cast<bool>(ParsedName));
107 EXPECT_EQ(*ParsedName, OrigVarName);
108 EXPECT_TRUE(VarName.empty());
109 EXPECT_TRUE(IsPseudo);
110
111 VarName = bufferize(SM, "42BadVar");
112 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
113 EXPECT_TRUE(errorToBool(ParsedName.takeError()));
114
115 VarName = bufferize(SM, "$@");
116 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
117 EXPECT_TRUE(errorToBool(ParsedName.takeError()));
118
119 VarName = OrigVarName = bufferize(SM, "B@dVar");
120 IsPseudo = true;
121 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
122 EXPECT_TRUE(static_cast<bool>(ParsedName));
123 EXPECT_EQ(VarName, OrigVarName.substr(1));
124 EXPECT_EQ(*ParsedName, "B");
125 EXPECT_FALSE(IsPseudo);
126
127 VarName = OrigVarName = bufferize(SM, "B$dVar");
128 IsPseudo = true;
129 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
130 EXPECT_TRUE(static_cast<bool>(ParsedName));
131 EXPECT_EQ(VarName, OrigVarName.substr(1));
132 EXPECT_EQ(*ParsedName, "B");
133 EXPECT_FALSE(IsPseudo);
134
135 VarName = bufferize(SM, "BadVar+");
136 IsPseudo = true;
137 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
138 EXPECT_TRUE(static_cast<bool>(ParsedName));
139 EXPECT_EQ(VarName, "+");
140 EXPECT_EQ(*ParsedName, "BadVar");
141 EXPECT_FALSE(IsPseudo);
142
143 VarName = bufferize(SM, "BadVar-");
144 IsPseudo = true;
145 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
146 EXPECT_TRUE(static_cast<bool>(ParsedName));
147 EXPECT_EQ(VarName, "-");
148 EXPECT_EQ(*ParsedName, "BadVar");
149 EXPECT_FALSE(IsPseudo);
150
151 VarName = bufferize(SM, "BadVar:");
152 IsPseudo = true;
153 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
154 EXPECT_TRUE(static_cast<bool>(ParsedName));
155 EXPECT_EQ(VarName, ":");
156 EXPECT_EQ(*ParsedName, "BadVar");
157 EXPECT_FALSE(IsPseudo);
158}
159
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000160class PatternTester {
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000161private:
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000162 size_t LineNumber = 1;
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000163 SourceMgr SM;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000164 FileCheckRequest Req;
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000165 FileCheckPatternContext Context;
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000166 FileCheckPattern P =
167 FileCheckPattern(Check::CheckPlain, &Context, LineNumber++);
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000168
169public:
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000170 PatternTester() {
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000171 std::vector<std::string> GlobalDefines;
172 GlobalDefines.emplace_back(std::string("#FOO=42"));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000173 GlobalDefines.emplace_back(std::string("BAR=BAZ"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000174 EXPECT_FALSE(
175 errorToBool(Context.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme56f63082019-07-05 16:25:46 +0000176 Context.createLineVariable();
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000177 // Call parsePattern to have @LINE defined.
178 P.parsePattern("N/A", "CHECK", SM, Req);
179 // parsePattern does not expect to be called twice for the same line and
180 // will set FixedStr and RegExStr incorrectly if it is. Therefore prepare
181 // a pattern for a different line.
182 initNextPattern();
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000183 }
184
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000185 void initNextPattern() {
186 P = FileCheckPattern(Check::CheckPlain, &Context, LineNumber++);
187 }
188
189 bool parseNumVarDefExpect(StringRef Expr) {
190 StringRef ExprBufferRef = bufferize(SM, Expr);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000191 return errorToBool(FileCheckPattern::parseNumericVariableDefinition(
Thomas Preud'homme56f63082019-07-05 16:25:46 +0000192 ExprBufferRef, &Context, LineNumber, SM)
193 .takeError());
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000194 }
195
196 bool parseSubstExpect(StringRef Expr) {
197 StringRef ExprBufferRef = bufferize(SM, Expr);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000198 Optional<FileCheckNumericVariable *> DefinedNumericVariable;
199 return errorToBool(P.parseNumericSubstitutionBlock(
200 ExprBufferRef, DefinedNumericVariable, SM)
201 .takeError());
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000202 }
203
204 bool parsePatternExpect(StringRef Pattern) {
205 StringRef PatBufferRef = bufferize(SM, Pattern);
206 return P.parsePattern(PatBufferRef, "CHECK", SM, Req);
207 }
208
209 bool matchExpect(StringRef Buffer) {
210 StringRef BufferRef = bufferize(SM, Buffer);
211 size_t MatchLen;
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000212 return errorToBool(P.match(BufferRef, MatchLen, SM).takeError());
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000213 }
214};
215
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000216TEST_F(FileCheckTest, ParseNumericVariableDefinition) {
217 PatternTester Tester;
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000218
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000219 // Invalid definition of pseudo.
220 EXPECT_TRUE(Tester.parseNumVarDefExpect("@LINE"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000221
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000222 // Conflict with pattern variable.
223 EXPECT_TRUE(Tester.parseNumVarDefExpect("BAR"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000224
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000225 // Defined variable.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000226 EXPECT_FALSE(Tester.parseNumVarDefExpect("FOO"));
227}
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000228
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000229TEST_F(FileCheckTest, ParseExpr) {
230 PatternTester Tester;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000231
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000232 // Variable definition.
233
234 // Definition of invalid variable.
235 EXPECT_TRUE(Tester.parseSubstExpect("10VAR:"));
236 EXPECT_TRUE(Tester.parseSubstExpect("@FOO:"));
237 EXPECT_TRUE(Tester.parseSubstExpect("@LINE:"));
238
239 // Garbage after name of variable being defined.
240 EXPECT_TRUE(Tester.parseSubstExpect("VAR GARBAGE:"));
241
242 // Variable defined to numeric expression.
243 EXPECT_TRUE(Tester.parseSubstExpect("VAR1: FOO"));
244
245 // Acceptable variable definition.
246 EXPECT_FALSE(Tester.parseSubstExpect("VAR1:"));
247 EXPECT_FALSE(Tester.parseSubstExpect(" VAR2:"));
248 EXPECT_FALSE(Tester.parseSubstExpect("VAR3 :"));
249 EXPECT_FALSE(Tester.parseSubstExpect("VAR3: "));
250
251 // Numeric expression.
252
253 // Unacceptable variable.
254 EXPECT_TRUE(Tester.parseSubstExpect("10VAR"));
255 EXPECT_TRUE(Tester.parseSubstExpect("@FOO"));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000256
257 // Only valid variable.
258 EXPECT_FALSE(Tester.parseSubstExpect("@LINE"));
259 EXPECT_FALSE(Tester.parseSubstExpect("FOO"));
Thomas Preud'hommefe7ac172019-07-05 16:25:33 +0000260 EXPECT_FALSE(Tester.parseSubstExpect("UNDEF"));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000261
262 // Use variable defined on same line.
263 EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:]]"));
264 EXPECT_TRUE(Tester.parseSubstExpect("LINE1VAR"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000265
266 // Unsupported operator.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000267 EXPECT_TRUE(Tester.parseSubstExpect("@LINE/2"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000268
269 // Missing offset operand.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000270 EXPECT_TRUE(Tester.parseSubstExpect("@LINE+"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000271
272 // Cannot parse offset operand.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000273 EXPECT_TRUE(Tester.parseSubstExpect("@LINE+x"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000274
275 // Unexpected string at end of numeric expression.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000276 EXPECT_TRUE(Tester.parseSubstExpect("@LINE+5x"));
277
278 // Valid expression.
279 EXPECT_FALSE(Tester.parseSubstExpect("@LINE+5"));
280 EXPECT_FALSE(Tester.parseSubstExpect("FOO+4"));
281}
282
283TEST_F(FileCheckTest, ParsePattern) {
284 PatternTester Tester;
285
286 // Space in pattern variable expression.
287 EXPECT_TRUE(Tester.parsePatternExpect("[[ BAR]]"));
288
289 // Invalid variable name.
290 EXPECT_TRUE(Tester.parsePatternExpect("[[42INVALID]]"));
291
292 // Invalid pattern variable definition.
293 EXPECT_TRUE(Tester.parsePatternExpect("[[@PAT:]]"));
294 EXPECT_TRUE(Tester.parsePatternExpect("[[PAT+2:]]"));
295
296 // Collision with numeric variable.
297 EXPECT_TRUE(Tester.parsePatternExpect("[[FOO:]]"));
298
299 // Valid use of pattern variable.
300 EXPECT_FALSE(Tester.parsePatternExpect("[[BAR]]"));
301
302 // Valid pattern variable definition.
303 EXPECT_FALSE(Tester.parsePatternExpect("[[PAT:[0-9]+]]"));
304
305 // Invalid numeric expressions.
306 EXPECT_TRUE(Tester.parsePatternExpect("[[#42INVALID]]"));
307 EXPECT_TRUE(Tester.parsePatternExpect("[[#@FOO]]"));
308 EXPECT_TRUE(Tester.parsePatternExpect("[[#@LINE/2]]"));
309 EXPECT_TRUE(Tester.parsePatternExpect("[[#2+@LINE]]"));
310 EXPECT_TRUE(Tester.parsePatternExpect("[[#YUP:@LINE]]"));
311
312 // Valid numeric expressions and numeric variable definition.
313 EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO]]"));
314 EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE+2]]"));
315 EXPECT_FALSE(Tester.parsePatternExpect("[[#NUMVAR:]]"));
316}
317
318TEST_F(FileCheckTest, Match) {
319 PatternTester Tester;
320
321 // Check matching a definition only matches a number.
322 Tester.parsePatternExpect("[[#NUMVAR:]]");
323 EXPECT_TRUE(Tester.matchExpect("FAIL"));
324 EXPECT_FALSE(Tester.matchExpect("18"));
325
326 // Check matching the variable defined matches the correct number only
327 Tester.initNextPattern();
328 Tester.parsePatternExpect("[[#NUMVAR]] [[#NUMVAR+2]]");
329 EXPECT_TRUE(Tester.matchExpect("19 21"));
330 EXPECT_TRUE(Tester.matchExpect("18 21"));
331 EXPECT_FALSE(Tester.matchExpect("18 20"));
Thomas Preud'hommef6ea43b2019-07-10 12:49:17 +0000332
333 // Check matching a numeric expression using @LINE after match failure uses
334 // the correct value for @LINE.
335 Tester.initNextPattern();
336 EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
337 // Ok, @LINE is 4 now.
338 EXPECT_FALSE(Tester.matchExpect("4"));
339 Tester.initNextPattern();
340 // @LINE is now 5, match with substitution failure.
341 EXPECT_FALSE(Tester.parsePatternExpect("[[#UNKNOWN]]"));
342 EXPECT_TRUE(Tester.matchExpect("FOO"));
343 Tester.initNextPattern();
344 // Check that @LINE is 6 as expected.
345 EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
346 EXPECT_FALSE(Tester.matchExpect("6"));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000347}
348
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000349TEST_F(FileCheckTest, Substitution) {
350 SourceMgr SM;
351 FileCheckPatternContext Context;
352 std::vector<std::string> GlobalDefines;
353 GlobalDefines.emplace_back(std::string("FOO=BAR"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000354 EXPECT_FALSE(errorToBool(Context.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000355
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000356 // Substitution of an undefined string variable fails and error holds that
357 // variable's name.
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000358 FileCheckStringSubstitution StringSubstitution =
359 FileCheckStringSubstitution(&Context, "VAR404", 42);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000360 Expected<std::string> SubstValue = StringSubstitution.getResult();
361 EXPECT_FALSE(static_cast<bool>(SubstValue));
362 expectUndefError("VAR404", SubstValue.takeError());
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000363
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000364 // Substitutions of defined pseudo and non-pseudo numeric variables return
365 // the right value.
366 FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000367 FileCheckNumericVariable NVar = FileCheckNumericVariable("N", 10);
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000368 FileCheckExpression LineExpression = FileCheckExpression(doAdd, &LineVar, 0);
369 FileCheckExpression NExpression = FileCheckExpression(doAdd, &NVar, 3);
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000370 FileCheckNumericSubstitution SubstitutionLine =
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000371 FileCheckNumericSubstitution(&Context, "@LINE", &LineExpression, 12);
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000372 FileCheckNumericSubstitution SubstitutionN =
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000373 FileCheckNumericSubstitution(&Context, "N", &NExpression, 30);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000374 Expected<std::string> Value = SubstitutionLine.getResult();
375 EXPECT_TRUE(static_cast<bool>(Value));
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000376 EXPECT_EQ("42", *Value);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000377 Value = SubstitutionN.getResult();
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000378 EXPECT_TRUE(static_cast<bool>(Value));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000379 EXPECT_EQ("13", *Value);
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000380
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000381 // Substitution of an undefined numeric variable fails.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000382 LineVar.clearValue();
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000383 SubstValue = SubstitutionLine.getResult().takeError();
384 EXPECT_FALSE(static_cast<bool>(SubstValue));
385 expectUndefError("@LINE", SubstValue.takeError());
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000386 NVar.clearValue();
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000387 SubstValue = SubstitutionN.getResult().takeError();
388 EXPECT_FALSE(static_cast<bool>(SubstValue));
389 expectUndefError("N", SubstValue.takeError());
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000390
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000391 // Substitution of a defined string variable returns the right value.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000392 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context, 1);
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000393 StringSubstitution = FileCheckStringSubstitution(&Context, "FOO", 42);
394 Value = StringSubstitution.getResult();
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000395 EXPECT_TRUE(static_cast<bool>(Value));
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000396 EXPECT_EQ("BAR", *Value);
397}
398
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000399TEST_F(FileCheckTest, FileCheckContext) {
400 FileCheckPatternContext Cxt = FileCheckPatternContext();
401 std::vector<std::string> GlobalDefines;
402 SourceMgr SM;
403
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000404 // Missing equal sign.
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000405 GlobalDefines.emplace_back(std::string("LocalVar"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000406 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000407 GlobalDefines.clear();
408 GlobalDefines.emplace_back(std::string("#LocalNumVar"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000409 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000410
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000411 // Empty variable name.
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000412 GlobalDefines.clear();
413 GlobalDefines.emplace_back(std::string("=18"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000414 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000415 GlobalDefines.clear();
416 GlobalDefines.emplace_back(std::string("#=18"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000417 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000418
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000419 // Invalid variable name.
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000420 GlobalDefines.clear();
421 GlobalDefines.emplace_back(std::string("18LocalVar=18"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000422 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000423 GlobalDefines.clear();
424 GlobalDefines.emplace_back(std::string("#18LocalNumVar=18"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000425 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000426
427 // Name conflict between pattern and numeric variable.
428 GlobalDefines.clear();
429 GlobalDefines.emplace_back(std::string("LocalVar=18"));
430 GlobalDefines.emplace_back(std::string("#LocalVar=36"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000431 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000432 Cxt = FileCheckPatternContext();
433 GlobalDefines.clear();
434 GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
435 GlobalDefines.emplace_back(std::string("LocalNumVar=36"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000436 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000437 Cxt = FileCheckPatternContext();
438
439 // Invalid numeric value for numeric variable.
440 GlobalDefines.clear();
441 GlobalDefines.emplace_back(std::string("#LocalNumVar=x"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000442 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000443
444 // Define local variables from command-line.
445 GlobalDefines.clear();
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000446 GlobalDefines.emplace_back(std::string("LocalVar=FOO"));
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000447 GlobalDefines.emplace_back(std::string("EmptyVar="));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000448 GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000449 EXPECT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000450
451 // Check defined variables are present and undefined is absent.
452 StringRef LocalVarStr = "LocalVar";
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000453 StringRef LocalNumVarRef = bufferize(SM, "LocalNumVar");
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000454 StringRef EmptyVarStr = "EmptyVar";
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000455 StringRef UnknownVarStr = "UnknownVar";
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000456 Expected<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000457 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000458 Optional<FileCheckNumericVariable *> DefinedNumericVariable;
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000459 Expected<FileCheckExpression *> Expression = P.parseNumericSubstitutionBlock(
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000460 LocalNumVarRef, DefinedNumericVariable, SM);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000461 Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
462 Expected<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
463 EXPECT_TRUE(static_cast<bool>(LocalVar));
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000464 EXPECT_EQ(*LocalVar, "FOO");
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000465 EXPECT_TRUE(static_cast<bool>(Expression));
466 Expected<uint64_t> ExpressionVal = (*Expression)->eval();
467 EXPECT_TRUE(static_cast<bool>(ExpressionVal));
468 EXPECT_EQ(*ExpressionVal, 18U);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000469 EXPECT_TRUE(static_cast<bool>(EmptyVar));
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000470 EXPECT_EQ(*EmptyVar, "");
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000471 EXPECT_TRUE(errorToBool(UnknownVar.takeError()));
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000472
473 // Clear local variables and check they become absent.
474 Cxt.clearLocalVars();
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000475 LocalVar = Cxt.getPatternVarValue(LocalVarStr);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000476 EXPECT_TRUE(errorToBool(LocalVar.takeError()));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000477 // Check a numeric expression's evaluation fails if called after clearing of
478 // local variables, if it was created before. This is important because local
479 // variable clearing due to --enable-var-scope happens after numeric
480 // expressions are linked to the numeric variables they use.
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000481 EXPECT_TRUE(errorToBool((*Expression)->eval().takeError()));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000482 P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000483 Expression = P.parseNumericSubstitutionBlock(LocalNumVarRef,
484 DefinedNumericVariable, SM);
Thomas Preud'hommefe7ac172019-07-05 16:25:33 +0000485 EXPECT_TRUE(bool(Expression));
486 ExpressionVal = (*Expression)->eval();
487 EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000488 EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000489 EXPECT_TRUE(errorToBool(EmptyVar.takeError()));
Thomas Preud'hommefe7ac172019-07-05 16:25:33 +0000490 // Clear again because parseNumericSubstitutionBlock would have created a
491 // dummy variable and stored it in GlobalNumericVariableTable.
492 Cxt.clearLocalVars();
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000493
494 // Redefine global variables and check variables are defined again.
495 GlobalDefines.emplace_back(std::string("$GlobalVar=BAR"));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000496 GlobalDefines.emplace_back(std::string("#$GlobalNumVar=36"));
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000497 EXPECT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000498 StringRef GlobalVarStr = "$GlobalVar";
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000499 StringRef GlobalNumVarRef = bufferize(SM, "$GlobalNumVar");
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000500 Expected<StringRef> GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
501 EXPECT_TRUE(static_cast<bool>(GlobalVar));
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000502 EXPECT_EQ(*GlobalVar, "BAR");
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000503 P = FileCheckPattern(Check::CheckPlain, &Cxt, 3);
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000504 Expression = P.parseNumericSubstitutionBlock(GlobalNumVarRef,
505 DefinedNumericVariable, SM);
506 EXPECT_TRUE(static_cast<bool>(Expression));
507 ExpressionVal = (*Expression)->eval();
508 EXPECT_TRUE(static_cast<bool>(ExpressionVal));
509 EXPECT_EQ(*ExpressionVal, 36U);
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000510
511 // Clear local variables and check global variables remain defined.
512 Cxt.clearLocalVars();
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000513 EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError()));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000514 P = FileCheckPattern(Check::CheckPlain, &Cxt, 4);
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000515 Expression = P.parseNumericSubstitutionBlock(GlobalNumVarRef,
516 DefinedNumericVariable, SM);
517 EXPECT_TRUE(static_cast<bool>(Expression));
518 ExpressionVal = (*Expression)->eval();
519 EXPECT_TRUE(static_cast<bool>(ExpressionVal));
520 EXPECT_EQ(*ExpressionVal, 36U);
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000521}
522} // namespace