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 0cb0f08935 FileCheck [4/12]: Introduce @LINE numeric expressions
Summary:
This patch is part of a patch series to add support for FileCheck
numeric expressions. This specific patch introduces the @LINE numeric
expressions.

This commit introduces a new syntax to express a relation a numeric
value in the input text must have with the line number of a given CHECK
pattern: [[#<@LINE numeric expression>]]. Further commits build on that
to express relations between several numeric values in the input text.
To help with naming, regular variables are renamed into pattern
variables and old @LINE expression syntax is referred to as legacy
numeric expression.

Compared to existing @LINE expressions, this new syntax allow arbitrary
spacing between the component of the expression. It offers otherwise the
same functionality but the commit serves to introduce some of the data
structure needed to support more general numeric expressions.

Copyright:
    - Linaro (changes up to diff 183612 of revision D55940)
    - GraphCore (changes in later versions of revision D55940 and
                 in new revision created off D55940)

Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar, arichardson, rnk

Subscribers: hiraditya, llvm-commits, probinson, dblaikie, grimar, arichardson, tra, rnk, kristina, hfinkel, rogfer01, JonChesterfield

Tags: #llvm

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

llvm-svn: 359741
2019-05-02 00:04:38 +00:00

256 lines
8.3 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, 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