diff options
Diffstat (limited to 'effcee/match_test.cc')
-rw-r--r-- | effcee/match_test.cc | 894 |
1 files changed, 894 insertions, 0 deletions
diff --git a/effcee/match_test.cc b/effcee/match_test.cc new file mode 100644 index 0000000..65350f0 --- /dev/null +++ b/effcee/match_test.cc @@ -0,0 +1,894 @@ +// Copyright 2017 The Effcee Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gmock/gmock.h" + +#include "effcee.h" + +namespace { + +using effcee::Match; +using effcee::Options; +using ::testing::Eq; +using ::testing::HasSubstr; + +const char* kNotFound = "error: expected string not found in input"; +const char* kMissedSame = + "error: CHECK-SAME: is not on the same line as previous match"; +const char* kNextOnSame = + "error: CHECK-NEXT: is on the same line as previous match"; +const char* kNextTooLate = + "error: CHECK-NEXT: is not on the line after the previous match"; +const char* kNotStrFound = "error: CHECK-NOT: string occurred!"; + +// Match free function + +TEST(Match, FreeFunctionLinks) { + Match("", ""); + Match("", "", effcee::Options()); +} + +// Simple checks + +TEST(Match, OneSimpleCheckPass) { + const auto result = Match("Hello", "CHECK: Hello"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, OneSimpleCheckFail) { + const auto result = Match("World", "CHECK: Hello"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK: Hello")); +} + +TEST(Match, TwoSimpleChecksPass) { + const auto result = Match("Hello\nWorld", "CHECK: Hello\nCHECK: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, RepeatedCheckFails) { + const auto result = Match("Hello\nWorld", "CHECK: Hello\nCHECK: Hello"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); +} + +TEST(Match, TwoSimpleChecksPassWithSurroundingText) { + const auto input = R"(Say + Hello + World + Today)"; + const auto result = Match(input, "CHECK: Hello\nCHECK: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, TwoSimpleChecksPassWithInterveningText) { + const auto input = R"(Hello + Between + World)"; + const auto result = Match(input, "CHECK: Hello\nCHECK: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, TwoSimpleChecksPassWhenInSequenceSameLine) { + const auto result = Match("HelloWorld", "CHECK: Hello\nCHECK: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, TwoSimpleChecksFailWhenReversed) { + const auto result = Match("HelloWorld", "CHECK: World\nCHECK: Hello"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK: Hello")); +} + +TEST(Match, SimpleThenSamePasses) { + const auto result = Match("HelloWorld", "CHECK: Hello\nCHECK-SAME: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, SimpleThenSamePassesWithInterveningOnSameLine) { + const auto result = Match("Hello...World", "CHECK: Hello\nCHECK-SAME: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, SimpleThenSameFailsIfOnNextLine) { + const auto result = Match("Hello\nWorld", "CHECK: Hello\nCHECK-SAME: World"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(),HasSubstr(kMissedSame)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-SAME: World")); +} + +TEST(Match, SimpleThenSameFailsIfOnMuchLaterLine) { + const auto result = + Match("Hello\n\nz\n\nWorld", "CHECK: Hello\nCHECK-SAME: World"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kMissedSame)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-SAME: World")); +} + +TEST(Match, SimpleThenSameFailsIfNeverMatched) { + const auto result = Match("Hello\nHome", "CHECK: Hello\nCHECK-SAME: World"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-SAME: World")); +} + +TEST(Match, SimpleThenNextOnSameLineFails) { + const auto result = Match("HelloWorld", "CHECK: Hello\nCHECK-NEXT: World"); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), HasSubstr(kNextOnSame)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NEXT: World")); +} + +TEST(Match, SimpleThenNextPassesIfOnNextLine) { + const auto result = Match("Hello\nWorld", "CHECK: Hello\nCHECK-NEXT: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, SimpleThenNextFailsIfOnAfterNextLine) { + const auto result = Match("Hello\nfoo\nWorld", "CHECK: Hello\nCHECK-NEXT: World"); + EXPECT_THAT(result.message(), HasSubstr(kNextTooLate)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NEXT: World")); +} + +TEST(Match, SimpleThenNextFailsIfNeverMatched) { + const auto result = + Match("Hello\nHome", "CHECK: Hello\nCHECK-NEXT: World"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NEXT: World")); +} + +// TODO: CHECK-NOT + +TEST(Match, AloneNotNeverSeenPasses) { + const auto result = Match("Hello", "CHECK-NOT: Borg"); + EXPECT_TRUE(result); +} + +TEST(Match, LeadingNotNeverSeenPasses) { + const auto result = Match("Hello", "CHECK-NOT: Borg\nCHECK: Hello"); + EXPECT_TRUE(result); +} + +TEST(Match, BetweenNotNeverSeenPasses) { + const auto result = + Match("HelloWorld", "CHECK: Hello\nCHECK-NOT: Borg\nCHECK: World"); + EXPECT_TRUE(result); +} + +TEST(Match, BetweenNotDotsNeverSeenPasses) { + // The before and after matches occur on the same line. + const auto result = + Match("Hello...World", "CHECK: Hello\nCHECK-NOT: Borg\nCHECK: World"); + EXPECT_TRUE(result); +} + +TEST(Match, BetweenNotLinesNeverSeenPasses) { + // The before and after matches occur on different lines. + const auto result = + Match("Hello\nz\nWorld", "CHECK: Hello\nCHECK-NOT: Borg\nCHECK: World"); + EXPECT_TRUE(result); +} + +TEST(Match, NotBetweenMatchesPasses) { + const auto result = + Match("Hello\nWorld\nBorg\n", "CHECK: Hello\nCHECK-NOT: Borg\nCHECK: World"); + EXPECT_TRUE(result); +} + +TEST(Match, NotBeforeFirstMatchPasses) { + const auto result = + Match("Hello\nWorld\nBorg\n", "CHECK-NOT: World\nCHECK: Hello"); + EXPECT_TRUE(result); +} + +TEST(Match, NotAfterLastMatchPasses) { + const auto result = + Match("Hello\nWorld\nBorg\n", "CHECK: World\nCHECK-NOT: Hello"); + EXPECT_TRUE(result); +} + +TEST(Match, NotBeforeFirstMatchFails) { + const auto result = + Match("Hello\nWorld\n", "CHECK-NOT: Hello\nCHECK: World"); + EXPECT_FALSE(result); +} + +TEST(Match, NotBetweenMatchesFails) { + const auto result = + Match("Hello\nWorld\nBorg\n", "CHECK: Hello\nCHECK-NOT: World\nCHECK: Borg"); + EXPECT_FALSE(result); +} + +TEST(Match, NotAfterLastMatchFails) { + const auto result = + Match("Hello\nWorld\n", "CHECK: Hello\nCHECK-NOT: World"); + EXPECT_FALSE(result); +} + +TEST(Match, TrailingNotNeverSeenPasses) { + const auto result = Match("Hello", "CHECK: Hello\nCHECK-NOT: Borg"); + EXPECT_TRUE(result); +} + +TEST(Match, AloneNotSeenFails) { + const auto result = Match("Borg", "CHECK-NOT: Borg"); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), HasSubstr(kNotStrFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NOT: Borg")); +} + +TEST(Match, LeadingNotSeenFails) { + const auto result = Match("Borg", "CHECK-NOT: Borg\nCHECK: Hello"); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), HasSubstr(kNotStrFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NOT: Borg")); +} + +TEST(Match, BetweenNotSeenFails) { + const auto result = + Match("HelloBorgWorld", "CHECK: Hello\nCHECK-NOT: Borg\nCHECK: World"); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), HasSubstr(kNotStrFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NOT: Borg")); +} + +TEST(Match, BetweenNotDotsSeenFails) { + const auto result = + Match("Hello.Borg.World", "CHECK: Hello\nCHECK-NOT: Borg\nCHECK: World"); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), HasSubstr(kNotStrFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NOT: Borg")); +} + +TEST(Match, BetweenNotLinesSeenFails) { + const auto result = Match("Hello\nBorg\nWorld", + "CHECK: Hello\nCHECK-NOT: Borg\nCHECK: World"); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), HasSubstr(kNotStrFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NOT: Borg")); +} + +TEST(Match, TrailingNotSeenFails) { + const auto result = Match("HelloBorg", "CHECK: Hello\nCHECK-NOT: Borg"); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), HasSubstr(kNotStrFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NOT: Borg")); +} + +// WIP: CHECK-LABEL + +TEST(Match, OneLabelCheckPass) { + const auto result = Match("Hello", "CHECK-LABEL: Hello"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, OneLabelCheckFail) { + const auto result = Match("World", "CHECK-LABEL: Hello"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-LABEL: Hello")); +} + +TEST(Match, TwoLabelChecksPass) { + const auto result = + Match("Hello\nWorld", "CHECK-LABEL: Hello\nCHECK-LABEL: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, TwoLabelChecksPassWithSurroundingText) { + const auto input = R"(Say + Hello + World + Today)"; + const auto result = Match(input, "CHECK-LABEL: Hello\nCHECK-LABEL: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, TwoLabelChecksPassWithInterveningText) { + const auto input = R"(Hello + Between + World)"; + const auto result = Match(input, "CHECK-LABEL: Hello\nCHECK-LABEL: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, TwoLabelChecksPassWhenInSequenceSameLine) { + const auto result = + Match("HelloWorld", "CHECK-LABEL: Hello\nCHECK-LABEL: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, TwoLabelChecksFailWhenReversed) { + const auto result = + Match("HelloWorld", "CHECK-LABEL: World\nCHECK-LABEL: Hello"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-LABEL: Hello")); +} + +// WIP: Mixture of Simple and Label checks + +TEST(Match, SimpleAndLabelChecksPass) { + const auto result = Match("Hello\nWorld", "CHECK: Hello\nCHECK-LABEL: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, LabelAndSimpleChecksPass) { + const auto result = Match("Hello\nWorld", "CHECK-LABEL: Hello\nCHECK: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, SimpleAndLabelChecksFails) { + const auto result = Match("Hello\nWorld", "CHECK: Hello\nCHECK-LABEL: Band"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-LABEL: Band")); +} + +TEST(Match, LabelAndSimpleChecksFails) { + const auto result = Match("Hello\nWorld", "CHECK-LABEL: Hello\nCHECK: Band"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK: Band")); +} + +// DAG checks: Part 1: Tests simlar to simple checks tests + +TEST(Match, OneDAGCheckPass) { + const auto result = Match("Hello", "CHECK-DAG: Hello"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, OneDAGCheckFail) { + const auto result = Match("World", "CHECK-DAG: Hello"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-DAG: Hello")); +} + +TEST(Match, TwoDAGChecksPass) { + const auto result = Match("Hello\nWorld", "CHECK-DAG: Hello\nCHECK-DAG: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, TwoDAGChecksPassWithSurroundingText) { + const auto input = R"(Say + Hello + World + Today)"; + const auto result = Match(input, "CHECK-DAG: Hello\nCHECK-DAG: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, TwoDAGChecksPassWithInterveningText) { + const auto input = R"(Hello + Between + World)"; + const auto result = Match(input, "CHECK-DAG: Hello\nCHECK-DAG: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, TwoDAGChecksPassWhenInSequenceSameLine) { + const auto result = Match("HelloWorld", "CHECK-DAG: Hello\nCHECK-DAG: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, DAGThenSamePasses) { + const auto result = Match("HelloWorld", "CHECK-DAG: Hello\nCHECK-SAME: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, DAGThenSamePassesWithInterveningOnSameLine) { + const auto result = Match("Hello...World", "CHECK-DAG: Hello\nCHECK-SAME: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, DAGThenSameFailsIfOnNextLine) { + const auto result = Match("Hello\nWorld", "CHECK-DAG: Hello\nCHECK-SAME: World"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kMissedSame)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-SAME: World")); +} + +TEST(Match, DAGThenSameFailsIfOnMuchLaterLine) { + const auto result = + Match("Hello\n\nz\n\nWorld", "CHECK-DAG: Hello\nCHECK-SAME: World"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kMissedSame)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-SAME: World")); +} + +TEST(Match, DAGThenSameFailsIfNeverMatched) { + const auto result = Match("Hello\nHome", "CHECK-DAG: Hello\nCHECK-SAME: World"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-SAME: World")); +} + +TEST(Match, DAGThenNextOnSameLineFails) { + const auto result = Match("HelloWorld", "CHECK-DAG: Hello\nCHECK-NEXT: World"); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), HasSubstr(kNextOnSame)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NEXT: World")); +} + +TEST(Match, DAGThenNextPassesIfOnNextLine) { + const auto result = Match("Hello\nWorld", "CHECK-DAG: Hello\nCHECK-NEXT: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, DAGThenNextPassesIfOnAfterNextLine) { + const auto result = Match("Hello\nWorld", "CHECK-DAG: Hello\nCHECK-NEXT: World"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, DAGThenNextFailsIfNeverMatched) { + const auto result = + Match("Hello\nHome", "CHECK-DAG: Hello\nCHECK-NEXT: World"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NEXT: World")); +} + +// DAG checks: Part 2: Out of order matching + +TEST(Match, TwoDAGMatchedOutOfOrderPasses) { + const auto result = Match("Hello\nWorld", "CHECK-DAG: World\nCHECK-DAG: Hello"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, ThreeDAGMatchedOutOfOrderPasses) { + const auto result = + Match("Hello\nWorld\nNow", + "CHECK-DAG: Now\nCHECK-DAG: World\nCHECK-DAG: Hello"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, TwoDAGChecksPassWhenReversedMatchingSameLine) { + const auto result = Match("HelloWorld", "CHECK-DAG: World\nCHECK-DAG: Hello"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, DAGChecksGreedilyConsumeInput) { + const auto result = + Match("Hello\nBlocker\nWorld\n", + "CHECK-DAG: Hello\nCHECK-DAG: World\nCHECK: Blocker"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-DAG: World")); +} + +// DAG checks: Part 3: Interaction with Not checks + +TEST(Match, DAGsAreSeparatedByNot) { + // In this case the search for "Before" consumes the entire input. + const auto result = + Match("After\nBlocker\nBefore\n", + "CHECK-DAG: Before\nCHECK-NOT: nothing\nCHECK-DAG: After"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-DAG: After")); +} + +TEST(Match, TwoDAGsAreSeparatedByNot) { + const auto result = Match("After\nApres\nBlocker\nBefore\nAnte", + "CHECK-DAG: Ante\nCHECK-DAG: Before\nCHECK-NOT: " + "nothing\nCHECK-DAG: Apres\nCHECK-DAG: After"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-DAG: Apres")); +} + +// DAG checks: Part 4: Interaction with simple checks + +TEST(Match, DAGsAreTerminatedBySimple) { + const auto result = + Match("After\nsimple\nBefore\n", + "CHECK-DAG: Before\nCHECK: simple\nCHECK-DAG: After"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-DAG: Before")); +} + +TEST(Match, TwoDAGsAreTerminatedBySimple) { + const auto result = Match("After\nApres\nBlocker\nBefore\nAnte", + "CHECK-DAG: Ante\nCHECK-DAG: Before\nCHECK: " + "Blocker\nCHECK-DAG: Apres\nCHECK-DAG: After"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr(kNotFound)); + EXPECT_THAT(result.message(), HasSubstr("CHECK-DAG: Ante")); +} + +// Test detailed message text + +TEST(Match, MessageStringNotFoundWhenNeverMatchedAnything) { + const char* input = R"(Begin +Hello + World)"; + const char* checks = R"( +Hello + ; CHECK: Needle +)"; + const char* expected = R"(chklist:3:13: error: expected string not found in input + ; CHECK: Needle + ^ +myin.txt:1:1: note: scanning from here +Begin +^ +)"; + const auto result = + Match(input, checks, + Options().SetInputName("myin.txt").SetChecksName("chklist")); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), Eq(expected)) << result.message(); +} + +TEST(Match, MessageStringNotFoundAfterInitialMatch) { + const char* input = R"(Begin +Hello + World)"; + const char* checks = R"( +Hello + ; CHECK-LABEL: Hel + ; CHECK: Needle +)"; + const char* expected = R"(chklist:4:13: error: expected string not found in input + ; CHECK: Needle + ^ +myin.txt:2:4: note: scanning from here +Hello + ^ +)"; + const auto result = + Match(input, checks, + Options().SetInputName("myin.txt").SetChecksName("chklist")); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), Eq(expected)) << result.message(); +} + +TEST(Match, MessageCheckNotStringFoundAtStart) { + const auto result = + Match(" Cheese", "CHECK-NOT: Cheese", + Options().SetInputName("in").SetChecksName("checks")); + EXPECT_FALSE(result); + const char* expected = R"(in:1:3: error: CHECK-NOT: string occurred! + Cheese + ^ +checks:1:12: note: CHECK-NOT: pattern specified here +CHECK-NOT: Cheese + ^ +)"; + EXPECT_THAT(result.message(), Eq(expected)) << result.message(); +} + +TEST(Match, MessageCheckNotStringFoundAfterInitialMatch) { + const auto result = + Match("Cream Cheese", "CHECK: Cream\nCHECK-NOT: Cheese", + Options().SetInputName("in").SetChecksName("checks")); + EXPECT_FALSE(result); + const char* expected = R"(in:1:10: error: CHECK-NOT: string occurred! +Cream Cheese + ^ +checks:2:12: note: CHECK-NOT: pattern specified here +CHECK-NOT: Cheese + ^ +)"; + EXPECT_THAT(result.message(), Eq(expected)) << result.message(); +} + +TEST(Match, MessageCheckSameFails) { + const char* input = R"( +Bees +Make +Delicious Honey +)"; + const char* checks = R"( +CHECK: Make +CHECK-SAME: Honey +)"; + + const auto result = Match( + input, checks, Options().SetInputName("in").SetChecksName("checks")); + EXPECT_FALSE(result); + const char* expected = R"(checks:3:13: error: CHECK-SAME: is not on the same line as previous match +CHECK-SAME: Honey + ^ +in:4:11: note: 'next' match was here +Delicious Honey + ^ +in:3:5: note: previous match ended here +Make + ^ +)"; + EXPECT_THAT(result.message(), Eq(expected)) << result.message(); +} + +TEST(Match, MessageCheckNextFailsSinceOnSameLine) { + const char* input = R"( +Bees +Make +Delicious Honey +)"; + const char* checks = R"( +CHECK: Bees +CHECK-NEXT: Honey +)"; + + const auto result = Match( + input, checks, Options().SetInputName("in").SetChecksName("checks")); + EXPECT_FALSE(result); + const char* expected = R"(checks:3:13: error: CHECK-NEXT: is not on the line after the previous match +CHECK-NEXT: Honey + ^ +in:4:11: note: 'next' match was here +Delicious Honey + ^ +in:2:5: note: previous match ended here +Bees + ^ +in:3:1: note: non-matching line after previous match is here +Make +^ +)"; + EXPECT_THAT(result.message(), Eq(expected)) << result.message(); +} + +TEST(Match, MessageCheckNextFailsSinceLaterLine) { + const char* input = R"( +Bees Make Delicious Honey +)"; + const char* checks = R"( +CHECK: Make +CHECK-NEXT: Honey +)"; + + const auto result = Match( + input, checks, Options().SetInputName("in").SetChecksName("checks")); + EXPECT_FALSE(result); + const char* expected = R"(checks:3:13: error: CHECK-NEXT: is on the same line as previous match +CHECK-NEXT: Honey + ^ +in:2:21: note: 'next' match was here +Bees Make Delicious Honey + ^ +in:2:10: note: previous match ended here +Bees Make Delicious Honey + ^ +)"; + EXPECT_THAT(result.message(), Eq(expected)) << result.message(); +} + +TEST(Match, MessageUnresolvedDAG) { + const char* input = R"( +Bees +Make +Delicious Honey +)"; + const char* checks = R"( +CHECK: ees +CHECK-DAG: Flowers +CHECK: Honey +)"; + + const auto result = Match( + input, checks, Options().SetInputName("in").SetChecksName("checks")); + EXPECT_FALSE(result); + const char* expected = R"(checks:3:12: error: expected string not found in input +CHECK-DAG: Flowers + ^ +in:2:5: note: scanning from here +Bees + ^ +in:4:11: note: next check matches here +Delicious Honey + ^ +)"; + EXPECT_THAT(result.message(), Eq(expected)) << result.message(); +} + + +// Regexp + +TEST(Match, CheckRegexPass) { + const auto result = Match("Hello", "CHECK: He{{ll}}o"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, CheckRegexWithFalseStartPass) { + // This examples has three false starts. That is, we match the first + // few parts of the pattern before we finally match it. + const auto result = Match("He Hel Hell Hello Helloo", "CHECK: He{{ll}}oo"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, CheckRegexWithRangePass) { + const auto result = Match("Hello", "CHECK: He{{[a-z]+}}o"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, CheckRegexMatchesEmptyPass) { + const auto result = Match("Heo", "CHECK: He{{[a-z]*}}o"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, CheckThreeRegexPass) { + // This proves that we parsed the check correctly, finding matching pairs + // of regexp delimiters {{ and }}. + const auto result = Match("Hello World", "CHECK: He{{[a-z]+}}o{{ +}}{{[Ww]}}orld"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, CheckRegexFail) { + const auto result = Match("Heo", "CHECK: He{{[a-z]*}}o"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, MessageStringRegexRegexWithFalseStartFail) { + const char* input = "He Hel Hell Hello Hello"; + const char* checks = "CHECK: He{{ll}}oo"; + const char* expected = R"(chklist:1:8: error: expected string not found in input +CHECK: He{{ll}}oo + ^ +myin.txt:1:1: note: scanning from here +He Hel Hell Hello Hello +^ +)"; + const auto result = + Match(input, checks, + Options().SetInputName("myin.txt").SetChecksName("chklist")); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), Eq(expected)) << result.message(); +} + +TEST(Match, MessageStringRegexNotFoundWhenNeverMatchedAnything) { + const char* input = R"(Begin +Hello + World)"; + const char* checks = R"( +Hello + ; CHECK: He{{[0-9]+}}llo +)"; + const char* expected = R"(chklist:3:13: error: expected string not found in input + ; CHECK: He{{[0-9]+}}llo + ^ +myin.txt:1:1: note: scanning from here +Begin +^ +)"; + const auto result = + Match(input, checks, + Options().SetInputName("myin.txt").SetChecksName("chklist")); + EXPECT_FALSE(result); + EXPECT_THAT(result.message(), Eq(expected)) << result.message(); +} + + +// Statefulness: variable definitions and uses + +TEST(Match, VarDefFollowedByUsePass) { + const auto result = + Match("Hello\nHello", "CHECK: H[[X:[a-z]+]]o\nCHECK-NEXT: H[[X]]o"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, VarDefFollowedByUseFail) { + const auto result = + Match("Hello\n\nWorld", "CHECK: H[[X:[a-z]+]]o\nCHECK: H[[X]]o"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), + HasSubstr(":2:8: error: expected string not found in input")); + EXPECT_THAT(result.message(), + HasSubstr("note: with variable \"X\" equal to \"ell\"")); +} + +TEST(Match, VarDefFollowedByUseFailAfterDAG) { + const auto result = + Match("Hello\nWorld", + "CHECK: H[[X:[a-z]+]]o\nCHECK-DAG: box[[X]]\nCHECK: H[[X]]o"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), + HasSubstr(":2:12: error: expected string not found in input")); + EXPECT_THAT(result.message(), + HasSubstr("note: with variable \"X\" equal to \"ell\"")); +} + +TEST(Match, VarDefFollowedByUseInNotCheck) { + const auto result = + Match("Hello\nHello", "CHECK: H[[X:[a-z]+]]o\nCHECK-NOT: H[[X]]o"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), HasSubstr("CHECK-NOT: string occurred")); + EXPECT_THAT(result.message(), + HasSubstr("note: with variable \"X\" equal to \"ell\"")); +} + +TEST(Match, VarDefFollowedByUseInNextCheckRightLine) { + const auto result = + Match("Hello\nHello", "CHECK: H[[X:[a-z]+]]o\nCHECK-NEXT: Blad[[X]]"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), + HasSubstr(":2:13: error: expected string not found in input")); + EXPECT_THAT(result.message(), + HasSubstr("note: with variable \"X\" equal to \"ell\"")); +} + +TEST(Match, VarDefFollowedByUseInNextCheckBadLine) { + const auto result = + Match("Hello\n\nHello", "CHECK: H[[X:[a-z]+]]o\nCHECK-NEXT: H[[X]]o"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), + HasSubstr(":2:13: error: CHECK-NEXT: is not on the line after")); + EXPECT_THAT(result.message(), + HasSubstr("note: with variable \"X\" equal to \"ell\"")); +} + +TEST(Match, UndefinedVarNeverMatches) { + const auto result = Match("Hello HeXllo", "CHECK: He[[X]]llo"); + EXPECT_FALSE(result) << result.message(); + EXPECT_THAT(result.message(), + HasSubstr("note: uses undefined variable \"X\"")); +} + +TEST(Match, NoteSeveralUndefinedVariables) { + const auto result = Match("Hello HeXllo", "CHECK: He[[X]]l[[YZ]]lo[[Q]]"); + EXPECT_FALSE(result) << result.message(); + const char* substr = R"( +<stdin>:1:1: note: uses undefined variable "X" +Hello HeXllo +^ +<stdin>:1:1: note: uses undefined variable "YZ" +Hello HeXllo +^ +<stdin>:1:1: note: uses undefined variable "Q" +Hello HeXllo +^ +)"; + EXPECT_THAT(result.message(), HasSubstr(substr)); +} + +TEST(Match, OutOfOrderDefAndUseViaDAGChecks) { + // In this example the X variable should be set to 'l', and then match + // the earlier occurrence in 'Hello'. + const auto result = Match( + "Hello\nWorld", "CHECK-DAG: Wor[[X:[a-z]+]]d\nCHECK-DAG: He[[X]]lo"); + EXPECT_FALSE(result) << result.message(); +} + +TEST(Match, VarDefRegexCountsParenthesesProperlyPass) { + const auto result = Match( + "FirstabababSecondcdcd\n1ababab2cdcd", + "CHECK: First[[X:(ab)+]]Second[[Y:(cd)+]]\nCHECK: 1[[X]]2[[Y]]"); + EXPECT_TRUE(result) << result.message(); +} + +TEST(Match, VarDefRegexCountsParenthesesProperlyFail) { + const auto result = + Match("Firstababab1abab", "CHECK: First[[X:(ab)+]]\nCHECK: 1[[X]]"); + EXPECT_FALSE(result) << result.message(); + const char* substr = R"(<stdin>:2:8: error: expected string not found in input +CHECK: 1[[X]] + ^ +<stdin>:1:12: note: scanning from here +Firstababab1abab + ^ +<stdin>:1:12: note: with variable "X" equal to "ababab" +Firstababab1abab + ^ +)"; + EXPECT_THAT(result.message(), HasSubstr(substr)); +} + +} // namespace |