| // 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 |