| //===- 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" |
| |
| using namespace llvm; |
| namespace { |
| |
| class FileCheckTest : public ::testing::Test {}; |
| |
| 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(':')); |
| } |
| |
| TEST_F(FileCheckTest, ParseVar) { |
| StringRef VarName = "GoodVar42"; |
| bool IsPseudo = true; |
| unsigned TrailIdx = 0; |
| EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx)); |
| EXPECT_FALSE(IsPseudo); |
| EXPECT_EQ(TrailIdx, VarName.size()); |
| |
| VarName = "$GoodGlobalVar"; |
| IsPseudo = true; |
| TrailIdx = 0; |
| EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx)); |
| EXPECT_FALSE(IsPseudo); |
| EXPECT_EQ(TrailIdx, VarName.size()); |
| |
| VarName = "@GoodPseudoVar"; |
| IsPseudo = true; |
| TrailIdx = 0; |
| EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx)); |
| EXPECT_TRUE(IsPseudo); |
| EXPECT_EQ(TrailIdx, VarName.size()); |
| |
| VarName = "42BadVar"; |
| EXPECT_TRUE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx)); |
| |
| VarName = "$@"; |
| EXPECT_TRUE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx)); |
| |
| VarName = "B@dVar"; |
| IsPseudo = true; |
| TrailIdx = 0; |
| EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx)); |
| EXPECT_FALSE(IsPseudo); |
| EXPECT_EQ(TrailIdx, 1U); |
| |
| VarName = "B$dVar"; |
| IsPseudo = true; |
| TrailIdx = 0; |
| EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx)); |
| EXPECT_FALSE(IsPseudo); |
| EXPECT_EQ(TrailIdx, 1U); |
| |
| VarName = "BadVar+"; |
| IsPseudo = true; |
| TrailIdx = 0; |
| EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx)); |
| EXPECT_FALSE(IsPseudo); |
| EXPECT_EQ(TrailIdx, VarName.size() - 1); |
| |
| VarName = "BadVar-"; |
| IsPseudo = true; |
| TrailIdx = 0; |
| EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx)); |
| EXPECT_FALSE(IsPseudo); |
| EXPECT_EQ(TrailIdx, VarName.size() - 1); |
| |
| VarName = "BadVar:"; |
| IsPseudo = true; |
| TrailIdx = 0; |
| EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx)); |
| EXPECT_FALSE(IsPseudo); |
| EXPECT_EQ(TrailIdx, VarName.size() - 1); |
| } |
| |
| class ExprTester { |
| private: |
| SourceMgr SM; |
| FileCheckPatternContext Context; |
| FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context); |
| |
| public: |
| bool parseExpect(std::string &VarName, std::string &Trailer) { |
| std::string NameTrailer = VarName + Trailer; |
| std::unique_ptr<MemoryBuffer> Buffer = |
| MemoryBuffer::getMemBufferCopy(NameTrailer, "TestBuffer"); |
| StringRef NameTrailerRef = Buffer->getBuffer(); |
| SM.AddNewSourceBuffer(std::move(Buffer), SMLoc()); |
| StringRef VarNameRef = NameTrailerRef.substr(0, VarName.size()); |
| StringRef TrailerRef = NameTrailerRef.substr(VarName.size()); |
| return P.parseNumericExpression(VarNameRef, TrailerRef, SM) == nullptr; |
| } |
| }; |
| |
| TEST_F(FileCheckTest, ParseExpr) { |
| ExprTester Tester; |
| |
| // @LINE with offset. |
| std::string VarName = "@LINE"; |
| std::string Trailer = "+3"; |
| EXPECT_FALSE(Tester.parseExpect(VarName, Trailer)); |
| |
| // @LINE only. |
| Trailer = ""; |
| EXPECT_FALSE(Tester.parseExpect(VarName, Trailer)); |
| |
| // Wrong Pseudovar. |
| VarName = "@FOO"; |
| EXPECT_TRUE(Tester.parseExpect(VarName, Trailer)); |
| |
| // Unsupported operator. |
| VarName = "@LINE"; |
| Trailer = "/2"; |
| EXPECT_TRUE(Tester.parseExpect(VarName, Trailer)); |
| |
| // Missing offset operand. |
| VarName = "@LINE"; |
| Trailer = "+"; |
| EXPECT_TRUE(Tester.parseExpect(VarName, Trailer)); |
| |
| // Cannot parse offset operand. |
| VarName = "@LINE"; |
| Trailer = "+x"; |
| EXPECT_TRUE(Tester.parseExpect(VarName, Trailer)); |
| |
| // Unexpected string at end of numeric expression. |
| VarName = "@LINE"; |
| Trailer = "+5x"; |
| EXPECT_TRUE(Tester.parseExpect(VarName, Trailer)); |
| } |
| |
| TEST_F(FileCheckTest, Substitution) { |
| SourceMgr SM; |
| FileCheckPatternContext Context; |
| std::vector<std::string> GlobalDefines; |
| GlobalDefines.emplace_back(std::string("FOO=BAR")); |
| Context.defineCmdlineVariables(GlobalDefines, SM); |
| |
| FileCheckPatternSubstitution Substitution = |
| FileCheckPatternSubstitution(&Context, "VAR404", 42); |
| EXPECT_FALSE(Substitution.getResult()); |
| |
| FileCheckNumExpr NumExpr = FileCheckNumExpr(42); |
| Substitution = FileCheckPatternSubstitution(&Context, "@LINE", &NumExpr, 12); |
| llvm::Optional<std::string> Value = Substitution.getResult(); |
| EXPECT_TRUE(Value); |
| EXPECT_EQ("42", *Value); |
| |
| FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context); |
| Substitution = FileCheckPatternSubstitution(&Context, "FOO", 42); |
| Value = Substitution.getResult(); |
| EXPECT_TRUE(Value); |
| EXPECT_EQ("BAR", *Value); |
| } |
| |
| TEST_F(FileCheckTest, UndefVars) { |
| SourceMgr SM; |
| FileCheckPatternContext Context; |
| std::vector<std::string> GlobalDefines; |
| GlobalDefines.emplace_back(std::string("FOO=BAR")); |
| Context.defineCmdlineVariables(GlobalDefines, SM); |
| |
| FileCheckPatternSubstitution Substitution = |
| FileCheckPatternSubstitution(&Context, "VAR404", 42); |
| StringRef UndefVar = Substitution.getUndefVarName(); |
| EXPECT_EQ("VAR404", UndefVar); |
| |
| FileCheckNumExpr NumExpr = FileCheckNumExpr(42); |
| Substitution = FileCheckPatternSubstitution(&Context, "@LINE", &NumExpr, 12); |
| UndefVar = Substitution.getUndefVarName(); |
| EXPECT_EQ("", UndefVar); |
| |
| Substitution = FileCheckPatternSubstitution(&Context, "FOO", 42); |
| UndefVar = Substitution.getUndefVarName(); |
| EXPECT_EQ("", UndefVar); |
| } |
| |
| 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(Cxt.defineCmdlineVariables(GlobalDefines, SM)); |
| |
| // Empty variable |
| GlobalDefines.clear(); |
| GlobalDefines.emplace_back(std::string("=18")); |
| EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM)); |
| |
| // Invalid variable |
| GlobalDefines.clear(); |
| GlobalDefines.emplace_back(std::string("18LocalVar=18")); |
| EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM)); |
| |
| // Define local variables from command-line. |
| GlobalDefines.clear(); |
| GlobalDefines.emplace_back(std::string("LocalVar=FOO")); |
| GlobalDefines.emplace_back(std::string("EmptyVar=")); |
| bool GotError = Cxt.defineCmdlineVariables(GlobalDefines, SM); |
| EXPECT_FALSE(GotError); |
| |
| // Check defined variables are present and undefined is absent. |
| StringRef LocalVarStr = "LocalVar"; |
| StringRef EmptyVarStr = "EmptyVar"; |
| StringRef UnknownVarStr = "UnknownVar"; |
| llvm::Optional<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr); |
| llvm::Optional<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr); |
| llvm::Optional<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr); |
| EXPECT_TRUE(LocalVar); |
| EXPECT_EQ(*LocalVar, "FOO"); |
| EXPECT_TRUE(EmptyVar); |
| EXPECT_EQ(*EmptyVar, ""); |
| EXPECT_FALSE(UnknownVar); |
| |
| // Clear local variables and check they become absent. |
| Cxt.clearLocalVars(); |
| LocalVar = Cxt.getPatternVarValue(LocalVarStr); |
| EXPECT_FALSE(LocalVar); |
| EmptyVar = Cxt.getPatternVarValue(EmptyVarStr); |
| EXPECT_FALSE(EmptyVar); |
| |
| // Redefine global variables and check variables are defined again. |
| GlobalDefines.emplace_back(std::string("$GlobalVar=BAR")); |
| GotError = Cxt.defineCmdlineVariables(GlobalDefines, SM); |
| EXPECT_FALSE(GotError); |
| StringRef GlobalVarStr = "$GlobalVar"; |
| llvm::Optional<StringRef> GlobalVar = Cxt.getPatternVarValue(GlobalVarStr); |
| EXPECT_TRUE(GlobalVar); |
| EXPECT_EQ(*GlobalVar, "BAR"); |
| |
| // Clear local variables and check global variables remain defined. |
| Cxt.clearLocalVars(); |
| GlobalVar = Cxt.getPatternVarValue(GlobalVarStr); |
| EXPECT_TRUE(GlobalVar); |
| } |
| } // namespace |