[FileCheck] Clean and improve unit tests

Summary:
Clean redundant unit test checks (codepath already tested elsewhere) and
add a few missing checks for existing numeric substitution and match
logic.

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

Reviewed By: jhenderson

Subscribers: llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D72912
This commit is contained in:
Thomas Preud'homme 2020-01-15 23:02:03 +00:00
parent 7bee94410c
commit abd0ab389e
1 changed files with 119 additions and 83 deletions

View File

@ -239,12 +239,12 @@ public:
P = Pattern(Check::CheckPlain, &Context, LineNumber++);
}
bool parseSubstExpect(StringRef Expr) {
bool parseSubstExpect(StringRef Expr, bool IsLegacyLineExpr = false) {
StringRef ExprBufferRef = bufferize(SM, Expr);
Optional<NumericVariable *> DefinedNumericVariable;
return errorToBool(
P.parseNumericSubstitutionBlock(ExprBufferRef, DefinedNumericVariable,
false, LineNumber - 1, &Context, SM)
return errorToBool(P.parseNumericSubstitutionBlock(
ExprBufferRef, DefinedNumericVariable,
IsLegacyLineExpr, LineNumber - 1, &Context, SM)
.takeError());
}
@ -260,14 +260,15 @@ public:
}
};
TEST_F(FileCheckTest, ParseExpr) {
TEST_F(FileCheckTest, ParseNumericSubstitutionBlock) {
PatternTester Tester;
// Variable definition.
// Definition of invalid variable.
EXPECT_TRUE(Tester.parseSubstExpect("10VAR:"));
EXPECT_TRUE(Tester.parseSubstExpect("@FOO:"));
// Invalid variable name.
EXPECT_TRUE(Tester.parseSubstExpect("%VAR:"));
// Invalid definition of pseudo variable.
EXPECT_TRUE(Tester.parseSubstExpect("@LINE:"));
// Conflict with pattern variable.
@ -281,82 +282,100 @@ TEST_F(FileCheckTest, ParseExpr) {
EXPECT_FALSE(Tester.parseSubstExpect(" VAR2:"));
EXPECT_FALSE(Tester.parseSubstExpect("VAR3 :"));
EXPECT_FALSE(Tester.parseSubstExpect("VAR3: "));
EXPECT_FALSE(Tester.parsePatternExpect("[[#FOOBAR: FOO+1]]"));
EXPECT_FALSE(Tester.parseSubstExpect("FOOBAR: FOO+1"));
// Numeric expression.
// Unacceptable variable.
EXPECT_TRUE(Tester.parseSubstExpect("10VAR"));
// Invalid variable name.
EXPECT_TRUE(Tester.parseSubstExpect("%VAR"));
// Invalid pseudo variable.
EXPECT_TRUE(Tester.parseSubstExpect("@FOO"));
// Only valid variable.
EXPECT_FALSE(Tester.parseSubstExpect("@LINE"));
EXPECT_FALSE(Tester.parseSubstExpect("FOO"));
EXPECT_FALSE(Tester.parseSubstExpect("UNDEF"));
// Invalid use of variable defined on the same line. Use parsePatternExpect
// for the variable to be recorded in GlobalNumericVariableTable and thus
// appear defined to parseNumericVariableUse. 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("[[#SAME_LINE_VAR:]]"));
EXPECT_TRUE(Tester.parseSubstExpect("SAME_LINE_VAR"));
// Invalid use of variable defined on the same line from an expression not
// using any variable defined on the same line.
ASSERT_FALSE(Tester.parsePatternExpect("[[#SAME_LINE_EXPR_VAR:@LINE+1]]"));
EXPECT_TRUE(Tester.parseSubstExpect("SAME_LINE_EXPR_VAR"));
// Valid use of undefined variable which creates the variable and record it
// in GlobalNumericVariableTable.
ASSERT_FALSE(Tester.parseSubstExpect("UNDEF"));
EXPECT_TRUE(Tester.parsePatternExpect("[[UNDEF:.*]]"));
// Invalid literal.
EXPECT_TRUE(Tester.parseSubstExpect("42U"));
// 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"));
// Valid single operand expression.
EXPECT_FALSE(Tester.parseSubstExpect("FOO"));
// 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"));
// Valid expression with 2 or more operands.
EXPECT_FALSE(Tester.parseSubstExpect("FOO+3"));
EXPECT_FALSE(Tester.parseSubstExpect("FOO-3+FOO"));
// Unsupported operator.
EXPECT_TRUE(Tester.parseSubstExpect("@LINE/2"));
// Missing offset operand.
// Missing RHS 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]]"));
// Errors in RHS operand are bubbled up by parseBinop() to
// parseNumericSubstitutionBlock.
EXPECT_TRUE(Tester.parseSubstExpect("@LINE+%VAR"));
// Invalid legacy @LINE expression with non literal rhs.
EXPECT_TRUE(Tester.parseSubstExpect("@LINE+@LINE", /*IsLegacyNumExpr=*/true));
// Invalid legacy @LINE expression made of a single literal.
EXPECT_TRUE(Tester.parseSubstExpect("2", /*IsLegacyNumExpr=*/true));
// Valid legacy @LINE expression.
EXPECT_FALSE(Tester.parseSubstExpect("@LINE+2", /*IsLegacyNumExpr=*/true));
// Invalid legacy @LINE expression with more than 2 operands.
EXPECT_TRUE(
Tester.parseSubstExpect("@LINE+2+@LINE", /*IsLegacyNumExpr=*/true));
EXPECT_TRUE(Tester.parseSubstExpect("@LINE+2+2", /*IsLegacyNumExpr=*/true));
}
TEST_F(FileCheckTest, ParsePattern) {
PatternTester Tester;
// Space in pattern variable expression.
// Invalid space in string substitution.
EXPECT_TRUE(Tester.parsePatternExpect("[[ BAR]]"));
// Invalid variable name.
// Invalid variable name in string substitution.
EXPECT_TRUE(Tester.parsePatternExpect("[[42INVALID]]"));
// Invalid pattern variable definition.
// Invalid string 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.
// Valid use of string variable.
EXPECT_FALSE(Tester.parsePatternExpect("[[BAR]]"));
// Valid pattern variable definition.
// Valid string variable definition.
EXPECT_FALSE(Tester.parsePatternExpect("[[PAT:[0-9]+]]"));
// Invalid numeric expressions.
// Invalid numeric substitution.
EXPECT_TRUE(Tester.parsePatternExpect("[[#42INVALID]]"));
EXPECT_TRUE(Tester.parsePatternExpect("[[#@FOO]]"));
EXPECT_TRUE(Tester.parsePatternExpect("[[#@LINE/2]]"));
// Valid numeric expressions and numeric variable definition.
// Valid numeric substitution.
EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO]]"));
EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE+2]]"));
EXPECT_FALSE(Tester.parsePatternExpect("[[#NUMVAR:]]"));
}
TEST_F(FileCheckTest, Match) {
@ -374,7 +393,17 @@ TEST_F(FileCheckTest, Match) {
EXPECT_TRUE(Tester.matchExpect(""));
EXPECT_FALSE(Tester.matchExpect("18"));
// Check matching the variable defined matches the correct number only
// Check matching an undefined variable returns a NotFound error.
Tester.initNextPattern();
ASSERT_FALSE(Tester.parsePatternExpect("100"));
EXPECT_TRUE(Tester.matchExpect("101"));
// Check matching the defined variable matches the correct number only.
Tester.initNextPattern();
ASSERT_FALSE(Tester.parsePatternExpect("[[#NUMVAR]]"));
EXPECT_FALSE(Tester.matchExpect("18"));
// Check matching several substitutions does not match them independently.
Tester.initNextPattern();
Tester.parsePatternExpect("[[#NUMVAR]] [[#NUMVAR+2]]");
EXPECT_TRUE(Tester.matchExpect("19 21"));
@ -385,16 +414,16 @@ TEST_F(FileCheckTest, Match) {
// the correct value for @LINE.
Tester.initNextPattern();
EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
// Ok, @LINE is 5 now.
EXPECT_FALSE(Tester.matchExpect("5"));
// Ok, @LINE is 7 now.
EXPECT_FALSE(Tester.matchExpect("7"));
Tester.initNextPattern();
// @LINE is now 6, match with substitution failure.
// @LINE is now 8, match with substitution failure.
EXPECT_FALSE(Tester.parsePatternExpect("[[#UNKNOWN]]"));
EXPECT_TRUE(Tester.matchExpect("FOO"));
Tester.initNextPattern();
// Check that @LINE is 7 as expected.
// Check that @LINE is 9 as expected.
EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
EXPECT_FALSE(Tester.matchExpect("7"));
EXPECT_FALSE(Tester.matchExpect("9"));
}
TEST_F(FileCheckTest, Substitution) {
@ -411,30 +440,19 @@ TEST_F(FileCheckTest, Substitution) {
ASSERT_FALSE(bool(SubstValue));
expectUndefError("VAR404", SubstValue.takeError());
// Substitutions of defined pseudo and non-pseudo numeric variables return
// the right value.
NumericVariable LineVar("@LINE", 1);
// Numeric substitution blocks constituted of defined numeric variables are
// substituted for the variable's value.
NumericVariable NVar("N", 1);
LineVar.setValue(42);
NVar.setValue(10);
auto LineVarUse = std::make_unique<NumericVariableUse>("@LINE", &LineVar);
auto NVarUse = std::make_unique<NumericVariableUse>("N", &NVar);
NumericSubstitution SubstitutionLine(&Context, "@LINE", std::move(LineVarUse),
12);
NumericSubstitution SubstitutionN(&Context, "N", std::move(NVarUse), 30);
SubstValue = SubstitutionLine.getResult();
ASSERT_TRUE(bool(SubstValue));
EXPECT_EQ("42", *SubstValue);
NumericSubstitution SubstitutionN(&Context, "N", std::move(NVarUse),
/*InsertIdx=*/30);
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));
@ -453,6 +471,9 @@ TEST_F(FileCheckTest, FileCheckContext) {
std::vector<std::string> GlobalDefines;
SourceMgr SM;
// No definition.
EXPECT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
// Missing equal sign.
GlobalDefines.emplace_back(std::string("LocalVar"));
EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
@ -505,19 +526,35 @@ TEST_F(FileCheckTest, FileCheckContext) {
GlobalDefines.emplace_back(std::string("#LocalNumVar2=LocalNumVar1+2"));
ASSERT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
// Check defined variables are present and undefined is absent.
// Create @LINE pseudo numeric variable and check it is present by matching
// it.
size_t LineNumber = 1;
Pattern P(Check::CheckPlain, &Cxt, LineNumber);
FileCheckRequest Req;
Cxt.createLineVariable();
ASSERT_FALSE(P.parsePattern("[[@LINE]]", "CHECK", SM, Req));
size_t MatchLen;
ASSERT_FALSE(errorToBool(P.match("1", MatchLen, SM).takeError()));
#ifndef NDEBUG
// Recreating @LINE pseudo numeric variable fails.
EXPECT_DEATH(Cxt.createLineVariable(),
"@LINE pseudo numeric variable already created");
#endif
// Check defined variables are present and undefined ones are 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);
Pattern P(Check::CheckPlain, &Cxt, 1);
P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
Optional<NumericVariable *> DefinedNumericVariable;
Expected<std::unique_ptr<ExpressionAST>> ExpressionASTPointer =
P.parseNumericSubstitutionBlock(LocalNumVar1Ref, DefinedNumericVariable,
/*IsLegacyLineExpr=*/false,
/*LineNumber=*/1, &Cxt, SM);
/*IsLegacyLineExpr=*/false, LineNumber,
&Cxt, SM);
ASSERT_TRUE(bool(LocalVar));
EXPECT_EQ(*LocalVar, "FOO");
Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
@ -526,10 +563,9 @@ TEST_F(FileCheckTest, FileCheckContext) {
Expected<uint64_t> ExpressionVal = (*ExpressionASTPointer)->eval();
ASSERT_TRUE(bool(ExpressionVal));
EXPECT_EQ(*ExpressionVal, 18U);
ExpressionASTPointer =
P.parseNumericSubstitutionBlock(LocalNumVar2Ref, DefinedNumericVariable,
/*IsLegacyLineExpr=*/false,
/*LineNumber=*/1, &Cxt, SM);
ExpressionASTPointer = P.parseNumericSubstitutionBlock(
LocalNumVar2Ref, DefinedNumericVariable,
/*IsLegacyLineExpr=*/false, LineNumber, &Cxt, SM);
ASSERT_TRUE(bool(ExpressionASTPointer));
ExpressionVal = (*ExpressionASTPointer)->eval();
ASSERT_TRUE(bool(ExpressionVal));
@ -547,16 +583,16 @@ TEST_F(FileCheckTest, FileCheckContext) {
// variable clearing due to --enable-var-scope happens after numeric
// expressions are linked to the numeric variables they use.
EXPECT_TRUE(errorToBool((*ExpressionASTPointer)->eval().takeError()));
P = Pattern(Check::CheckPlain, &Cxt, 2);
P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
ExpressionASTPointer = P.parseNumericSubstitutionBlock(
LocalNumVar1Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
/*LineNumber=*/2, &Cxt, SM);
LineNumber, &Cxt, SM);
ASSERT_TRUE(bool(ExpressionASTPointer));
ExpressionVal = (*ExpressionASTPointer)->eval();
EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
ExpressionASTPointer = P.parseNumericSubstitutionBlock(
LocalNumVar2Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
/*LineNumber=*/2, &Cxt, SM);
LineNumber, &Cxt, SM);
ASSERT_TRUE(bool(ExpressionASTPointer));
ExpressionVal = (*ExpressionASTPointer)->eval();
EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
@ -575,10 +611,10 @@ TEST_F(FileCheckTest, FileCheckContext) {
Expected<StringRef> GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
ASSERT_TRUE(bool(GlobalVar));
EXPECT_EQ(*GlobalVar, "BAR");
P = Pattern(Check::CheckPlain, &Cxt, 3);
P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
ExpressionASTPointer = P.parseNumericSubstitutionBlock(
GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
/*LineNumber=*/3, &Cxt, SM);
LineNumber, &Cxt, SM);
ASSERT_TRUE(bool(ExpressionASTPointer));
ExpressionVal = (*ExpressionASTPointer)->eval();
ASSERT_TRUE(bool(ExpressionVal));
@ -587,10 +623,10 @@ TEST_F(FileCheckTest, FileCheckContext) {
// Clear local variables and check global variables remain defined.
Cxt.clearLocalVars();
EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError()));
P = Pattern(Check::CheckPlain, &Cxt, 4);
P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
ExpressionASTPointer = P.parseNumericSubstitutionBlock(
GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
/*LineNumber=*/4, &Cxt, SM);
LineNumber, &Cxt, SM);
ASSERT_TRUE(bool(ExpressionASTPointer));
ExpressionVal = (*ExpressionASTPointer)->eval();
ASSERT_TRUE(bool(ExpressionVal));