123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603 |
- //===- llvm/unittest/Support/FileCheckTest.cpp - FileCheck tests --===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/Support/FileCheck.h"
- #include "gtest/gtest.h"
- #include <unordered_set>
- using namespace llvm;
- namespace {
- class FileCheckTest : public ::testing::Test {};
- TEST_F(FileCheckTest, Literal) {
- // Eval returns the literal's value.
- FileCheckExpressionLiteral Ten(10);
- Expected<uint64_t> Value = Ten.eval();
- ASSERT_TRUE(bool(Value));
- EXPECT_EQ(10U, *Value);
- // Max value can be correctly represented.
- FileCheckExpressionLiteral Max(std::numeric_limits<uint64_t>::max());
- Value = Max.eval();
- ASSERT_TRUE(bool(Value));
- EXPECT_EQ(std::numeric_limits<uint64_t>::max(), *Value);
- }
- static std::string toString(const std::unordered_set<std::string> &Set) {
- bool First = true;
- std::string Str;
- for (StringRef S : Set) {
- Str += Twine(First ? "{" + S : ", " + S).str();
- First = false;
- }
- Str += '}';
- return Str;
- }
- static void
- expectUndefErrors(std::unordered_set<std::string> ExpectedUndefVarNames,
- Error Err) {
- handleAllErrors(std::move(Err), [&](const FileCheckUndefVarError &E) {
- ExpectedUndefVarNames.erase(E.getVarName());
- });
- EXPECT_TRUE(ExpectedUndefVarNames.empty()) << toString(ExpectedUndefVarNames);
- }
- // Return whether Err contains any FileCheckUndefVarError whose associated name
- // is not ExpectedUndefVarName.
- static void expectUndefError(const Twine &ExpectedUndefVarName, Error Err) {
- expectUndefErrors({ExpectedUndefVarName.str()}, std::move(Err));
- }
- uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
- TEST_F(FileCheckTest, NumericVariable) {
- // Undefined variable: getValue and eval fail, error returned by eval holds
- // the name of the undefined variable.
- FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 1);
- EXPECT_EQ("FOO", FooVar.getName());
- FileCheckNumericVariableUse FooVarUse =
- FileCheckNumericVariableUse("FOO", &FooVar);
- EXPECT_FALSE(FooVar.getValue());
- Expected<uint64_t> EvalResult = FooVarUse.eval();
- ASSERT_FALSE(EvalResult);
- expectUndefError("FOO", EvalResult.takeError());
- FooVar.setValue(42);
- // Defined variable: getValue and eval return value set.
- Optional<uint64_t> Value = FooVar.getValue();
- ASSERT_TRUE(bool(Value));
- EXPECT_EQ(42U, *Value);
- EvalResult = FooVarUse.eval();
- ASSERT_TRUE(bool(EvalResult));
- EXPECT_EQ(42U, *EvalResult);
- // Clearing variable: getValue and eval fail. Error returned by eval holds
- // the name of the cleared variable.
- FooVar.clearValue();
- EXPECT_FALSE(FooVar.getValue());
- EvalResult = FooVarUse.eval();
- ASSERT_FALSE(EvalResult);
- expectUndefError("FOO", EvalResult.takeError());
- }
- TEST_F(FileCheckTest, Binop) {
- FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 1);
- FooVar.setValue(42);
- std::unique_ptr<FileCheckNumericVariableUse> FooVarUse =
- std::make_unique<FileCheckNumericVariableUse>("FOO", &FooVar);
- FileCheckNumericVariable BarVar = FileCheckNumericVariable("BAR", 2);
- BarVar.setValue(18);
- std::unique_ptr<FileCheckNumericVariableUse> BarVarUse =
- std::make_unique<FileCheckNumericVariableUse>("BAR", &BarVar);
- FileCheckASTBinop Binop =
- FileCheckASTBinop(doAdd, std::move(FooVarUse), std::move(BarVarUse));
- // Defined variable: eval returns right value.
- Expected<uint64_t> Value = Binop.eval();
- ASSERT_TRUE(bool(Value));
- EXPECT_EQ(60U, *Value);
- // 1 undefined variable: eval fails, error contains name of undefined
- // variable.
- FooVar.clearValue();
- Value = Binop.eval();
- ASSERT_FALSE(Value);
- expectUndefError("FOO", Value.takeError());
- // 2 undefined variables: eval fails, error contains names of all undefined
- // variables.
- BarVar.clearValue();
- Value = Binop.eval();
- ASSERT_FALSE(Value);
- expectUndefErrors({"FOO", "BAR"}, Value.takeError());
- }
- TEST_F(FileCheckTest, ValidVarNameStart) {
- EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('a'));
- EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('G'));
- EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('_'));
- EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('2'));
- EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('$'));
- EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('@'));
- EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('+'));
- EXPECT_FALSE(FileCheckPattern::isValidVarNameStart('-'));
- EXPECT_FALSE(FileCheckPattern::isValidVarNameStart(':'));
- }
- static StringRef bufferize(SourceMgr &SM, StringRef Str) {
- std::unique_ptr<MemoryBuffer> Buffer =
- MemoryBuffer::getMemBufferCopy(Str, "TestBuffer");
- StringRef StrBufferRef = Buffer->getBuffer();
- SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
- return StrBufferRef;
- }
- TEST_F(FileCheckTest, ParseVar) {
- SourceMgr SM;
- StringRef OrigVarName = bufferize(SM, "GoodVar42");
- StringRef VarName = OrigVarName;
- Expected<FileCheckPattern::VariableProperties> ParsedVarResult =
- FileCheckPattern::parseVariable(VarName, SM);
- ASSERT_TRUE(bool(ParsedVarResult));
- EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
- EXPECT_TRUE(VarName.empty());
- EXPECT_FALSE(ParsedVarResult->IsPseudo);
- VarName = OrigVarName = bufferize(SM, "$GoodGlobalVar");
- ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
- ASSERT_TRUE(bool(ParsedVarResult));
- EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
- EXPECT_TRUE(VarName.empty());
- EXPECT_FALSE(ParsedVarResult->IsPseudo);
- VarName = OrigVarName = bufferize(SM, "@GoodPseudoVar");
- ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
- ASSERT_TRUE(bool(ParsedVarResult));
- EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
- EXPECT_TRUE(VarName.empty());
- EXPECT_TRUE(ParsedVarResult->IsPseudo);
- VarName = bufferize(SM, "42BadVar");
- ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
- EXPECT_TRUE(errorToBool(ParsedVarResult.takeError()));
- VarName = bufferize(SM, "$@");
- ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
- EXPECT_TRUE(errorToBool(ParsedVarResult.takeError()));
- VarName = OrigVarName = bufferize(SM, "B@dVar");
- ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
- ASSERT_TRUE(bool(ParsedVarResult));
- EXPECT_EQ(VarName, OrigVarName.substr(1));
- EXPECT_EQ(ParsedVarResult->Name, "B");
- EXPECT_FALSE(ParsedVarResult->IsPseudo);
- VarName = OrigVarName = bufferize(SM, "B$dVar");
- ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
- ASSERT_TRUE(bool(ParsedVarResult));
- EXPECT_EQ(VarName, OrigVarName.substr(1));
- EXPECT_EQ(ParsedVarResult->Name, "B");
- EXPECT_FALSE(ParsedVarResult->IsPseudo);
- VarName = bufferize(SM, "BadVar+");
- ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
- ASSERT_TRUE(bool(ParsedVarResult));
- EXPECT_EQ(VarName, "+");
- EXPECT_EQ(ParsedVarResult->Name, "BadVar");
- EXPECT_FALSE(ParsedVarResult->IsPseudo);
- VarName = bufferize(SM, "BadVar-");
- ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
- ASSERT_TRUE(bool(ParsedVarResult));
- EXPECT_EQ(VarName, "-");
- EXPECT_EQ(ParsedVarResult->Name, "BadVar");
- EXPECT_FALSE(ParsedVarResult->IsPseudo);
- VarName = bufferize(SM, "BadVar:");
- ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
- ASSERT_TRUE(bool(ParsedVarResult));
- EXPECT_EQ(VarName, ":");
- EXPECT_EQ(ParsedVarResult->Name, "BadVar");
- EXPECT_FALSE(ParsedVarResult->IsPseudo);
- }
- class PatternTester {
- private:
- size_t LineNumber = 1;
- SourceMgr SM;
- FileCheckRequest Req;
- FileCheckPatternContext Context;
- FileCheckPattern P =
- FileCheckPattern(Check::CheckPlain, &Context, LineNumber++);
- public:
- PatternTester() {
- std::vector<std::string> GlobalDefines;
- GlobalDefines.emplace_back(std::string("#FOO=42"));
- GlobalDefines.emplace_back(std::string("BAR=BAZ"));
- // An ASSERT_FALSE would make more sense but cannot be used in a
- // constructor.
- EXPECT_FALSE(
- errorToBool(Context.defineCmdlineVariables(GlobalDefines, SM)));
- Context.createLineVariable();
- // Call parsePattern to have @LINE defined.
- P.parsePattern("N/A", "CHECK", SM, Req);
- // parsePattern does not expect to be called twice for the same line and
- // will set FixedStr and RegExStr incorrectly if it is. Therefore prepare
- // a pattern for a different line.
- initNextPattern();
- }
- void initNextPattern() {
- P = FileCheckPattern(Check::CheckPlain, &Context, LineNumber++);
- }
- bool parseSubstExpect(StringRef Expr) {
- StringRef ExprBufferRef = bufferize(SM, Expr);
- Optional<FileCheckNumericVariable *> DefinedNumericVariable;
- return errorToBool(
- P.parseNumericSubstitutionBlock(ExprBufferRef, DefinedNumericVariable,
- false, LineNumber - 1, &Context, SM)
- .takeError());
- }
- bool parsePatternExpect(StringRef Pattern) {
- StringRef PatBufferRef = bufferize(SM, Pattern);
- return P.parsePattern(PatBufferRef, "CHECK", SM, Req);
- }
- bool matchExpect(StringRef Buffer) {
- StringRef BufferRef = bufferize(SM, Buffer);
- size_t MatchLen;
- return errorToBool(P.match(BufferRef, MatchLen, SM).takeError());
- }
- };
- TEST_F(FileCheckTest, ParseExpr) {
- PatternTester Tester;
- // Variable definition.
- // Definition of invalid variable.
- EXPECT_TRUE(Tester.parseSubstExpect("10VAR:"));
- EXPECT_TRUE(Tester.parseSubstExpect("@FOO:"));
- EXPECT_TRUE(Tester.parseSubstExpect("@LINE:"));
- // Conflict with pattern variable.
- EXPECT_TRUE(Tester.parseSubstExpect("BAR:"));
- // Garbage after name of variable being defined.
- EXPECT_TRUE(Tester.parseSubstExpect("VAR GARBAGE:"));
- // Acceptable variable definition.
- EXPECT_FALSE(Tester.parseSubstExpect("VAR1:"));
- EXPECT_FALSE(Tester.parseSubstExpect(" VAR2:"));
- EXPECT_FALSE(Tester.parseSubstExpect("VAR3 :"));
- EXPECT_FALSE(Tester.parseSubstExpect("VAR3: "));
- EXPECT_FALSE(Tester.parsePatternExpect("[[#FOOBAR: FOO+1]]"));
- // Numeric expression.
- // Unacceptable variable.
- EXPECT_TRUE(Tester.parseSubstExpect("10VAR"));
- EXPECT_TRUE(Tester.parseSubstExpect("@FOO"));
- // Only valid variable.
- EXPECT_FALSE(Tester.parseSubstExpect("@LINE"));
- EXPECT_FALSE(Tester.parseSubstExpect("FOO"));
- EXPECT_FALSE(Tester.parseSubstExpect("UNDEF"));
- // Valid empty expression.
- EXPECT_FALSE(Tester.parseSubstExpect(""));
- // Invalid use of variable defined on the same line from expression. Note
- // that the same pattern object is used for the parsePatternExpect and
- // parseSubstExpect since no initNextPattern is called, thus appearing as
- // being on the same line from the pattern's point of view.
- ASSERT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:FOO+1]]"));
- EXPECT_TRUE(Tester.parseSubstExpect("LINE1VAR"));
- // Invalid use of variable defined on same line from input. As above, the
- // absence of a call to initNextPattern makes it appear to be on the same
- // line from the pattern's point of view.
- ASSERT_FALSE(Tester.parsePatternExpect("[[#LINE2VAR:]]"));
- EXPECT_TRUE(Tester.parseSubstExpect("LINE2VAR"));
- // Unsupported operator.
- EXPECT_TRUE(Tester.parseSubstExpect("@LINE/2"));
- // Missing offset operand.
- EXPECT_TRUE(Tester.parseSubstExpect("@LINE+"));
- // Valid expression.
- EXPECT_FALSE(Tester.parseSubstExpect("@LINE+5"));
- EXPECT_FALSE(Tester.parseSubstExpect("FOO+4"));
- Tester.initNextPattern();
- EXPECT_FALSE(Tester.parseSubstExpect("FOOBAR"));
- EXPECT_FALSE(Tester.parseSubstExpect("LINE1VAR"));
- EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+FOO]]"));
- EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+3-FOO]]"));
- }
- TEST_F(FileCheckTest, ParsePattern) {
- PatternTester Tester;
- // Space in pattern variable expression.
- EXPECT_TRUE(Tester.parsePatternExpect("[[ BAR]]"));
- // Invalid variable name.
- EXPECT_TRUE(Tester.parsePatternExpect("[[42INVALID]]"));
- // Invalid pattern variable definition.
- EXPECT_TRUE(Tester.parsePatternExpect("[[@PAT:]]"));
- EXPECT_TRUE(Tester.parsePatternExpect("[[PAT+2:]]"));
- // Collision with numeric variable.
- EXPECT_TRUE(Tester.parsePatternExpect("[[FOO:]]"));
- // Valid use of pattern variable.
- EXPECT_FALSE(Tester.parsePatternExpect("[[BAR]]"));
- // Valid pattern variable definition.
- EXPECT_FALSE(Tester.parsePatternExpect("[[PAT:[0-9]+]]"));
- // Invalid numeric expressions.
- EXPECT_TRUE(Tester.parsePatternExpect("[[#42INVALID]]"));
- EXPECT_TRUE(Tester.parsePatternExpect("[[#@FOO]]"));
- EXPECT_TRUE(Tester.parsePatternExpect("[[#@LINE/2]]"));
- // Valid numeric expressions and numeric variable definition.
- EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO]]"));
- EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE+2]]"));
- EXPECT_FALSE(Tester.parsePatternExpect("[[#NUMVAR:]]"));
- }
- TEST_F(FileCheckTest, Match) {
- PatternTester Tester;
- // Check matching an empty expression only matches a number.
- Tester.parsePatternExpect("[[#]]");
- EXPECT_TRUE(Tester.matchExpect("FAIL"));
- EXPECT_FALSE(Tester.matchExpect("18"));
- // Check matching a definition only matches a number.
- Tester.initNextPattern();
- Tester.parsePatternExpect("[[#NUMVAR:]]");
- EXPECT_TRUE(Tester.matchExpect("FAIL"));
- EXPECT_TRUE(Tester.matchExpect(""));
- EXPECT_FALSE(Tester.matchExpect("18"));
- // Check matching the variable defined matches the correct number only
- Tester.initNextPattern();
- Tester.parsePatternExpect("[[#NUMVAR]] [[#NUMVAR+2]]");
- EXPECT_TRUE(Tester.matchExpect("19 21"));
- EXPECT_TRUE(Tester.matchExpect("18 21"));
- EXPECT_FALSE(Tester.matchExpect("18 20"));
- // Check matching a numeric expression using @LINE after match failure uses
- // the correct value for @LINE.
- Tester.initNextPattern();
- EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
- // Ok, @LINE is 5 now.
- EXPECT_FALSE(Tester.matchExpect("5"));
- Tester.initNextPattern();
- // @LINE is now 6, match with substitution failure.
- EXPECT_FALSE(Tester.parsePatternExpect("[[#UNKNOWN]]"));
- EXPECT_TRUE(Tester.matchExpect("FOO"));
- Tester.initNextPattern();
- // Check that @LINE is 7 as expected.
- EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
- EXPECT_FALSE(Tester.matchExpect("7"));
- }
- TEST_F(FileCheckTest, Substitution) {
- SourceMgr SM;
- FileCheckPatternContext Context;
- std::vector<std::string> GlobalDefines;
- GlobalDefines.emplace_back(std::string("FOO=BAR"));
- EXPECT_FALSE(errorToBool(Context.defineCmdlineVariables(GlobalDefines, SM)));
- // Substitution of an undefined string variable fails and error holds that
- // variable's name.
- FileCheckStringSubstitution StringSubstitution =
- FileCheckStringSubstitution(&Context, "VAR404", 42);
- Expected<std::string> SubstValue = StringSubstitution.getResult();
- ASSERT_FALSE(bool(SubstValue));
- expectUndefError("VAR404", SubstValue.takeError());
- // Substitutions of defined pseudo and non-pseudo numeric variables return
- // the right value.
- FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 1);
- FileCheckNumericVariable NVar = FileCheckNumericVariable("N", 1);
- LineVar.setValue(42);
- NVar.setValue(10);
- auto LineVarUse =
- std::make_unique<FileCheckNumericVariableUse>("@LINE", &LineVar);
- auto NVarUse = std::make_unique<FileCheckNumericVariableUse>("N", &NVar);
- FileCheckNumericSubstitution SubstitutionLine = FileCheckNumericSubstitution(
- &Context, "@LINE", std::move(LineVarUse), 12);
- FileCheckNumericSubstitution SubstitutionN =
- FileCheckNumericSubstitution(&Context, "N", std::move(NVarUse), 30);
- SubstValue = SubstitutionLine.getResult();
- ASSERT_TRUE(bool(SubstValue));
- EXPECT_EQ("42", *SubstValue);
- SubstValue = SubstitutionN.getResult();
- ASSERT_TRUE(bool(SubstValue));
- EXPECT_EQ("10", *SubstValue);
- // Substitution of an undefined numeric variable fails, error holds name of
- // undefined variable.
- LineVar.clearValue();
- SubstValue = SubstitutionLine.getResult();
- ASSERT_FALSE(bool(SubstValue));
- expectUndefError("@LINE", SubstValue.takeError());
- NVar.clearValue();
- SubstValue = SubstitutionN.getResult();
- ASSERT_FALSE(bool(SubstValue));
- expectUndefError("N", SubstValue.takeError());
- // Substitution of a defined string variable returns the right value.
- FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context, 1);
- StringSubstitution = FileCheckStringSubstitution(&Context, "FOO", 42);
- SubstValue = StringSubstitution.getResult();
- ASSERT_TRUE(bool(SubstValue));
- EXPECT_EQ("BAR", *SubstValue);
- }
- TEST_F(FileCheckTest, FileCheckContext) {
- FileCheckPatternContext Cxt = FileCheckPatternContext();
- std::vector<std::string> GlobalDefines;
- SourceMgr SM;
- // Missing equal sign.
- GlobalDefines.emplace_back(std::string("LocalVar"));
- EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
- GlobalDefines.clear();
- GlobalDefines.emplace_back(std::string("#LocalNumVar"));
- EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
- // Empty variable name.
- GlobalDefines.clear();
- GlobalDefines.emplace_back(std::string("=18"));
- EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
- GlobalDefines.clear();
- GlobalDefines.emplace_back(std::string("#=18"));
- EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
- // Invalid variable name.
- GlobalDefines.clear();
- GlobalDefines.emplace_back(std::string("18LocalVar=18"));
- EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
- GlobalDefines.clear();
- GlobalDefines.emplace_back(std::string("#18LocalNumVar=18"));
- EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
- // Name conflict between pattern and numeric variable.
- GlobalDefines.clear();
- GlobalDefines.emplace_back(std::string("LocalVar=18"));
- GlobalDefines.emplace_back(std::string("#LocalVar=36"));
- EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
- Cxt = FileCheckPatternContext();
- GlobalDefines.clear();
- GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
- GlobalDefines.emplace_back(std::string("LocalNumVar=36"));
- EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
- Cxt = FileCheckPatternContext();
- // Invalid numeric value for numeric variable.
- GlobalDefines.clear();
- GlobalDefines.emplace_back(std::string("#LocalNumVar=x"));
- EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
- // Define local variables from command-line.
- GlobalDefines.clear();
- // Clear local variables to remove dummy numeric variable x that
- // parseNumericSubstitutionBlock would have created and stored in
- // GlobalNumericVariableTable.
- Cxt.clearLocalVars();
- GlobalDefines.emplace_back(std::string("LocalVar=FOO"));
- GlobalDefines.emplace_back(std::string("EmptyVar="));
- GlobalDefines.emplace_back(std::string("#LocalNumVar1=18"));
- GlobalDefines.emplace_back(std::string("#LocalNumVar2=LocalNumVar1+2"));
- ASSERT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
- // Check defined variables are present and undefined is absent.
- StringRef LocalVarStr = "LocalVar";
- StringRef LocalNumVar1Ref = bufferize(SM, "LocalNumVar1");
- StringRef LocalNumVar2Ref = bufferize(SM, "LocalNumVar2");
- StringRef EmptyVarStr = "EmptyVar";
- StringRef UnknownVarStr = "UnknownVar";
- Expected<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
- FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1);
- Optional<FileCheckNumericVariable *> DefinedNumericVariable;
- Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionAST =
- P.parseNumericSubstitutionBlock(LocalNumVar1Ref, DefinedNumericVariable,
- /*IsLegacyLineExpr=*/false,
- /*LineNumber=*/1, &Cxt, SM);
- ASSERT_TRUE(bool(LocalVar));
- EXPECT_EQ(*LocalVar, "FOO");
- Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
- Expected<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
- ASSERT_TRUE(bool(ExpressionAST));
- Expected<uint64_t> ExpressionVal = (*ExpressionAST)->eval();
- ASSERT_TRUE(bool(ExpressionVal));
- EXPECT_EQ(*ExpressionVal, 18U);
- ExpressionAST =
- P.parseNumericSubstitutionBlock(LocalNumVar2Ref, DefinedNumericVariable,
- /*IsLegacyLineExpr=*/false,
- /*LineNumber=*/1, &Cxt, SM);
- ASSERT_TRUE(bool(ExpressionAST));
- ExpressionVal = (*ExpressionAST)->eval();
- ASSERT_TRUE(bool(ExpressionVal));
- EXPECT_EQ(*ExpressionVal, 20U);
- ASSERT_TRUE(bool(EmptyVar));
- EXPECT_EQ(*EmptyVar, "");
- EXPECT_TRUE(errorToBool(UnknownVar.takeError()));
- // Clear local variables and check they become absent.
- Cxt.clearLocalVars();
- LocalVar = Cxt.getPatternVarValue(LocalVarStr);
- EXPECT_TRUE(errorToBool(LocalVar.takeError()));
- // Check a numeric expression's evaluation fails if called after clearing of
- // local variables, if it was created before. This is important because local
- // variable clearing due to --enable-var-scope happens after numeric
- // expressions are linked to the numeric variables they use.
- EXPECT_TRUE(errorToBool((*ExpressionAST)->eval().takeError()));
- P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);
- ExpressionAST = P.parseNumericSubstitutionBlock(
- LocalNumVar1Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
- /*LineNumber=*/2, &Cxt, SM);
- ASSERT_TRUE(bool(ExpressionAST));
- ExpressionVal = (*ExpressionAST)->eval();
- EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
- ExpressionAST = P.parseNumericSubstitutionBlock(
- LocalNumVar2Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
- /*LineNumber=*/2, &Cxt, SM);
- ASSERT_TRUE(bool(ExpressionAST));
- ExpressionVal = (*ExpressionAST)->eval();
- EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
- EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
- EXPECT_TRUE(errorToBool(EmptyVar.takeError()));
- // Clear again because parseNumericSubstitutionBlock would have created a
- // dummy variable and stored it in GlobalNumericVariableTable.
- Cxt.clearLocalVars();
- // Redefine global variables and check variables are defined again.
- GlobalDefines.emplace_back(std::string("$GlobalVar=BAR"));
- GlobalDefines.emplace_back(std::string("#$GlobalNumVar=36"));
- ASSERT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
- StringRef GlobalVarStr = "$GlobalVar";
- StringRef GlobalNumVarRef = bufferize(SM, "$GlobalNumVar");
- Expected<StringRef> GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
- ASSERT_TRUE(bool(GlobalVar));
- EXPECT_EQ(*GlobalVar, "BAR");
- P = FileCheckPattern(Check::CheckPlain, &Cxt, 3);
- ExpressionAST = P.parseNumericSubstitutionBlock(
- GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
- /*LineNumber=*/3, &Cxt, SM);
- ASSERT_TRUE(bool(ExpressionAST));
- ExpressionVal = (*ExpressionAST)->eval();
- ASSERT_TRUE(bool(ExpressionVal));
- EXPECT_EQ(*ExpressionVal, 36U);
- // Clear local variables and check global variables remain defined.
- Cxt.clearLocalVars();
- EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError()));
- P = FileCheckPattern(Check::CheckPlain, &Cxt, 4);
- ExpressionAST = P.parseNumericSubstitutionBlock(
- GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
- /*LineNumber=*/4, &Cxt, SM);
- ASSERT_TRUE(bool(ExpressionAST));
- ExpressionVal = (*ExpressionAST)->eval();
- ASSERT_TRUE(bool(ExpressionVal));
- EXPECT_EQ(*ExpressionVal, 36U);
- }
- } // namespace
|