1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-02-01 05:01:59 +01:00
llvm-mirror/unittests/Support/FileCheckTest.cpp
Thomas Preud'homme 8959c7cf6c FileCheck: Improve FileCheck variable terminology
Summary:
Terminology introduced by [[#]] blocks is confusing and does not
integrate well with existing terminology.

First, variables referred by [[]] blocks are called "pattern variables"
while the text a CHECK directive needs to match is called a "CHECK
pattern". This is inconsistent with variables in [[#]] blocks since
[[#]] blocks are also found in CHECK pattern yet those variables are
called "numeric variable".

Second, the replacing of both [[]] and [[#]] blocks by the value of the
variable or expression they contain is represented by a
FileCheckPatternSubstitution class. The naming refers to being a
substitution in a CHECK pattern but could be wrongly understood as being
a substitution of a pattern variable.

Third and lastly, comments use "numeric expression" to refer both to the
[[#]] blocks as well as to the numeric expressions these blocks contain
which get evaluated at match time.

This patch solves these confusions by
- calling variables in [[]] and [[#]] blocks as string and numeric
  variables respectively;
- referring to [[]] and [[#]] as substitution *blocks*, with the former
  being a string substitution block and the latter a numeric
  substitution block;
- calling [[]] and [[#]] blocks to be replaced by the value of a
  variable or expression they contain a substitution (as opposed to
  definition when these blocks are used to defined a variable), with the
  former being a string substitution and the latter a numeric
  substitution;
- renaming the FileCheckPatternSubstitution as a FileCheckSubstitution
  class with FileCheckStringSubstitution and
  FileCheckNumericSubstitution subclasses;
- restricting the use of "numeric expression" to refer to the expression
  that is evaluated in a numeric substitution.

While numeric substitution blocks only support numeric substitutions of
numeric expressions at the moment there are plans to augment numeric
substitution blocks to support numeric definitions as well as both a
numeric definition and numeric substitution in the same numeric
substitution block.

Reviewers: jhenderson, jdenny, probinson, arichardson

Subscribers: hiraditya, arichardson, probinson, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D62146

llvm-svn: 361445
2019-05-23 00:10:14 +00:00

423 lines
15 KiB
C++

//===- 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, NumericVariable) {
FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
EXPECT_EQ("FOO", FooVar.getName());
// Defined variable: getValue returns a value, setValue fails and value
// remains unchanged.
llvm::Optional<uint64_t> Value = FooVar.getValue();
EXPECT_TRUE(Value);
EXPECT_EQ(42U, *Value);
EXPECT_TRUE(FooVar.setValue(43));
Value = FooVar.getValue();
EXPECT_TRUE(Value);
EXPECT_EQ(42U, *Value);
// Clearing variable: getValue fails, clearValue again fails.
EXPECT_FALSE(FooVar.clearValue());
Value = FooVar.getValue();
EXPECT_FALSE(Value);
EXPECT_TRUE(FooVar.clearValue());
// Undefined variable: setValue works, getValue returns value set.
EXPECT_FALSE(FooVar.setValue(43));
Value = FooVar.getValue();
EXPECT_TRUE(Value);
EXPECT_EQ(43U, *Value);
}
uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
TEST_F(FileCheckTest, NumExpr) {
FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
FileCheckNumExpr NumExpr = FileCheckNumExpr(doAdd, &FooVar, 18);
// Defined variable: eval returns right value, no undefined variable
// returned.
llvm::Optional<uint64_t> Value = NumExpr.eval();
EXPECT_TRUE(Value);
EXPECT_EQ(60U, *Value);
StringRef UndefVar = NumExpr.getUndefVarName();
EXPECT_EQ("", UndefVar);
// Undefined variable: eval fails, undefined variable returned. We call
// getUndefVarName first to check that it can be called without calling
// eval() first.
FooVar.clearValue();
UndefVar = NumExpr.getUndefVarName();
EXPECT_EQ("FOO", UndefVar);
Value = NumExpr.eval();
EXPECT_FALSE(Value);
}
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);
}
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;
}
class ExprTester {
private:
SourceMgr SM;
FileCheckRequest Req;
FileCheckPatternContext Context;
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context);
public:
ExprTester() {
std::vector<std::string> GlobalDefines;
GlobalDefines.emplace_back(std::string("#FOO=42"));
Context.defineCmdlineVariables(GlobalDefines, SM);
// Call ParsePattern to have @LINE defined.
P.ParsePattern("N/A", "CHECK", SM, 1, Req);
}
bool parseExpect(std::string &VarName, std::string &Trailer) {
bool IsPseudo = VarName[0] == '@';
std::string NameTrailer = VarName + Trailer;
StringRef NameTrailerRef = bufferize(SM, NameTrailer);
StringRef VarNameRef = NameTrailerRef.substr(0, VarName.size());
StringRef TrailerRef = NameTrailerRef.substr(VarName.size());
return P.parseNumericSubstitution(VarNameRef, IsPseudo, 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));
// Defined variable.
VarName = "FOO";
EXPECT_FALSE(Tester.parseExpect(VarName, Trailer));
// Undefined variable.
VarName = "UNDEF";
EXPECT_TRUE(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);
// Substitution of an undefined string variable fails.
FileCheckSubstitution Substitution =
FileCheckSubstitution(&Context, "VAR404", 42);
EXPECT_FALSE(Substitution.getResult());
// Substitutions of defined pseudo and non-pseudo numeric variables return
// the right value.
FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
FileCheckNumericVariable NVar = FileCheckNumericVariable("@N", 10);
FileCheckNumExpr NumExprLine = FileCheckNumExpr(doAdd, &LineVar, 0);
FileCheckNumExpr NumExprN = FileCheckNumExpr(doAdd, &NVar, 3);
FileCheckSubstitution SubstitutionLine =
FileCheckSubstitution(&Context, "@LINE", &NumExprLine, 12);
FileCheckSubstitution SubstitutionN =
FileCheckSubstitution(&Context, "N", &NumExprN, 30);
llvm::Optional<std::string> Value = SubstitutionLine.getResult();
EXPECT_TRUE(Value);
EXPECT_EQ("42", *Value);
Value = SubstitutionN.getResult();
EXPECT_TRUE(Value);
EXPECT_EQ("13", *Value);
// Substitution of an undefined numeric variable fails.
LineVar.clearValue();
EXPECT_FALSE(SubstitutionLine.getResult());
NVar.clearValue();
EXPECT_FALSE(SubstitutionN.getResult());
// Substitution of a defined string variable returns the right value.
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context);
Substitution = FileCheckSubstitution(&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);
// getUndefVarName() on a string substitution with an undefined variable
// returns that variable.
FileCheckSubstitution Substitution =
FileCheckSubstitution(&Context, "VAR404", 42);
StringRef UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("VAR404", UndefVar);
// getUndefVarName() on a string substitution with a defined variable returns
// an empty string.
Substitution = FileCheckSubstitution(&Context, "FOO", 42);
UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("", UndefVar);
// getUndefVarName() on a numeric substitution with a defined variable
// returns an empty string.
FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
FileCheckNumExpr NumExpr = FileCheckNumExpr(doAdd, &LineVar, 0);
Substitution = FileCheckSubstitution(&Context, "@LINE", &NumExpr, 12);
UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("", UndefVar);
// getUndefVarName() on a numeric substitution with an undefined variable
// returns that variable.
LineVar.clearValue();
UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("@LINE", 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));
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("#LocalNumVar"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
// Empty variable name.
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("=18"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("#=18"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
// Invalid variable name.
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("18LocalVar=18"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("#18LocalNumVar=18"));
EXPECT_TRUE(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(Cxt.defineCmdlineVariables(GlobalDefines, SM));
Cxt = FileCheckPatternContext();
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
GlobalDefines.emplace_back(std::string("LocalNumVar=36"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
Cxt = FileCheckPatternContext();
// Invalid numeric value for numeric variable.
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("#LocalNumVar=x"));
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="));
GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
bool GotError = Cxt.defineCmdlineVariables(GlobalDefines, SM);
EXPECT_FALSE(GotError);
// Check defined variables are present and undefined is absent.
StringRef LocalVarStr = "LocalVar";
StringRef LocalNumVarRef = bufferize(SM, "LocalNumVar");
StringRef EmptyVarStr = "EmptyVar";
StringRef UnknownVarStr = "UnknownVar";
llvm::Optional<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt);
FileCheckNumExpr *NumExpr =
P.parseNumericSubstitution(LocalNumVarRef, false /*IsPseudo*/, "", SM);
llvm::Optional<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
llvm::Optional<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
EXPECT_TRUE(LocalVar);
EXPECT_EQ(*LocalVar, "FOO");
EXPECT_TRUE(NumExpr);
llvm::Optional<uint64_t> NumExprVal = NumExpr->eval();
EXPECT_TRUE(NumExprVal);
EXPECT_EQ(*NumExprVal, 18U);
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);
// 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_FALSE(NumExpr->eval());
P = FileCheckPattern(Check::CheckPlain, &Cxt);
NumExpr =
P.parseNumericSubstitution(LocalNumVarRef, false /*IsPseudo*/, "", SM);
EXPECT_FALSE(NumExpr);
EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
EXPECT_FALSE(EmptyVar);
// Redefine global variables and check variables are defined again.
GlobalDefines.emplace_back(std::string("$GlobalVar=BAR"));
GlobalDefines.emplace_back(std::string("#$GlobalNumVar=36"));
GotError = Cxt.defineCmdlineVariables(GlobalDefines, SM);
EXPECT_FALSE(GotError);
StringRef GlobalVarStr = "$GlobalVar";
StringRef GlobalNumVarRef = bufferize(SM, "$GlobalNumVar");
llvm::Optional<StringRef> GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
EXPECT_TRUE(GlobalVar);
EXPECT_EQ(*GlobalVar, "BAR");
P = FileCheckPattern(Check::CheckPlain, &Cxt);
NumExpr =
P.parseNumericSubstitution(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
EXPECT_TRUE(NumExpr);
NumExprVal = NumExpr->eval();
EXPECT_TRUE(NumExprVal);
EXPECT_EQ(*NumExprVal, 36U);
// Clear local variables and check global variables remain defined.
Cxt.clearLocalVars();
GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
EXPECT_TRUE(GlobalVar);
P = FileCheckPattern(Check::CheckPlain, &Cxt);
NumExpr =
P.parseNumericSubstitution(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
EXPECT_TRUE(NumExpr);
NumExprVal = NumExpr->eval();
EXPECT_TRUE(NumExprVal);
EXPECT_EQ(*NumExprVal, 36U);
}
} // namespace