kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/cxx/verifier/verifier_unit_test.cc (about) 1 /* 2 * Copyright 2014 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <optional> 18 #include <regex> 19 #include <string_view> 20 21 #include "absl/log/initialize.h" 22 #include "google/protobuf/text_format.h" 23 #include "google/protobuf/util/json_util.h" 24 #include "gtest/gtest.h" 25 #include "verifier.h" 26 27 namespace kythe { 28 namespace verifier { 29 namespace { 30 using MarkedSource = kythe::proto::common::MarkedSource; 31 32 TEST(VerifierUnitTest, StringPrettyPrinter) { 33 StringPrettyPrinter c_string; 34 c_string.Print("c_string"); 35 EXPECT_EQ("c_string", c_string.str()); 36 StringPrettyPrinter std_string; 37 std_string.Print(std::string("std_string")); 38 EXPECT_EQ("std_string", std_string.str()); 39 StringPrettyPrinter zero_ptrvoid; 40 void* zero = nullptr; 41 zero_ptrvoid.Print(zero); 42 EXPECT_EQ("0", zero_ptrvoid.str()); 43 void* one = reinterpret_cast<void*>(1); 44 StringPrettyPrinter one_ptrvoid; 45 one_ptrvoid.Print(one); 46 // Some implementations might pad stringified void*s. 47 std::string one_str = one_ptrvoid.str(); 48 std::regex ptrish_regex("0x0*1"); 49 ASSERT_TRUE(std::regex_match(one_str, ptrish_regex)); 50 } 51 52 TEST(VerifierUnitTest, QuotingPrettyPrinter) { 53 StringPrettyPrinter c_string; 54 QuoteEscapingPrettyPrinter c_string_quoting(c_string); 55 c_string_quoting.Print(R"("hello")"); 56 EXPECT_EQ(R"(\"hello\")", c_string.str()); 57 StringPrettyPrinter std_string; 58 QuoteEscapingPrettyPrinter std_string_quoting(std_string); 59 std_string_quoting.Print(std::string(R"(<"' 60 )")); 61 EXPECT_EQ(R"(<\"\'\n)", std_string.str()); 62 StringPrettyPrinter zero_ptrvoid; 63 QuoteEscapingPrettyPrinter zero_ptrvoid_quoting(zero_ptrvoid); 64 void* zero = nullptr; 65 zero_ptrvoid_quoting.Print(zero); 66 EXPECT_EQ("0", zero_ptrvoid.str()); 67 } 68 69 TEST(VerifierUnitTest, HtmlPrettyPrinter) { 70 StringPrettyPrinter c_string; 71 HtmlEscapingPrettyPrinter c_string_html(c_string); 72 c_string_html.Print(R"("hello")"); 73 EXPECT_EQ(R"("hello")", c_string.str()); 74 StringPrettyPrinter std_string; 75 HtmlEscapingPrettyPrinter std_string_html(std_string); 76 std_string_html.Print(std::string(R"(x<>&"ml)")); 77 EXPECT_EQ(R"(x<>&"ml)", std_string.str()); 78 StringPrettyPrinter zero_ptrvoid; 79 HtmlEscapingPrettyPrinter zero_ptrvoid_html(zero_ptrvoid); 80 void* zero = nullptr; 81 zero_ptrvoid_html.Print(zero); 82 EXPECT_EQ("0", zero_ptrvoid.str()); 83 } 84 85 TEST(VerifierUnitTest, UnescapeStringLiterals) { 86 std::string tmp = "tmp"; 87 EXPECT_TRUE(AssertionParser::Unescape(R"("")", &tmp)); 88 EXPECT_EQ("", tmp); 89 EXPECT_FALSE(AssertionParser::Unescape("", &tmp)); 90 EXPECT_TRUE(AssertionParser::Unescape(R"("foo")", &tmp)); 91 EXPECT_EQ("foo", tmp); 92 EXPECT_TRUE(AssertionParser::Unescape(R"("\"foo\"")", &tmp)); 93 EXPECT_EQ("\"foo\"", tmp); 94 EXPECT_FALSE(AssertionParser::Unescape(R"("\foo")", &tmp)); 95 EXPECT_FALSE(AssertionParser::Unescape(R"("foo\")", &tmp)); 96 EXPECT_TRUE(AssertionParser::Unescape(R"("\\")", &tmp)); 97 EXPECT_EQ("\\", tmp); 98 } 99 100 bool CheckEVarInit(std::string_view s) { return s != "nil" && !s.empty(); } 101 102 enum class Solver { Old, New }; 103 104 class VerifierTest : public testing::TestWithParam<Solver> { 105 protected: 106 void SetUp() override { 107 v.UseFastSolver(GetParam() == Solver::Old ? false : true); 108 } 109 110 Verifier v; 111 }; 112 113 INSTANTIATE_TEST_SUITE_P(Solvers, VerifierTest, 114 testing::Values(Solver::Old, Solver::New), 115 [](const auto& p) { 116 return p.param == Solver::Old ? "old" : "new"; 117 }); 118 119 TEST_P(VerifierTest, TrivialHappyCase) { ASSERT_TRUE(v.VerifyAllGoals()); } 120 121 TEST(VerifierUnitTest, EmptyProtoIsNotWellFormed) { 122 Verifier v; 123 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 124 })")); 125 ASSERT_FALSE(v.VerifyAllGoals()); 126 } 127 128 TEST(VerifierUnitTest, EmptyVnameIsNotWellFormed) { 129 Verifier v; 130 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 131 source { } 132 fact_name: "testname" 133 fact_value: "testvalue" 134 })")); 135 ASSERT_FALSE(v.PrepareDatabase()); 136 ASSERT_FALSE(v.VerifyAllGoals()); 137 } 138 139 TEST_P(VerifierTest, NoRulesIsOk) { 140 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 141 source { root: "1" } 142 fact_name: "testname" 143 fact_value: "testvalue" 144 })")); 145 ASSERT_TRUE(v.PrepareDatabase()); 146 ASSERT_TRUE(v.VerifyAllGoals()); 147 } 148 149 TEST(VerifierUnitTest, DuplicateFactsNotWellFormed) { 150 Verifier v; 151 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 152 source { root: "1" } 153 fact_name: "testname" 154 fact_value: "testvalue" 155 } 156 entries { 157 source { root: "1" } 158 fact_name: "testname" 159 fact_value: "testvalue" 160 })")); 161 ASSERT_FALSE(v.PrepareDatabase()); 162 ASSERT_FALSE(v.VerifyAllGoals()); 163 } 164 165 TEST(VerifierUnitTest, DuplicateFactsNotWellFormedEvenIfYouSeparateThem) { 166 Verifier v; 167 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 168 source { root: "1" } 169 fact_name: "testname" 170 fact_value: "testvalue" 171 } 172 entries { 173 source { root: "2" } 174 fact_name: "testname" 175 fact_value: "testvalue" 176 } 177 entries { 178 source { root: "1" } 179 fact_name: "testname" 180 fact_value: "testvalue" 181 })")); 182 ASSERT_FALSE(v.PrepareDatabase()); 183 ASSERT_FALSE(v.VerifyAllGoals()); 184 } 185 186 TEST(VerifierUnitTest, DuplicateEdgesAreUseless) { 187 Verifier v; 188 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 189 source { root: "1" } 190 edge_kind: "somekind" 191 target { root: "2" } 192 fact_name: "/" 193 fact_value: "" 194 } 195 entries { 196 source { root: "1" } 197 edge_kind: "somekind" 198 target { root: "2" } 199 fact_name: "/" 200 fact_value: "" 201 })")); 202 ASSERT_FALSE(v.PrepareDatabase()); 203 ASSERT_FALSE(v.VerifyAllGoals()); 204 } 205 206 TEST_P(VerifierTest, EdgesCanSupplyMultipleOrdinals) { 207 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 208 source { root: "1" } 209 edge_kind: "somekind" 210 target { root: "2" } 211 fact_name: "/kythe/ordinal" 212 fact_value: "42" 213 } 214 entries { 215 source { root: "1" } 216 edge_kind: "somekind" 217 target { root: "2" } 218 fact_name: "/kythe/ordinal" 219 fact_value: "43" 220 })")); 221 ASSERT_TRUE(v.PrepareDatabase()); 222 ASSERT_TRUE(v.VerifyAllGoals()); 223 } 224 225 TEST_P(VerifierTest, EdgesCanSupplyMultipleDotOrdinals) { 226 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 227 source { root: "1" } 228 edge_kind: "somekind.42" 229 target { root: "2" } 230 fact_name: "/" 231 } 232 entries { 233 source { root: "1" } 234 edge_kind: "somekind.43" 235 target { root: "2" } 236 fact_name: "/" 237 })")); 238 ASSERT_TRUE(v.PrepareDatabase()); 239 ASSERT_TRUE(v.VerifyAllGoals()); 240 } 241 242 TEST(VerifierUnitTest, ConflictingFactsNotWellFormed) { 243 Verifier v; 244 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 245 source { root: "1" } 246 fact_name: "testname" 247 fact_value: "testvalue" 248 } 249 entries { 250 source { root: "1" } 251 fact_name: "testname" 252 fact_value: "testvalue2" 253 })")); 254 ASSERT_FALSE(v.PrepareDatabase()); 255 ASSERT_FALSE(v.VerifyAllGoals()); 256 } 257 258 TEST(VerifierUnitTest, OnlyTargetIsWrong) { 259 Verifier v; 260 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 261 edge_kind: "somekind" 262 target { root: "2" } 263 fact_name: "/kythe/ordinal" 264 fact_value: "42" 265 })")); 266 ASSERT_FALSE(v.PrepareDatabase()); 267 ASSERT_FALSE(v.VerifyAllGoals()); 268 } 269 270 TEST(VerifierUnitTest, OnlyTargetIsWrongDotOrdinal) { 271 Verifier v; 272 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 273 edge_kind: "somekind.42" 274 target { root: "2" } 275 fact_name: "/" 276 })")); 277 ASSERT_FALSE(v.PrepareDatabase()); 278 ASSERT_FALSE(v.VerifyAllGoals()); 279 } 280 281 TEST_P(VerifierTest, MissingAnchorTextFails) { 282 ASSERT_FALSE(v.LoadInlineProtoFile(R"(entries { 283 #- @text defines SomeNode 284 source { root: "1" } 285 fact_name: "testname" 286 fact_value: "testvalue" 287 })")); 288 } 289 290 TEST_P(VerifierTest, AmbiguousAnchorTextFails) { 291 ASSERT_FALSE(v.LoadInlineProtoFile(R"(entries { 292 #- @text defines SomeNode 293 # text text 294 source { root: "1" } 295 fact_name: "testname" 296 fact_value: "testvalue" 297 })")); 298 } 299 300 TEST_P(VerifierTest, GenerateAnchorEvarFailsOnEmptyDB) { 301 ASSERT_TRUE(v.LoadInlineProtoFile(R"( 302 #- @text defines SomeNode 303 # text 304 )")); 305 ASSERT_TRUE(v.PrepareDatabase()); 306 ASSERT_FALSE(v.VerifyAllGoals()); 307 } 308 309 TEST_P(VerifierTest, OffsetsVersusRuleBlocks) { 310 ASSERT_TRUE(v.LoadInlineProtoFile(R"( 311 #- @text defines SomeNode 312 #- @+2text defines SomeNode 313 #- @+1text defines SomeNode 314 # text 315 )")); 316 ASSERT_TRUE(v.PrepareDatabase()); 317 ASSERT_FALSE(v.VerifyAllGoals()); 318 } 319 320 TEST_P(VerifierTest, ZeroRelativeLineReferencesDontWork) { 321 ASSERT_FALSE(v.LoadInlineProtoFile(R"( 322 #- @+0text defines SomeNode 323 # text 324 )")); 325 } 326 327 TEST_P(VerifierTest, NoMatchingInsideGoalComments) { 328 ASSERT_FALSE(v.LoadInlineProtoFile(R"( 329 #- @+1text defines SomeNode 330 #- @text defines SomeNode 331 # text 332 )")); 333 } 334 335 TEST_P(VerifierTest, OutOfBoundsRelativeLineReferencesDontWork) { 336 ASSERT_FALSE(v.LoadInlineProtoFile(R"( 337 #- @+2text defines SomeNode 338 # text 339 )")); 340 } 341 342 TEST_P(VerifierTest, EndOfFileAbsoluteLineReferencesWork) { 343 ASSERT_TRUE(v.LoadInlineProtoFile(R"( 344 #- @:3text defines SomeNode 345 # text 346 )")); 347 } 348 349 TEST_P(VerifierTest, OutOfBoundsAbsoluteLineReferencesDontWork) { 350 Verifier v; 351 ASSERT_FALSE(v.LoadInlineProtoFile(R"( 352 #- @:4text defines SomeNode 353 # text 354 )")); 355 } 356 357 TEST_P(VerifierTest, ZeroAbsoluteLineReferencesDontWork) { 358 ASSERT_FALSE(v.LoadInlineProtoFile(R"( 359 #- @:0text defines SomeNode 360 # text 361 )")); 362 } 363 364 TEST_P(VerifierTest, SameAbsoluteLineReferencesDontWork) { 365 ASSERT_FALSE(v.LoadInlineProtoFile(R"( 366 #- @:1text defines SomeNode 367 # text 368 )")); 369 } 370 371 TEST_P(VerifierTest, HistoricalAbsoluteLineReferencesDontWork) { 372 ASSERT_FALSE(v.LoadInlineProtoFile(R"( 373 # 374 #- @:1text defines SomeNode 375 # text 376 )")); 377 } 378 379 TEST_P(VerifierTest, ParseLiteralString) { 380 ASSERT_TRUE(v.LoadInlineProtoFile(R"( 381 #- @"text" defines SomeNode 382 # text 383 )")); 384 ASSERT_TRUE(v.PrepareDatabase()); 385 ASSERT_FALSE(v.VerifyAllGoals()); 386 } 387 388 TEST_P(VerifierTest, ParseLiteralStringWithSpace) { 389 ASSERT_TRUE(v.LoadInlineProtoFile(R"( 390 #- @"text txet" defines SomeNode 391 # text txet 392 )")); 393 ASSERT_TRUE(v.PrepareDatabase()); 394 ASSERT_FALSE(v.VerifyAllGoals()); 395 } 396 397 TEST_P(VerifierTest, ParseLiteralStringWithEscape) { 398 ASSERT_TRUE(v.LoadInlineProtoFile(R"( 399 #- @"text \"txet\" ettx" defines SomeNode 400 # text "txet" ettx 401 )")); 402 ASSERT_TRUE(v.PrepareDatabase()); 403 ASSERT_FALSE(v.VerifyAllGoals()); 404 } 405 406 TEST_P(VerifierTest, GenerateStartOffsetEVar) { 407 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 408 #- ANode.loc/start @^text 409 ##text (line 3 column 2 offset 38-42) 410 source { root:"1" } 411 fact_name: "/kythe/node/kind" 412 fact_value: "anchor" 413 } 414 entries { 415 source { root:"1" } 416 fact_name: "/kythe/loc/start" 417 fact_value: "38" 418 } 419 entries { 420 source { root:"1" } 421 fact_name: "/kythe/loc/end" 422 fact_value: "42" 423 } 424 entries { 425 source { root:"1" } 426 edge_kind: "/kythe/edge/defines" 427 target { root:"2" } 428 fact_name: "/" 429 fact_value: "" 430 })")); 431 ASSERT_TRUE(v.PrepareDatabase()); 432 ASSERT_TRUE(v.VerifyAllGoals()); 433 } 434 435 TEST_P(VerifierTest, GenerateStartOffsetEVarRelativeLine) { 436 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 437 #- ANode.loc/start @^+22text 438 source { root:"1" } 439 fact_name: "/kythe/node/kind" 440 fact_value: "anchor" 441 } 442 entries { 443 source { root:"1" } 444 fact_name: "/kythe/loc/start" 445 fact_value: "387" 446 } 447 entries { 448 source { root:"1" } 449 fact_name: "/kythe/loc/end" 450 fact_value: "391" 451 } 452 entries { 453 source { root:"1" } 454 edge_kind: "/kythe/edge/defines" 455 target { root:"2" } 456 fact_name: "/" 457 fact_value: "" 458 } 459 ##text (line 24 column 2 offset 387-391))")); 460 ASSERT_TRUE(v.PrepareDatabase()); 461 ASSERT_TRUE(v.VerifyAllGoals()); 462 } 463 464 TEST_P(VerifierTest, GenerateEndOffsetEVarAbsoluteLine) { 465 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 466 #- ANode.loc/end @$:24text 467 source { root:"1" } 468 fact_name: "/kythe/node/kind" 469 fact_value: "anchor" 470 } 471 entries { 472 source { root:"1" } 473 fact_name: "/kythe/loc/start" 474 fact_value: "387" 475 } 476 entries { 477 source { root:"1" } 478 fact_name: "/kythe/loc/end" 479 fact_value: "391" 480 } 481 entries { 482 source { root:"1" } 483 edge_kind: "/kythe/edge/defines" 484 target { root:"2" } 485 fact_name: "/" 486 fact_value: "" 487 } 488 ##text (line 24 column 2 offset 387-391))")); 489 ASSERT_TRUE(v.PrepareDatabase()); 490 ASSERT_TRUE(v.VerifyAllGoals()); 491 } 492 493 TEST_P(VerifierTest, GenerateEndOffsetEVar) { 494 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 495 #- ANode.loc/end @$text 496 ##text (line 3 column 2 offset 38-42) 497 source { root:"1" } 498 fact_name: "/kythe/node/kind" 499 fact_value: "anchor" 500 } 501 entries { 502 source { root:"1" } 503 fact_name: "/kythe/loc/start" 504 fact_value: "38" 505 } 506 entries { 507 source { root:"1" } 508 fact_name: "/kythe/loc/end" 509 fact_value: "42" 510 } 511 entries { 512 source { root:"1" } 513 edge_kind: "/kythe/edge/defines" 514 target { root:"2" } 515 fact_name: "/" 516 fact_value: "" 517 })")); 518 ASSERT_TRUE(v.PrepareDatabase()); 519 ASSERT_TRUE(v.VerifyAllGoals()); 520 } 521 522 TEST_P(VerifierTest, AnchorKind) { 523 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 524 #- @text.node/kind anchor 525 ##text (line 3 column 2 offset 38-42) 526 source { root:"1" } 527 fact_name: "/kythe/node/kind" 528 fact_value: "anchor" 529 } 530 entries { 531 source { root:"1" } 532 fact_name: "/kythe/loc/start" 533 fact_value: "38" 534 } 535 entries { 536 source { root:"1" } 537 fact_name: "/kythe/loc/end" 538 fact_value: "42" 539 } 540 )", 541 "", "1")); 542 ASSERT_TRUE(v.PrepareDatabase()); 543 ASSERT_TRUE(v.VerifyAllGoals()); 544 } 545 546 TEST_P(VerifierTest, GenerateAnchorEvar) { 547 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 548 #- @text defines SomeNode 549 ##text (line 3 column 2 offset 38-42) 550 source { root:"1" } 551 fact_name: "/kythe/node/kind" 552 fact_value: "anchor" 553 } 554 entries { 555 source { root:"1" } 556 fact_name: "/kythe/loc/start" 557 fact_value: "38" 558 } 559 entries { 560 source { root:"1" } 561 fact_name: "/kythe/loc/end" 562 fact_value: "42" 563 } 564 entries { 565 source { root:"1" } 566 edge_kind: "/kythe/edge/defines" 567 target { root:"2" } 568 fact_name: "/" 569 fact_value: "" 570 })", 571 "", "1")); 572 ASSERT_TRUE(v.PrepareDatabase()); 573 ASSERT_TRUE(v.VerifyAllGoals()); 574 } 575 576 constexpr char kMatchAnchorSubgraph[] = R"(entries { 577 source { root:"1" } 578 fact_name: "/kythe/node/kind" 579 fact_value: "anchor" 580 } 581 entries { 582 source { root:"1" } 583 fact_name: "/kythe/loc/start" 584 fact_value: "40" 585 } 586 entries { 587 source { root:"1" } 588 fact_name: "/kythe/loc/end" 589 fact_value: "44" 590 } 591 entries { 592 source { root:"3" } 593 fact_name: "/kythe/node/kind" 594 fact_value: "anchor" 595 } 596 entries { 597 source { root:"3" } 598 fact_name: "/kythe/loc/start" 599 fact_value: "45" 600 } 601 entries { 602 source { root:"3" } 603 fact_name: "/kythe/loc/end" 604 fact_value: "49" 605 } 606 entries { 607 source { root:"4" } 608 fact_name: "/kythe/node/kind" 609 fact_value: "anchor" 610 } 611 entries { 612 source { root:"4" } 613 fact_name: "/kythe/loc/start" 614 fact_value: "50" 615 } 616 entries { 617 source { root:"4" } 618 fact_name: "/kythe/loc/end" 619 fact_value: "54" 620 })"; 621 622 TEST_P(VerifierTest, GenerateAnchorEvarMatchNumber0) { 623 ASSERT_TRUE(v.LoadInlineProtoFile(std::string(R"(entries { 624 #- @#0text defines SomeNode 625 ##text text text(40-44, 45-49, 50-54) 626 627 source { root:"1" } 628 edge_kind: "/kythe/edge/defines" 629 target { root:"2" } 630 fact_name: "/" 631 fact_value: "" 632 })") + kMatchAnchorSubgraph, 633 "", "1")); 634 ASSERT_TRUE(v.PrepareDatabase()); 635 ASSERT_TRUE(v.VerifyAllGoals()); 636 } 637 638 TEST_P(VerifierTest, GenerateAnchorEvarMatchNumber1) { 639 ASSERT_TRUE(v.LoadInlineProtoFile(std::string(R"(entries { 640 #- @#1text defines SomeNode 641 ##text text text(40-44, 45-49, 50-54) 642 643 source { root:"3" } 644 edge_kind: "/kythe/edge/defines" 645 target { root:"2" } 646 fact_name: "/" 647 fact_value: "" 648 })") + kMatchAnchorSubgraph, 649 "", "3")); 650 ASSERT_TRUE(v.PrepareDatabase()); 651 ASSERT_TRUE(v.VerifyAllGoals()); 652 } 653 654 TEST_P(VerifierTest, GenerateAnchorEvarMatchNumber2) { 655 ASSERT_TRUE(v.LoadInlineProtoFile(std::string(R"(entries { 656 #- @#2text defines SomeNode 657 ##text text text(40-44, 45-49, 50-54) 658 659 source { root:"4" } 660 edge_kind: "/kythe/edge/defines" 661 target { root:"2" } 662 fact_name: "/" 663 fact_value: "" 664 })") + kMatchAnchorSubgraph, 665 "", "4")); 666 ASSERT_TRUE(v.PrepareDatabase()); 667 ASSERT_TRUE(v.VerifyAllGoals()); 668 } 669 670 TEST_P(VerifierTest, GenerateAnchorEvarMatchNumber3) { 671 ASSERT_FALSE(v.LoadInlineProtoFile(R"(entries { 672 #- @#3text defines SomeNode 673 ##text text text(40-44, 45-49, 50-54) 674 })")); 675 } 676 677 TEST_P(VerifierTest, GenerateAnchorEvarMatchNumberNegative1) { 678 ASSERT_FALSE(v.LoadInlineProtoFile(R"(entries { 679 #- @#-1text defines SomeNode 680 ##text text text(40-44, 45-49, 50-54) 681 })")); 682 } 683 684 TEST_P(VerifierTest, GenerateAnchorEvarAbsoluteLine) { 685 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 686 #- @:24text defines SomeNode 687 source { root:"1" } 688 fact_name: "/kythe/node/kind" 689 fact_value: "anchor" 690 } 691 entries { 692 source { root:"1" } 693 fact_name: "/kythe/loc/start" 694 fact_value: "387" 695 } 696 entries { 697 source { root:"1" } 698 fact_name: "/kythe/loc/end" 699 fact_value: "391" 700 } 701 entries { 702 source { root:"1" } 703 edge_kind: "/kythe/edge/defines" 704 target { root:"2" } 705 fact_name: "/" 706 fact_value: "" 707 } 708 ##text (line 24 column 2 offset 387-391))", 709 "", "1")); 710 ASSERT_TRUE(v.PrepareDatabase()); 711 ASSERT_TRUE(v.VerifyAllGoals()); 712 } 713 714 TEST_P(VerifierTest, GenerateAnchorEvarRelativeLine) { 715 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 716 #- @+22text defines SomeNode 717 source { root:"1" } 718 fact_name: "/kythe/node/kind" 719 fact_value: "anchor" 720 } 721 entries { 722 source { root:"1" } 723 fact_name: "/kythe/loc/start" 724 fact_value: "387" 725 } 726 entries { 727 source { root:"1" } 728 fact_name: "/kythe/loc/end" 729 fact_value: "391" 730 } 731 entries { 732 source { root:"1" } 733 edge_kind: "/kythe/edge/defines" 734 target { root:"2" } 735 fact_name: "/" 736 fact_value: "" 737 } 738 ##text (line 24 column 2 offset 387-391))", 739 "", "1")); 740 ASSERT_TRUE(v.PrepareDatabase()); 741 ASSERT_TRUE(v.VerifyAllGoals()); 742 } 743 744 TEST_P(VerifierTest, GenerateAnchorEvarAtEndOfFile) { 745 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 746 source { root:"1" } 747 fact_name: "/kythe/node/kind" 748 fact_value: "anchor" 749 } 750 entries { 751 source { root:"1" } 752 fact_name: "/kythe/loc/start" 753 fact_value: "384" 754 } 755 entries { 756 source { root:"1" } 757 fact_name: "/kythe/loc/end" 758 fact_value: "388" 759 } 760 entries { 761 source { root:"1" } 762 edge_kind: "/kythe/edge/defines" 763 target { root:"2" } 764 fact_name: "/" 765 fact_value: "" 766 } 767 #- @text defines SomeNode 768 ##text (line 22 column 2 offset 384-388))", 769 "", "1")); 770 ASSERT_TRUE(v.PrepareDatabase()); 771 ASSERT_TRUE(v.VerifyAllGoals()); 772 } 773 774 TEST_P(VerifierTest, GenerateAnchorEvarAtEndOfFileWithSpaces) { 775 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 776 source { root:"1" } 777 fact_name: "/kythe/node/kind" 778 fact_value: "anchor" 779 } 780 entries { 781 source { root:"1" } 782 fact_name: "/kythe/loc/start" 783 fact_value: "386" 784 } 785 entries { 786 source { root:"1" } 787 fact_name: "/kythe/loc/end" 788 fact_value: "390" 789 } 790 entries { 791 source { root:"1" } 792 edge_kind: "/kythe/edge/defines" 793 target { root:"2" } 794 fact_name: "/" 795 fact_value: "" 796 } 797 #- @text defines SomeNode 798 ##text (line 22 column 2 offset 386-390))", 799 "", "1")); 800 ASSERT_TRUE(v.PrepareDatabase()); 801 ASSERT_TRUE(v.VerifyAllGoals()); 802 } 803 804 TEST_P(VerifierTest, GenerateAnchorEvarAtEndOfFileWithTrailingRule) { 805 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 806 source { root:"1" } 807 fact_name: "/kythe/node/kind" 808 fact_value: "anchor" 809 } 810 entries { 811 source { root:"1" } 812 fact_name: "/kythe/loc/start" 813 fact_value: "384" 814 } 815 entries { 816 source { root:"1" } 817 fact_name: "/kythe/loc/end" 818 fact_value: "388" 819 } 820 entries { 821 source { root:"1" } 822 edge_kind: "/kythe/edge/defines" 823 target { root:"2" } 824 fact_name: "/" 825 fact_value: "" 826 } 827 #- @text defines SomeNode 828 ##text (line 22 column 2 offset 384-388)) 829 #- SomeAnchor defines SomeNode)", 830 "", "1")); 831 ASSERT_TRUE(v.PrepareDatabase()); 832 ASSERT_TRUE(v.VerifyAllGoals()); 833 } 834 835 TEST_P(VerifierTest, GenerateAnchorEvarAcrossMultipleGoalLines) { 836 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 837 #- @text defines 838 #- 839 #- SomeNode 840 ##text (line 5 column 2 offset 46-50) 841 source { root:"1" } 842 fact_name: "/kythe/node/kind" 843 fact_value: "anchor" 844 } 845 entries { 846 source { root:"1" } 847 fact_name: "/kythe/loc/start" 848 fact_value: "46" 849 } 850 entries { 851 source { root:"1" } 852 fact_name: "/kythe/loc/end" 853 fact_value: "50" 854 } 855 entries { 856 source { root:"1" } 857 edge_kind: "/kythe/edge/defines" 858 target { root:"2" } 859 fact_name: "/" 860 fact_value: "" 861 })", 862 "", "1")); 863 ASSERT_TRUE(v.PrepareDatabase()); 864 ASSERT_TRUE(v.VerifyAllGoals()); 865 } 866 867 TEST_P(VerifierTest, GenerateAnchorEvarAcrossMultipleGoalLinesWithSpaces) { 868 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 869 #- @text defines 870 #- 871 #- SomeNode 872 ##text (line 5 column 4 offset 51-55) 873 source { root:"1" } 874 fact_name: "/kythe/node/kind" 875 fact_value: "anchor" 876 } 877 entries { 878 source { root:"1" } 879 fact_name: "/kythe/loc/start" 880 fact_value: "51" 881 } 882 entries { 883 source { root:"1" } 884 fact_name: "/kythe/loc/end" 885 fact_value: "55" 886 } 887 entries { 888 source { root:"1" } 889 edge_kind: "/kythe/edge/defines" 890 target { root:"2" } 891 fact_name: "/" 892 fact_value: "" 893 })", 894 "", "1")); 895 ASSERT_TRUE(v.PrepareDatabase()); 896 ASSERT_TRUE(v.VerifyAllGoals()); 897 } 898 899 TEST_P(VerifierTest, GenerateAnchorEvarWithBlankLines) { 900 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 901 source { root:"1" } 902 fact_name: "/kythe/node/kind" 903 fact_value: "anchor" 904 } 905 entries { 906 source { root:"1" } 907 fact_name: "/kythe/loc/start" 908 fact_value: "384" 909 } 910 entries { 911 source { root:"1" } 912 fact_name: "/kythe/loc/end" 913 fact_value: "388" 914 } 915 entries { 916 source { root:"1" } 917 edge_kind: "/kythe/edge/defines" 918 target { root:"2" } 919 fact_name: "/" 920 fact_value: "" 921 } 922 #- @texx defines SomeNode 923 ##texx (line 22 column 2 offset 384-388)) 924 925 #- SomeAnchor defines SomeNode)", 926 "", "1")); 927 ASSERT_TRUE(v.PrepareDatabase()); 928 ASSERT_TRUE(v.VerifyAllGoals()); 929 } 930 931 TEST_P(VerifierTest, GenerateAnchorEvarWithWhitespaceLines) { 932 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 933 source { root:"1" } 934 fact_name: "/kythe/node/kind" 935 fact_value: "anchor" 936 } 937 entries { 938 source { root:"1" } 939 fact_name: "/kythe/loc/start" 940 fact_value: "384" 941 } 942 entries { 943 source { root:"1" } 944 fact_name: "/kythe/loc/end" 945 fact_value: "388" 946 } 947 entries { 948 source { root:"1" } 949 edge_kind: "/kythe/edge/defines" 950 target { root:"2" } 951 fact_name: "/" 952 fact_value: "" 953 } 954 #- @texx defines SomeNode 955 ##texx (line 22 column 2 offset 384-388)) 956 957 #- SomeAnchor defines SomeNode)", 958 "", "1")); 959 ASSERT_TRUE(v.PrepareDatabase()); 960 ASSERT_TRUE(v.VerifyAllGoals()); 961 } 962 963 TEST(VerifierUnitTest, GenerateTwoSeparatedAnchorEvars) { 964 Verifier v; 965 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 966 #- @text defines SomeNode 967 ##text (line 3 column 2 offset 38-42) 968 #- @more defines OtherNode 969 #more (line 5 column 1 offset 102-106 970 source { root:"1" } 971 fact_name: "/kythe/node/kind" 972 fact_value: "anchor" 973 } 974 entries { 975 source { root:"1" } 976 fact_name: "/kythe/loc/start" 977 fact_value: "38" 978 } 979 entries { 980 source { root:"1" } 981 fact_name: "/kythe/loc/end" 982 fact_value: "42" 983 } 984 entries { 985 source { root:"1" } 986 edge_kind: "/kythe/edge/defines" 987 target { root:"2" } 988 fact_name: "/" 989 fact_value: "" 990 } 991 entries { 992 source { root:"3" } 993 fact_name: "/kythe/node/kind" 994 fact_value: "anchor" 995 } 996 entries { 997 source { root:"3" } 998 fact_name: "/kythe/loc/start" 999 fact_value: "102" 1000 } 1001 entries { 1002 source { root:"3" } 1003 fact_name: "/kythe/loc/end" 1004 fact_value: "106" 1005 } 1006 entries { 1007 source { root:"3" } 1008 edge_kind: "/kythe/edge/defines" 1009 target { root:"4" } 1010 fact_name: "/" 1011 fact_value: "" 1012 } 1013 )")); 1014 ASSERT_TRUE(v.PrepareDatabase()); 1015 ASSERT_TRUE(v.VerifyAllGoals()); 1016 } 1017 1018 TEST(VerifierUnitTest, GenerateTwoSeparatedAnchorEvarsWithSpaces) { 1019 Verifier v; 1020 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1021 #- @" text" defines SomeNode 1022 ## text (line 3 column 3 offset 42-47) 1023 #- @" more " defines OtherNode 1024 # more (line 5 column 1 offset 111-117 1025 source { root:"1" } 1026 fact_name: "/kythe/node/kind" 1027 fact_value: "anchor" 1028 } 1029 entries { 1030 source { root:"1" } 1031 fact_name: "/kythe/loc/start" 1032 fact_value: "42" 1033 } 1034 entries { 1035 source { root:"1" } 1036 fact_name: "/kythe/loc/end" 1037 fact_value: "47" 1038 } 1039 entries { 1040 source { root:"1" } 1041 edge_kind: "/kythe/edge/defines" 1042 target { root:"2" } 1043 fact_name: "/" 1044 fact_value: "" 1045 } 1046 entries { 1047 source { root:"3" } 1048 fact_name: "/kythe/node/kind" 1049 fact_value: "anchor" 1050 } 1051 entries { 1052 source { root:"3" } 1053 fact_name: "/kythe/loc/start" 1054 fact_value: "111" 1055 } 1056 entries { 1057 source { root:"3" } 1058 fact_name: "/kythe/loc/end" 1059 fact_value: "117" 1060 } 1061 entries { 1062 source { root:"3" } 1063 edge_kind: "/kythe/edge/defines" 1064 target { root:"4" } 1065 fact_name: "/" 1066 fact_value: "" 1067 } 1068 )")); 1069 ASSERT_TRUE(v.PrepareDatabase()); 1070 ASSERT_TRUE(v.VerifyAllGoals()); 1071 } 1072 1073 TEST(VerifierUnitTest, GenerateTwoAnchorEvars) { 1074 Verifier v; 1075 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1076 #- @more defines SomeNode 1077 #- @text defines OtherNode 1078 ##text (line 4 column 2 offset 65-69) more (line 4 column 38 offset 101-105) 1079 source { root:"1" } 1080 fact_name: "/kythe/node/kind" 1081 fact_value: "anchor" 1082 } 1083 entries { 1084 source { root:"1" } 1085 fact_name: "/kythe/loc/start" 1086 fact_value: "65" 1087 } 1088 entries { 1089 source { root:"1" } 1090 fact_name: "/kythe/loc/end" 1091 fact_value: "69" 1092 } 1093 entries { 1094 source { root:"1" } 1095 edge_kind: "/kythe/edge/defines" 1096 target { root:"2" } 1097 fact_name: "/" 1098 fact_value: "" 1099 } 1100 entries { 1101 source { root:"3" } 1102 fact_name: "/kythe/node/kind" 1103 fact_value: "anchor" 1104 } 1105 entries { 1106 source { root:"3" } 1107 fact_name: "/kythe/loc/start" 1108 fact_value: "101" 1109 } 1110 entries { 1111 source { root:"3" } 1112 fact_name: "/kythe/loc/end" 1113 fact_value: "105" 1114 } 1115 entries { 1116 source { root:"3" } 1117 edge_kind: "/kythe/edge/defines" 1118 target { root:"4" } 1119 fact_name: "/" 1120 fact_value: "" 1121 } 1122 )")); 1123 ASSERT_TRUE(v.PrepareDatabase()); 1124 ASSERT_TRUE(v.VerifyAllGoals()); 1125 } 1126 1127 TEST_P(VerifierTest, ContentFactPasses) { 1128 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1129 #- SomeNode.content 42 1130 source { root:"1" } 1131 fact_name: "/kythe/content" 1132 fact_value: "42" 1133 })")); 1134 ASSERT_TRUE(v.PrepareDatabase()); 1135 ASSERT_TRUE(v.VerifyAllGoals()); 1136 } 1137 1138 TEST_P(VerifierTest, BCPLCommentBlocksWrongRule) { 1139 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1140 #- //SomeNode.content 43 1141 #- SomeNode.content 42 1142 source { root:"1" } 1143 fact_name: "/kythe/content" 1144 fact_value: "42" 1145 })")); 1146 ASSERT_TRUE(v.PrepareDatabase()); 1147 ASSERT_TRUE(v.VerifyAllGoals()); 1148 } 1149 1150 TEST_P(VerifierTest, BCPLCommentInStringLiteral) { 1151 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1152 #- SomeNode.content "4//2" 1153 source { root:"1" } 1154 fact_name: "/kythe/content" 1155 fact_value: "4//2" 1156 })")); 1157 ASSERT_TRUE(v.PrepareDatabase()); 1158 ASSERT_TRUE(v.VerifyAllGoals()); 1159 } 1160 1161 TEST_P(VerifierTest, BCPLCommentTrailingValue) { 1162 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1163 #- SomeNode.content 42//x 1164 source { root:"1" } 1165 fact_name: "/kythe/content" 1166 fact_value: "42" 1167 })")); 1168 ASSERT_TRUE(v.PrepareDatabase()); 1169 ASSERT_TRUE(v.VerifyAllGoals()); 1170 } 1171 1172 TEST_P(VerifierTest, EmptyBCPLCommentTrailingValue) { 1173 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1174 #- SomeNode.content 42// 1175 source { root:"1" } 1176 fact_name: "/kythe/content" 1177 fact_value: "42" 1178 })")); 1179 ASSERT_TRUE(v.PrepareDatabase()); 1180 ASSERT_TRUE(v.VerifyAllGoals()); 1181 } 1182 1183 TEST_P(VerifierTest, EmptyBCPLComment) { 1184 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1185 #-// 1186 #- SomeNode.content 43 1187 source { root:"1" } 1188 fact_name: "/kythe/content" 1189 fact_value: "42" 1190 })")); 1191 ASSERT_TRUE(v.PrepareDatabase()); 1192 ASSERT_FALSE(v.VerifyAllGoals()); 1193 } 1194 1195 TEST_P(VerifierTest, DontCareInNegativeIsGroundedPass) { 1196 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1197 #- !{X typed vname(_,"","3","","")} 1198 source { root:"1" } 1199 edge_kind: "/kythe/edge/typed" 1200 target { root:"2" } 1201 fact_name: "/" 1202 fact_value: "" 1203 })")); 1204 ASSERT_TRUE(v.PrepareDatabase()); 1205 ASSERT_TRUE(v.VerifyAllGoals()); 1206 } 1207 1208 TEST_P(VerifierTest, FastSolverCantInspectNegatedEvar) { 1209 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1210 #- !{_? nottyped SomeType} 1211 source { root:"1" } 1212 edge_kind: "/kythe/edge/typed" 1213 target { root:"2" } 1214 fact_name: "/" 1215 fact_value: "" 1216 })")); 1217 ASSERT_TRUE(v.PrepareDatabase()); 1218 if (GetParam() == Solver::New) { 1219 ASSERT_FALSE(v.VerifyAllGoals()); 1220 } else { 1221 ASSERT_TRUE(v.VerifyAllGoals()); 1222 } 1223 } 1224 1225 TEST_P(VerifierTest, FastSolverIgnoresInspectImplicitNegatedDontCareEvar) { 1226 v.SaveEVarAssignments(); 1227 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1228 #- !{Var=_ nottyped SomeType} 1229 source { root:"1" } 1230 edge_kind: "/kythe/edge/typed" 1231 target { root:"2" } 1232 fact_name: "/" 1233 fact_value: "" 1234 })")); 1235 ASSERT_TRUE(v.PrepareDatabase()); 1236 // SaveEVarAssignments marks Implicit and SomeType as implicitly inspected 1237 // EVars. These should not cause verification to fail even though they appear 1238 // in a negated context. 1239 ASSERT_TRUE(v.VerifyAllGoals()); 1240 } 1241 1242 TEST_P(VerifierTest, FastSolverIgnoresInspectImplicitNegatedEvar) { 1243 v.SaveEVarAssignments(); 1244 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1245 #- !{Implicit nottyped SomeType} 1246 source { root:"1" } 1247 edge_kind: "/kythe/edge/typed" 1248 target { root:"2" } 1249 fact_name: "/" 1250 fact_value: "" 1251 })")); 1252 ASSERT_TRUE(v.PrepareDatabase()); 1253 // SaveEVarAssignments marks Implicit and SomeType as implicitly inspected 1254 // EVars. These should not cause verification to fail even though they appear 1255 // in a negated context. 1256 ASSERT_TRUE(v.VerifyAllGoals()); 1257 } 1258 1259 TEST_P(VerifierTest, DontCareInNegativeIsGroundedFail) { 1260 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1261 #- !{X typed vname(_,"","2","","")} 1262 source { root:"1" } 1263 edge_kind: "/kythe/edge/typed" 1264 target { root:"2" } 1265 fact_name: "/" 1266 fact_value: "" 1267 })")); 1268 ASSERT_TRUE(v.PrepareDatabase()); 1269 ASSERT_FALSE(v.VerifyAllGoals()); 1270 } 1271 1272 TEST(VerifierUnitTest, EVarsUnsetAfterNegatedBlock) { 1273 Verifier v; 1274 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1275 #- !{vname(_,_,Root?="3",_,_) defines SomeNode} 1276 source { root:"1" } 1277 edge_kind: "/kythe/edge/defines" 1278 target { root:"2" } 1279 fact_name: "/" 1280 fact_value: "" 1281 })")); 1282 size_t call_count = 0; 1283 bool evar_unset = false; 1284 ASSERT_TRUE(v.PrepareDatabase()); 1285 ASSERT_TRUE(v.VerifyAllGoals( 1286 [&call_count, &evar_unset](Verifier* cxt, const Inspection& inspection, 1287 std::string_view) { 1288 ++call_count; 1289 if (inspection.label == "Root" && !inspection.evar->current()) { 1290 evar_unset = true; 1291 } 1292 return true; 1293 })); 1294 EXPECT_EQ(1, call_count); 1295 EXPECT_TRUE(evar_unset); 1296 } 1297 1298 TEST(VerifierUnitTest, NegatedBlocksDontLeak) { 1299 Verifier v; 1300 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1301 #- !{vname(_,_,Root="3",_,_) defines SomeNode} 1302 #- !{vname(_,_,Root?,_,_) notanedge OtherNode} 1303 source { root:"1" } 1304 edge_kind: "/kythe/edge/defines" 1305 target { root:"2" } 1306 fact_name: "/" 1307 fact_value: "" 1308 })")); 1309 size_t call_count = 0; 1310 bool evar_unset = false; 1311 ASSERT_TRUE(v.PrepareDatabase()); 1312 ASSERT_TRUE(v.VerifyAllGoals( 1313 [&call_count, &evar_unset](Verifier* cxt, const Inspection& inspection, 1314 std::string_view) { 1315 ++call_count; 1316 if (inspection.label == "Root" && !inspection.evar->current()) { 1317 evar_unset = true; 1318 } 1319 return true; 1320 })); 1321 EXPECT_EQ(1, call_count); 1322 EXPECT_TRUE(evar_unset); 1323 } 1324 1325 TEST(VerifierUnitTest, UngroupedEVarsAvailableInGroupedContexts) { 1326 Verifier v; 1327 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1328 #- vname(_,_,Root="3",_,_) defines SomeNode 1329 #- !{vname(_,_,Root?,_,_) defines SomeNode} 1330 source { root:"1" } 1331 edge_kind: "/kythe/edge/defines" 1332 target { root:"2" } 1333 fact_name: "/" 1334 fact_value: "" 1335 } 1336 entries { 1337 source { root:"3" } 1338 edge_kind: "/kythe/edge/defines" 1339 target { root:"4" } 1340 fact_name: "/" 1341 fact_value: "" 1342 })")); 1343 size_t call_count = 0; 1344 bool evar_set = false; 1345 ASSERT_TRUE(v.PrepareDatabase()); 1346 ASSERT_FALSE(v.VerifyAllGoals([&call_count, &evar_set]( 1347 Verifier* cxt, const Inspection& inspection, 1348 std::string_view) { 1349 ++call_count; 1350 if (inspection.label == "Root" && inspection.evar->current()) { 1351 if (Identifier* identifier = inspection.evar->current()->AsIdentifier()) { 1352 if (cxt->symbol_table()->text(identifier->symbol()) == "3") { 1353 evar_set = true; 1354 } 1355 } 1356 } 1357 return true; 1358 })); 1359 EXPECT_EQ(1, call_count); 1360 EXPECT_TRUE(evar_set); 1361 } 1362 1363 TEST(VerifierUnitTest, UngroupedEVarsAvailableInGroupedContextsReordered) { 1364 Verifier v; 1365 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1366 #- !{vname(_,_,Root?,_,_) defines SomeNode} 1367 #- vname(_,_,Root="3",_,_) defines SomeNode 1368 source { root:"1" } 1369 edge_kind: "/kythe/edge/defines" 1370 target { root:"2" } 1371 fact_name: "/" 1372 fact_value: "" 1373 } 1374 entries { 1375 source { root:"3" } 1376 edge_kind: "/kythe/edge/defines" 1377 target { root:"4" } 1378 fact_name: "/" 1379 fact_value: "" 1380 })")); 1381 size_t call_count = 0; 1382 bool evar_set = false; 1383 ASSERT_TRUE(v.PrepareDatabase()); 1384 ASSERT_FALSE(v.VerifyAllGoals([&call_count, &evar_set]( 1385 Verifier* cxt, const Inspection& inspection, 1386 std::string_view) { 1387 ++call_count; 1388 if (inspection.label == "Root" && inspection.evar->current()) { 1389 if (Identifier* identifier = inspection.evar->current()->AsIdentifier()) { 1390 if (cxt->symbol_table()->text(identifier->symbol()) == "3") { 1391 evar_set = true; 1392 } 1393 } 1394 } 1395 return true; 1396 })); 1397 EXPECT_EQ(1, call_count); 1398 EXPECT_TRUE(evar_set); 1399 } 1400 1401 TEST(VerifierUnitTest, EVarsReportedAfterFailedNegatedBlock) { 1402 Verifier v; 1403 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1404 #- !{vname(_,_,Root?="1",_,_) defines SomeNode} 1405 source { root:"1" } 1406 edge_kind: "/kythe/edge/defines" 1407 target { root:"2" } 1408 fact_name: "/" 1409 fact_value: "" 1410 })")); 1411 size_t call_count = 0; 1412 bool evar_set = false; 1413 ASSERT_TRUE(v.PrepareDatabase()); 1414 ASSERT_FALSE(v.VerifyAllGoals([&call_count, &evar_set]( 1415 Verifier* cxt, const Inspection& inspection, 1416 std::string_view) { 1417 ++call_count; 1418 if (inspection.label == "Root" && inspection.evar->current()) { 1419 if (Identifier* identifier = inspection.evar->current()->AsIdentifier()) { 1420 if (cxt->symbol_table()->text(identifier->symbol()) == "1") { 1421 evar_set = true; 1422 } 1423 } 1424 } 1425 return true; 1426 })); 1427 EXPECT_EQ(1, call_count); 1428 EXPECT_TRUE(evar_set); 1429 } 1430 1431 TEST_P(VerifierTest, GroupFactFails) { 1432 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1433 #- { SomeNode.content 43 } 1434 source { root:"1" } 1435 fact_name: "/kythe/content" 1436 fact_value: "42" 1437 })")); 1438 ASSERT_TRUE(v.PrepareDatabase()); 1439 ASSERT_FALSE(v.VerifyAllGoals()); 1440 } 1441 1442 // Slightly brittle in that it depends on the order we try facts. 1443 TEST_P(VerifierTest, FailWithCutInGroups) { 1444 if (GetParam() == Solver::New) { 1445 // The new solver will pick the second entry. 1446 GTEST_SKIP(); 1447 } 1448 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1449 #- { SomeNode.content SomeValue } 1450 #- { SomeNode.content 43 } 1451 source { root:"1" } 1452 fact_name: "/kythe/content" 1453 fact_value: "42" 1454 } 1455 entries { 1456 source { root:"2" } 1457 fact_name: "/kythe/content" 1458 fact_value: "43" 1459 })")); 1460 ASSERT_TRUE(v.PrepareDatabase()); 1461 ASSERT_FALSE(v.VerifyAllGoals()); 1462 } 1463 1464 // Slightly brittle in that it depends on the order we try facts. 1465 TEST_P(VerifierTest, FailWithCut) { 1466 if (GetParam() == Solver::New) { 1467 // The new solver will pick the second entry. 1468 GTEST_SKIP(); 1469 } 1470 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1471 #- SomeNode.content SomeValue 1472 #- { SomeNode.content 43 } 1473 source { root:"1" } 1474 fact_name: "/kythe/content" 1475 fact_value: "42" 1476 } 1477 entries { 1478 source { root:"2" } 1479 fact_name: "/kythe/content" 1480 fact_value: "43" 1481 })")); 1482 ASSERT_TRUE(v.PrepareDatabase()); 1483 ASSERT_FALSE(v.VerifyAllGoals()); 1484 } 1485 1486 TEST_P(VerifierTest, PassWithoutCut) { 1487 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1488 #- SomeNode.content SomeValue 1489 #- SomeNode.content 43 1490 source { root:"1" } 1491 fact_name: "/kythe/content" 1492 fact_value: "42" 1493 } 1494 entries { 1495 source { root:"2" } 1496 fact_name: "/kythe/content" 1497 fact_value: "43" 1498 })")); 1499 ASSERT_TRUE(v.PrepareDatabase()); 1500 ASSERT_TRUE(v.VerifyAllGoals()); 1501 } 1502 1503 TEST_P(VerifierTest, GroupFactPasses) { 1504 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1505 #- { SomeNode.content 42 } 1506 source { root:"1" } 1507 fact_name: "/kythe/content" 1508 fact_value: "42" 1509 })")); 1510 ASSERT_TRUE(v.PrepareDatabase()); 1511 ASSERT_TRUE(v.VerifyAllGoals()); 1512 } 1513 1514 TEST_P(VerifierTest, CompoundGroups) { 1515 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1516 #- SomeNode.content 42 1517 #- !{ OtherNode.content 43 1518 #- AnotherNode.content 44 } 1519 #- !{ LastNode.content 45 } 1520 source { root:"1" } 1521 fact_name: "/kythe/content" 1522 fact_value: "42" 1523 } 1524 entries { 1525 source { root:"2" } 1526 fact_name: "/kythe/content" 1527 fact_value: "43" 1528 } 1529 )")); 1530 ASSERT_TRUE(v.PrepareDatabase()); 1531 ASSERT_TRUE(v.VerifyAllGoals()); 1532 } 1533 1534 TEST_P(VerifierTest, ConjunctionInsideNegatedGroupPassFail) { 1535 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1536 #- !{ SomeNode.content 42 1537 #- OtherNode.content 44 } 1538 source { root:"1" } 1539 fact_name: "/kythe/content" 1540 fact_value: "42" 1541 } 1542 entries { 1543 source { root:"2" } 1544 fact_name: "/kythe/content" 1545 fact_value: "43" 1546 } 1547 )")); 1548 ASSERT_TRUE(v.PrepareDatabase()); 1549 ASSERT_TRUE(v.VerifyAllGoals()); 1550 } 1551 1552 TEST_P(VerifierTest, ConjunctionInsideNegatedGroupPassPass) { 1553 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1554 #- !{ SomeNode.content 42 1555 #- OtherNode.content 43 } 1556 source { root:"1" } 1557 fact_name: "/kythe/content" 1558 fact_value: "42" 1559 } 1560 entries { 1561 source { root:"2" } 1562 fact_name: "/kythe/content" 1563 fact_value: "43" 1564 } 1565 )")); 1566 ASSERT_TRUE(v.PrepareDatabase()); 1567 ASSERT_FALSE(v.VerifyAllGoals()); 1568 } 1569 1570 TEST_P(VerifierTest, AntiContentFactFails) { 1571 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1572 #- !{ SomeNode.content 42 } 1573 source { root:"1" } 1574 fact_name: "/kythe/content" 1575 fact_value: "42" 1576 })")); 1577 ASSERT_TRUE(v.PrepareDatabase()); 1578 ASSERT_FALSE(v.VerifyAllGoals()); 1579 } 1580 1581 TEST_P(VerifierTest, AntiContentFactPasses) { 1582 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1583 #- !{ SomeNode.content 43 } 1584 source { root:"1" } 1585 fact_name: "/kythe/content" 1586 fact_value: "42" 1587 })")); 1588 ASSERT_TRUE(v.PrepareDatabase()); 1589 ASSERT_TRUE(v.VerifyAllGoals()); 1590 } 1591 1592 TEST_P(VerifierTest, SpacesAreOkay) { 1593 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1594 #- SomeNode.content 42 1595 source { root:"1" } 1596 fact_name: "/kythe/content" 1597 fact_value: "42" 1598 })")); 1599 ASSERT_TRUE(v.PrepareDatabase()); 1600 ASSERT_TRUE(v.VerifyAllGoals()); 1601 } 1602 1603 TEST_P(VerifierTest, ContentFactFails) { 1604 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1605 #- SomeNode.content 42 1606 source { root:"1" } 1607 fact_name: "/kythe/content" 1608 fact_value: "43" 1609 })")); 1610 ASSERT_TRUE(v.PrepareDatabase()); 1611 ASSERT_FALSE(v.VerifyAllGoals()); 1612 } 1613 1614 TEST_P(VerifierTest, PercentContentFactFails) { 1615 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1616 #- SomeNode.%content 42 1617 source { root:"1" } 1618 fact_name: "%/kythe/content" 1619 fact_value: "43" 1620 })")); 1621 ASSERT_TRUE(v.PrepareDatabase()); 1622 ASSERT_FALSE(v.VerifyAllGoals()); 1623 } 1624 1625 TEST_P(VerifierTest, SpacesDontDisableRules) { 1626 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1627 #- SomeNode.content 42 1628 source { root:"1" } 1629 fact_name: "/kythe/content" 1630 fact_value: "43" 1631 })")); 1632 ASSERT_TRUE(v.PrepareDatabase()); 1633 ASSERT_FALSE(v.VerifyAllGoals()); 1634 } 1635 1636 TEST_P(VerifierTest, DefinesEdgePasses) { 1637 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1638 #- SomeAnchor defines SomeNode 1639 source { root:"1" } 1640 edge_kind: "/kythe/edge/defines" 1641 target { root:"2" } 1642 fact_name: "/" 1643 fact_value: "" 1644 })")); 1645 ASSERT_TRUE(v.PrepareDatabase()); 1646 ASSERT_TRUE(v.VerifyAllGoals()); 1647 } 1648 1649 TEST_P(VerifierTest, HashDefinesEdgePasses) { 1650 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1651 #- SomeAnchor #defines SomeNode 1652 source { root:"1" } 1653 edge_kind: "#/kythe/edge/defines" 1654 target { root:"2" } 1655 fact_name: "/" 1656 fact_value: "" 1657 })")); 1658 ASSERT_TRUE(v.PrepareDatabase()); 1659 ASSERT_TRUE(v.VerifyAllGoals()); 1660 } 1661 1662 TEST_P(VerifierTest, HashFullDefinesEdgePasses) { 1663 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1664 #- SomeAnchor #/kythe/edge/defines SomeNode 1665 source { root:"1" } 1666 edge_kind: "#/kythe/edge/defines" 1667 target { root:"2" } 1668 fact_name: "/" 1669 fact_value: "" 1670 })")); 1671 ASSERT_TRUE(v.PrepareDatabase()); 1672 ASSERT_TRUE(v.VerifyAllGoals()); 1673 } 1674 1675 TEST_P(VerifierTest, PercentDefinesEdgePasses) { 1676 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1677 #- SomeAnchor %defines SomeNode 1678 source { root:"1" } 1679 edge_kind: "%/kythe/edge/defines" 1680 target { root:"2" } 1681 fact_name: "/" 1682 fact_value: "" 1683 })")); 1684 ASSERT_TRUE(v.PrepareDatabase()); 1685 ASSERT_TRUE(v.VerifyAllGoals()); 1686 } 1687 1688 TEST_P(VerifierTest, PercentFullDefinesEdgePasses) { 1689 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1690 #- SomeAnchor %/kythe/edge/defines SomeNode 1691 source { root:"1" } 1692 edge_kind: "%/kythe/edge/defines" 1693 target { root:"2" } 1694 fact_name: "/" 1695 fact_value: "" 1696 })")); 1697 ASSERT_TRUE(v.PrepareDatabase()); 1698 ASSERT_TRUE(v.VerifyAllGoals()); 1699 } 1700 1701 TEST_P(VerifierTest, IsParamEdgePasses) { 1702 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1703 #- SomeParam is_param.1 SomeNode 1704 source { root:"1" } 1705 edge_kind: "/kythe/edge/is_param" 1706 target { root:"2" } 1707 fact_name: "/kythe/ordinal" 1708 fact_value: "1" 1709 })")); 1710 ASSERT_TRUE(v.PrepareDatabase()); 1711 ASSERT_TRUE(v.VerifyAllGoals()); 1712 } 1713 1714 TEST_P(VerifierTest, IsParamEdgePassesDotOrdinal) { 1715 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1716 #- SomeParam is_param.1 SomeNode 1717 source { root:"1" } 1718 edge_kind: "/kythe/edge/is_param.1" 1719 target { root:"2" } 1720 fact_name: "/" 1721 })")); 1722 ASSERT_TRUE(v.PrepareDatabase()); 1723 ASSERT_TRUE(v.VerifyAllGoals()); 1724 } 1725 1726 TEST_P(VerifierTest, IsParamEdgeBadDotOrdinalNoNumber) { 1727 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1728 #- SomeParam is_param.1 SomeNode 1729 source { root:"1" } 1730 edge_kind: "/kythe/edge/is_param." 1731 target { root:"2" } 1732 fact_name: "/" 1733 })")); 1734 ASSERT_TRUE(v.PrepareDatabase()); 1735 ASSERT_FALSE(v.VerifyAllGoals()); 1736 } 1737 1738 TEST_P(VerifierTest, IsParamEdgeBadDotOrdinalOnlyDot) { 1739 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1740 #- SomeParam is_param.1 SomeNode 1741 source { root:"1" } 1742 edge_kind: "." 1743 target { root:"2" } 1744 fact_name: "/" 1745 })")); 1746 ASSERT_TRUE(v.PrepareDatabase()); 1747 ASSERT_FALSE(v.VerifyAllGoals()); 1748 } 1749 1750 TEST_P(VerifierTest, IsParamEdgeBadDotOrdinalNoEdge) { 1751 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1752 #- SomeParam is_param.1 SomeNode 1753 source { root:"1" } 1754 edge_kind: ".42" 1755 target { root:"2" } 1756 fact_name: "/" 1757 })")); 1758 ASSERT_TRUE(v.PrepareDatabase()); 1759 ASSERT_FALSE(v.VerifyAllGoals()); 1760 } 1761 1762 TEST_P(VerifierTest, IsParamEdgeFailsOnWrongOrdinal) { 1763 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1764 #- SomeParam is_param.1 SomeNode 1765 source { root:"1" } 1766 edge_kind: "/kythe/edge/is_param" 1767 target { root:"2" } 1768 fact_name: "/kythe/ordinal" 1769 fact_value: "42" 1770 })")); 1771 ASSERT_TRUE(v.PrepareDatabase()); 1772 ASSERT_FALSE(v.VerifyAllGoals()); 1773 } 1774 1775 TEST_P(VerifierTest, IsParamEdgeFailsOnWrongDotOrdinal) { 1776 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1777 #- SomeParam is_param.1 SomeNode 1778 source { root:"1" } 1779 edge_kind: "/kythe/edge/is_param.42" 1780 target { root:"2" } 1781 fact_name: "/" 1782 })")); 1783 ASSERT_TRUE(v.PrepareDatabase()); 1784 ASSERT_FALSE(v.VerifyAllGoals()); 1785 } 1786 1787 TEST_P(VerifierTest, IsParamEdgeFailsOnMissingOrdinalInGoal) { 1788 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1789 #- SomeParam is_param SomeNode 1790 source { root:"1" } 1791 edge_kind: "/kythe/edge/is_param" 1792 target { root:"2" } 1793 fact_name: "/kythe/ordinal" 1794 fact_value: "42" 1795 })")); 1796 ASSERT_TRUE(v.PrepareDatabase()); 1797 ASSERT_FALSE(v.VerifyAllGoals()); 1798 } 1799 1800 TEST_P(VerifierTest, IsParamEdgeFailsOnMissingDotOrdinalInGoal) { 1801 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1802 #- SomeParam is_param SomeNode 1803 source { root:"1" } 1804 edge_kind: "/kythe/edge/is_param.42" 1805 target { root:"2" } 1806 fact_name: "/" 1807 })")); 1808 ASSERT_TRUE(v.PrepareDatabase()); 1809 ASSERT_FALSE(v.VerifyAllGoals()); 1810 } 1811 1812 TEST_P(VerifierTest, IsParamEdgeFailsOnMissingOrdinalInFact) { 1813 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1814 #- SomeParam is_param.42 SomeNode 1815 source { root:"1" } 1816 edge_kind: "/kythe/edge/is_param" 1817 target { root:"2" } 1818 fact_name: "/" 1819 fact_value: "" 1820 })")); 1821 ASSERT_TRUE(v.PrepareDatabase()); 1822 ASSERT_FALSE(v.VerifyAllGoals()); 1823 } 1824 1825 TEST_P(VerifierTest, EvarsShareANamespace) { 1826 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1827 #- SomeAnchor defines SomeNode 1828 #- SomeNode defines SomeAnchor 1829 source { root:"1" } 1830 edge_kind: "/kythe/edge/defines" 1831 target { root:"2" } 1832 fact_name: "/" 1833 fact_value: "" 1834 })")); 1835 ASSERT_TRUE(v.PrepareDatabase()); 1836 ASSERT_FALSE(v.VerifyAllGoals()); 1837 } 1838 1839 TEST_P(VerifierTest, DefinesEdgePassesSymmetry) { 1840 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1841 #- SomeAnchor defines SomeNode 1842 source { root:"1" } 1843 edge_kind: "/kythe/edge/defines" 1844 target { root:"2" } 1845 fact_name: "/" 1846 fact_value: "" 1847 } 1848 entries { 1849 #- SomeNode defined_by SomeAnchor 1850 source { root:"2" } 1851 edge_kind: "/kythe/edge/defined_by" 1852 target { root:"1" } 1853 fact_name: "/" 1854 fact_value: "" 1855 } 1856 )")); 1857 ASSERT_TRUE(v.PrepareDatabase()); 1858 ASSERT_TRUE(v.VerifyAllGoals()); 1859 } 1860 1861 TEST_P(VerifierTest, EvarsStillShareANamespace) { 1862 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1863 #- SomeAnchor defines SomeNode 1864 source { root:"1" } 1865 edge_kind: "/kythe/edge/defines" 1866 target { root:"2" } 1867 fact_name: "/" 1868 fact_value: "" 1869 } 1870 entries { 1871 #- SomeAnchor defined_by SomeNode 1872 source { root:"2" } 1873 edge_kind: "/kythe/edge/defined_by" 1874 target { root:"1" } 1875 fact_name: "/" 1876 fact_value: "" 1877 } 1878 )")); 1879 ASSERT_TRUE(v.PrepareDatabase()); 1880 ASSERT_FALSE(v.VerifyAllGoals()); 1881 } 1882 1883 TEST(VerifierUnitTest, InspectionCalledFailure) { 1884 Verifier v; 1885 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1886 #- SomeAnchor? defines SomeNode 1887 source { root:"1" } 1888 edge_kind: "/kythe/edge/defines" 1889 target { root:"2" } 1890 fact_name: "/" 1891 fact_value: "" 1892 })")); 1893 ASSERT_TRUE(v.PrepareDatabase()); 1894 ASSERT_FALSE(v.VerifyAllGoals([](Verifier* cxt, const Inspection&, 1895 std::string_view) { return false; })); 1896 } 1897 1898 TEST(VerifierUnitTest, EvarsAreSharedAcrossInputFiles) { 1899 Verifier v; 1900 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1901 #- SomeAnchor? defines SomeNode 1902 source { root:"1" } 1903 edge_kind: "/kythe/edge/defines" 1904 target { root:"2" } 1905 fact_name: "/" 1906 fact_value: "" 1907 })")); 1908 ASSERT_TRUE(v.LoadInlineProtoFile(R"( 1909 #- SomeAnchor? defines _ 1910 )")); 1911 ASSERT_TRUE(v.PrepareDatabase()); 1912 EVar* seen_evar = nullptr; 1913 int seen_count = 0; 1914 ASSERT_TRUE(v.VerifyAllGoals( 1915 [&seen_evar, &seen_count](Verifier* cxt, const Inspection& inspection, 1916 std::string_view) { 1917 if (inspection.label == "SomeAnchor") { 1918 ++seen_count; 1919 if (seen_evar == nullptr) { 1920 seen_evar = inspection.evar; 1921 } else if (seen_evar != inspection.evar) { 1922 return false; 1923 } 1924 } 1925 return true; 1926 })); 1927 ASSERT_EQ(2, seen_count); 1928 ASSERT_NE(nullptr, seen_evar); 1929 } 1930 1931 TEST(VerifierUnitTest, InspectionCalledSuccess) { 1932 Verifier v; 1933 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1934 #- SomeAnchor? defines SomeNode 1935 source { root:"1" } 1936 edge_kind: "/kythe/edge/defines" 1937 target { root:"2" } 1938 fact_name: "/" 1939 fact_value: "" 1940 })")); 1941 ASSERT_TRUE(v.PrepareDatabase()); 1942 ASSERT_TRUE(v.VerifyAllGoals( 1943 [](Verifier* cxt, const Inspection&, std::string_view) { return true; })); 1944 } 1945 1946 TEST_P(VerifierTest, ManyInspectionsDontUpsetSolver) { 1947 // Souffle ships with a default max arity of 20 and will abort if it hits a 1948 // larger (output) relation. Check that we handle this. 1949 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1950 #- I01? defines SomeNode 1951 #- I02? defines SomeNode 1952 #- I03? defines SomeNode 1953 #- I04? defines SomeNode 1954 #- I05? defines SomeNode 1955 #- I06? defines SomeNode 1956 #- I07? defines SomeNode 1957 #- I08? defines SomeNode 1958 #- I09? defines SomeNode 1959 #- I10? defines SomeNode 1960 #- I11? defines SomeNode 1961 #- I12? defines SomeNode 1962 #- I13? defines SomeNode 1963 #- I14? defines SomeNode 1964 #- I15? defines SomeNode 1965 #- I16? defines SomeNode 1966 #- I17? defines SomeNode 1967 #- I18? defines SomeNode 1968 #- I19? defines SomeNode 1969 #- I20? defines SomeNode 1970 #- I21? defines SomeNode 1971 1972 source { root:"1" } 1973 edge_kind: "/kythe/edge/defines" 1974 target { root:"2" } 1975 fact_name: "/" 1976 fact_value: "" 1977 })")); 1978 int inspection_count = 0; 1979 ASSERT_TRUE(v.PrepareDatabase()); 1980 ASSERT_TRUE( 1981 v.VerifyAllGoals([&](Verifier* cxt, const Inspection&, std::string_view) { 1982 ++inspection_count; 1983 return true; 1984 })); 1985 EXPECT_EQ(inspection_count, 21); 1986 } 1987 1988 TEST(VerifierUnitTest, InspectionHappensMoreThanOnceAndThatsOk) { 1989 Verifier v; 1990 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 1991 #- SomeAnchor? defines SomeNode 1992 #- SomeAnchor? defines SomeNode 1993 source { root:"1" } 1994 edge_kind: "/kythe/edge/defines" 1995 target { root:"2" } 1996 fact_name: "/" 1997 fact_value: "" 1998 })")); 1999 ASSERT_TRUE(v.PrepareDatabase()); 2000 size_t inspect_count = 0; 2001 ASSERT_TRUE(v.VerifyAllGoals( 2002 [&inspect_count](Verifier* cxt, const Inspection&, std::string_view) { 2003 ++inspect_count; 2004 return true; 2005 })); 2006 ASSERT_EQ(2, inspect_count); 2007 } 2008 2009 TEST_P(VerifierTest, InspectionCalledCorrectly) { 2010 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2011 #- SomeAnchor? defines SomeNode 2012 source { root:"1" } 2013 edge_kind: "/kythe/edge/defines" 2014 target { root:"2" } 2015 fact_name: "/" 2016 fact_value: "" 2017 })")); 2018 ASSERT_TRUE(v.PrepareDatabase()); 2019 size_t call_count = 0; 2020 bool key_was_someanchor = false; 2021 bool evar_init = false; 2022 std::string istr; 2023 ASSERT_TRUE(v.VerifyAllGoals([&](Verifier* cxt, const Inspection& inspection, 2024 std::optional<std::string_view> s) { 2025 ++call_count; 2026 // Check for equivalence to `App(#vname, (#"", #"", 1, #"", #""))` 2027 key_was_someanchor = (inspection.label == "SomeAnchor"); 2028 istr = s ? *s : v.InspectionString(inspection); 2029 return true; 2030 })); 2031 EXPECT_EQ(1, call_count); 2032 EXPECT_EQ(R"(vname("", "", "1", "", ""))", istr); 2033 EXPECT_TRUE(key_was_someanchor); 2034 } 2035 2036 TEST_P(VerifierTest, FactsAreNotLinear) { 2037 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2038 #- SomeAnchor? defines SomeNode? 2039 #- AnotherAnchor? defines AnotherNode? 2040 source { root:"1" } 2041 edge_kind: "/kythe/edge/defines" 2042 target { root:"2" } 2043 fact_name: "/" 2044 fact_value: "" 2045 })")); 2046 ASSERT_TRUE(v.PrepareDatabase()); 2047 std::string some_anchor, some_node, another_anchor, another_node; 2048 ASSERT_TRUE(v.VerifyAllGoals( 2049 [&some_anchor, &some_node, &another_anchor, &another_node]( 2050 Verifier* cxt, const Inspection& inspection, std::string_view s) { 2051 if (inspection.label == "SomeAnchor") { 2052 some_anchor = s; 2053 } else if (inspection.label == "SomeNode") { 2054 some_node = s; 2055 } else if (inspection.label == "AnotherAnchor") { 2056 another_anchor = s; 2057 } else if (inspection.label == "AnotherNode") { 2058 another_node = s; 2059 } else { 2060 return false; 2061 } 2062 return true; 2063 })); 2064 EXPECT_EQ(some_anchor, another_anchor); 2065 EXPECT_EQ(some_node, another_node); 2066 EXPECT_NE(some_anchor, some_node); 2067 EXPECT_NE(another_anchor, another_node); 2068 } 2069 2070 TEST_P(VerifierTest, OrdinalsGetUnified) { 2071 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2072 #- SomeAnchor is_param.Ordinal? SomeNode 2073 source { root:"1" } 2074 edge_kind: "/kythe/edge/is_param" 2075 target { root:"2" } 2076 fact_name: "/kythe/ordinal" 2077 fact_value: "42" 2078 })")); 2079 ASSERT_TRUE(v.PrepareDatabase()); 2080 size_t call_count = 0; 2081 bool key_was_ordinal = false; 2082 bool evar_init = false; 2083 bool evar_init_to_correct_ordinal = false; 2084 ASSERT_TRUE(v.VerifyAllGoals( 2085 [&call_count, &key_was_ordinal, &evar_init, 2086 &evar_init_to_correct_ordinal]( 2087 Verifier* cxt, const Inspection& inspection, std::string_view s) { 2088 ++call_count; 2089 key_was_ordinal = (inspection.label == "Ordinal"); 2090 evar_init = CheckEVarInit(s); 2091 evar_init_to_correct_ordinal = s == "\"42\""; 2092 return true; 2093 })); 2094 EXPECT_EQ(1, call_count); 2095 EXPECT_TRUE(key_was_ordinal); 2096 EXPECT_TRUE(evar_init_to_correct_ordinal); 2097 } 2098 2099 TEST(VerifierUnitTest, DotOrdinalsGetUnified) { 2100 Verifier v; 2101 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2102 #- SomeAnchor is_param.Ordinal? SomeNode 2103 source { root:"1" } 2104 edge_kind: "/kythe/edge/is_param.42" 2105 target { root:"2" } 2106 fact_name: "/" 2107 })")); 2108 ASSERT_TRUE(v.PrepareDatabase()); 2109 size_t call_count = 0; 2110 bool key_was_ordinal = false; 2111 bool evar_init = false; 2112 bool evar_init_to_correct_ordinal = false; 2113 ASSERT_TRUE(v.VerifyAllGoals( 2114 [&call_count, &key_was_ordinal, &evar_init, 2115 &evar_init_to_correct_ordinal]( 2116 Verifier* cxt, const Inspection& inspection, std::string_view s) { 2117 ++call_count; 2118 key_was_ordinal = (inspection.label == "Ordinal"); 2119 evar_init = CheckEVarInit(s); 2120 evar_init_to_correct_ordinal = s == "\"42\""; 2121 return true; 2122 })); 2123 EXPECT_EQ(1, call_count); 2124 EXPECT_TRUE(key_was_ordinal); 2125 EXPECT_TRUE(evar_init_to_correct_ordinal); 2126 } 2127 2128 TEST_P(VerifierTest, EvarsAndIdentifiersCanHaveTheSameText) { 2129 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2130 #- vname(Signature?, "Signature", Root?, Path?, Language?) defines SomeNode 2131 source { 2132 signature:"Signature" 2133 corpus:"Signature" 2134 root:"Root" 2135 path:"Path" 2136 language:"Language" 2137 } 2138 edge_kind: "/kythe/edge/defines" 2139 target { root:"2" } 2140 fact_name: "/" 2141 fact_value: "" 2142 })")); 2143 ASSERT_TRUE(v.PrepareDatabase()); 2144 bool signature = false; 2145 bool root = false; 2146 bool path = false; 2147 bool language = false; 2148 ASSERT_TRUE(v.VerifyAllGoals( 2149 [&signature, &root, &path, &language]( 2150 Verifier* cxt, const Inspection& inspection, std::string_view s) { 2151 if (inspection.label == "Signature") signature = s == "Signature"; 2152 if (inspection.label == "Root") root = s == "Root"; 2153 if (inspection.label == "Path") path = s == "Path"; 2154 if (inspection.label == "Language") language = s == "Language"; 2155 return true; 2156 })); 2157 EXPECT_TRUE(signature); 2158 EXPECT_TRUE(root); 2159 EXPECT_TRUE(path); 2160 EXPECT_TRUE(language); 2161 } 2162 2163 TEST_P(VerifierTest, EvarsAndIdentifiersCanHaveTheSameTextAndAreNotRebound) { 2164 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2165 #- vname(Signature?, "Signature", Signature?, Path?, Language?) defines SomeNode 2166 source { 2167 signature:"Signature" 2168 corpus:"Signature" 2169 root:"Signature" 2170 path:"Path" 2171 language:"Language" 2172 } 2173 edge_kind: "/kythe/edge/defines" 2174 target { root:"2" } 2175 fact_name: "/" 2176 fact_value: "" 2177 })")); 2178 ASSERT_TRUE(v.PrepareDatabase()); 2179 bool signature = false; 2180 bool path = false; 2181 bool language = false; 2182 ASSERT_TRUE(v.VerifyAllGoals( 2183 [&signature, &path, &language]( 2184 Verifier* cxt, const Inspection& inspection, std::string_view s) { 2185 if (s == inspection.label) { 2186 if (inspection.label == "Signature") signature = true; 2187 if (inspection.label == "Path") path = true; 2188 if (inspection.label == "Language") language = true; 2189 } else { 2190 return false; 2191 } 2192 return true; 2193 })); 2194 EXPECT_TRUE(signature); 2195 EXPECT_TRUE(path); 2196 EXPECT_TRUE(language); 2197 } 2198 2199 TEST_P(VerifierTest, EqualityConstraintWorks) { 2200 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2201 #- One is vname(_,_,Two? = "2",_,_) 2202 source { root:"1" } 2203 fact_name: "/" 2204 fact_value: "" 2205 edge_kind: "/kythe/edge/is" 2206 target { root:"2" } 2207 } entries { 2208 source { root:"1" } 2209 fact_name: "/" 2210 fact_value: "" 2211 edge_kind: "/kythe/edge/is" 2212 target { root:"3" } 2213 })")); 2214 ASSERT_TRUE(v.PrepareDatabase()); 2215 ASSERT_TRUE(v.VerifyAllGoals( 2216 [](Verifier* cxt, const Inspection& inspection, absl::string_view s) { 2217 return (inspection.label == "Two" && s == "\"2\""); 2218 })); 2219 } 2220 2221 TEST_P(VerifierTest, EqualityConstraintWorksOnAnchors) { 2222 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2223 #- Tx?=@text defines SomeNode 2224 ##text (line 3 column 2 offset 42-46) 2225 source { root:"1" } 2226 fact_name: "/kythe/node/kind" 2227 fact_value: "anchor" 2228 } 2229 entries { 2230 source { root:"1" } 2231 fact_name: "/kythe/loc/start" 2232 fact_value: "42" 2233 } 2234 entries { 2235 source { root:"1" } 2236 fact_name: "/kythe/loc/end" 2237 fact_value: "46" 2238 } 2239 entries { 2240 source { root:"1" } 2241 edge_kind: "/kythe/edge/defines" 2242 target { root:"2" } 2243 fact_name: "/" 2244 fact_value: "" 2245 })", 2246 "", "1")); 2247 ASSERT_TRUE(v.PrepareDatabase()); 2248 ASSERT_TRUE(v.VerifyAllGoals( 2249 [](Verifier* cxt, const Inspection& inspection, std::string_view s) { 2250 return (inspection.label == "Tx" && !s.empty()); 2251 })); 2252 } 2253 2254 TEST_P(VerifierTest, EqualityConstraintWorksOnAnchorsRev) { 2255 if (GetParam() == Solver::New) { 2256 // TODO: Turns out that we do need to propagate (type) equality constraints. 2257 GTEST_SKIP(); 2258 } 2259 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2260 #- @text=Tx? defines SomeNode 2261 ##text (line 3 column 2 offset 42-46) 2262 source { root:"1" } 2263 fact_name: "/kythe/node/kind" 2264 fact_value: "anchor" 2265 } 2266 entries { 2267 source { root:"1" } 2268 fact_name: "/kythe/loc/start" 2269 fact_value: "42" 2270 } 2271 entries { 2272 source { root:"1" } 2273 fact_name: "/kythe/loc/end" 2274 fact_value: "46" 2275 } 2276 entries { 2277 source { root:"1" } 2278 edge_kind: "/kythe/edge/defines" 2279 target { root:"2" } 2280 fact_name: "/" 2281 fact_value: "" 2282 })", 2283 "", "1")); 2284 ASSERT_TRUE(v.PrepareDatabase()); 2285 ASSERT_TRUE(v.VerifyAllGoals( 2286 [](Verifier* cxt, const Inspection& inspection, std::string_view s) { 2287 return (inspection.label == "Tx" && !s.empty()); 2288 })); 2289 } 2290 2291 // It's possible to match Tx against {root:7}: 2292 TEST_P(VerifierTest, EqualityConstraintWorksOnAnchorsPossibleConstraint) { 2293 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2294 #- @text defines SomeNode 2295 ##text (line 3 column 2 offset 38-42) 2296 #- Tx.node/kind notananchor 2297 source { root:"1" } 2298 fact_name: "/kythe/node/kind" 2299 fact_value: "anchor" 2300 } 2301 entries { 2302 source { root:"7" } 2303 fact_name: "/kythe/node/kind" 2304 fact_value: "notananchor" 2305 } 2306 entries { 2307 source { root:"1" } 2308 fact_name: "/kythe/loc/start" 2309 fact_value: "38" 2310 } 2311 entries { 2312 source { root:"1" } 2313 fact_name: "/kythe/loc/end" 2314 fact_value: "42" 2315 } 2316 entries { 2317 source { root:"1" } 2318 edge_kind: "/kythe/edge/defines" 2319 target { root:"2" } 2320 fact_name: "/" 2321 fact_value: "" 2322 })", 2323 "", "1")); 2324 ASSERT_TRUE(v.PrepareDatabase()); 2325 ASSERT_TRUE(v.VerifyAllGoals()); 2326 } 2327 2328 // It's impossible to match Tx against {root:7} if we constrain Tx to equal 2329 // an anchor specifier. 2330 TEST_P(VerifierTest, EqualityConstraintWorksOnAnchorsImpossibleConstraint) { 2331 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2332 #- Tx?=@text defines SomeNode 2333 ##text (line 3 column 2 offset 42-46) 2334 #- Tx.node/kind notananchor 2335 source { root:"1" } 2336 fact_name: "/kythe/node/kind" 2337 fact_value: "anchor" 2338 } 2339 entries { 2340 source { root:"7" } 2341 fact_name: "/kythe/node/kind" 2342 fact_value: "notananchor" 2343 } 2344 entries { 2345 source { root:"1" } 2346 fact_name: "/kythe/loc/start" 2347 fact_value: "42" 2348 } 2349 entries { 2350 source { root:"1" } 2351 fact_name: "/kythe/loc/end" 2352 fact_value: "46" 2353 } 2354 entries { 2355 source { root:"1" } 2356 edge_kind: "/kythe/edge/defines" 2357 target { root:"2" } 2358 fact_name: "/" 2359 fact_value: "" 2360 })")); 2361 ASSERT_TRUE(v.PrepareDatabase()); 2362 ASSERT_FALSE(v.VerifyAllGoals()); 2363 } 2364 2365 TEST_P(VerifierTest, EqualityConstraintWorksWithOtherSortedRules) { 2366 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2367 #- One is vname(_,_,Three? = "3",_,_) 2368 source { root:"1" } 2369 fact_name: "/" 2370 fact_value: "" 2371 edge_kind: "/kythe/edge/is" 2372 target { root:"2" } 2373 } entries { 2374 source { root:"1" } 2375 fact_name: "/" 2376 fact_value: "" 2377 edge_kind: "/kythe/edge/is" 2378 target { root:"3" } 2379 })")); 2380 ASSERT_TRUE(v.PrepareDatabase()); 2381 ASSERT_TRUE( 2382 v.VerifyAllGoals([](Verifier* cxt, const Inspection& inspection, 2383 std::string_view s) { return s == "\"3\""; })); 2384 } 2385 2386 TEST_P(VerifierTest, EqualityConstraintFails) { 2387 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2388 #- One is vname(_,_,Two = "2",_,_) 2389 #- One is vname(_,_,Three = "3",_,_) 2390 #- One is vname(_,_,Two = Three,_,_) 2391 source { root:"1" } 2392 fact_name: "/" 2393 fact_value: "" 2394 edge_kind: "/kythe/edge/is" 2395 target { root:"2" } 2396 } entries { 2397 source { root:"1" } 2398 fact_name: "/" 2399 fact_value: "" 2400 edge_kind: "/kythe/edge/is" 2401 target { root:"3" } 2402 })")); 2403 ASSERT_TRUE(v.PrepareDatabase()); 2404 ASSERT_FALSE(v.VerifyAllGoals()); 2405 } 2406 2407 TEST_P(VerifierTest, IdentityEqualityConstraintSucceeds) { 2408 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2409 #- One is vname(_,_,Two = Two,_,_) 2410 source { root:"1" } 2411 fact_name: "/" 2412 fact_value: "" 2413 edge_kind: "/kythe/edge/is" 2414 target { root:"2" } 2415 } entries { 2416 source { root:"1" } 2417 fact_name: "/" 2418 fact_value: "" 2419 edge_kind: "/kythe/edge/is" 2420 target { root:"3" } 2421 })")); 2422 ASSERT_TRUE(v.PrepareDatabase()); 2423 ASSERT_TRUE(v.VerifyAllGoals()); 2424 } 2425 2426 TEST_P(VerifierTest, TransitiveIdentityEqualityConstraintFails) { 2427 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2428 #- One is vname(_,_,Two = Dos = Two,_,_) 2429 source { root:"1" } 2430 fact_name: "/" 2431 fact_value: "" 2432 edge_kind: "/kythe/edge/is" 2433 target { root:"2" } 2434 } entries { 2435 source { root:"1" } 2436 fact_name: "/" 2437 fact_value: "" 2438 edge_kind: "/kythe/edge/is" 2439 target { root:"3" } 2440 })")); 2441 ASSERT_TRUE(v.PrepareDatabase()); 2442 if (GetParam() == Solver::New) { 2443 // The new solver can handle cycles in equality constraints. 2444 ASSERT_TRUE(v.VerifyAllGoals()); 2445 } else { 2446 ASSERT_FALSE(v.VerifyAllGoals()); 2447 } 2448 } 2449 2450 TEST_P(VerifierTest, GraphEqualityConstraintFails) { 2451 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2452 #- One is Two = vname(_,_,Two,_,_) 2453 source { root:"1" } 2454 fact_name: "/" 2455 fact_value: "" 2456 edge_kind: "/kythe/edge/is" 2457 target { root:"2" } 2458 } entries { 2459 source { root:"1" } 2460 fact_name: "/" 2461 fact_value: "" 2462 edge_kind: "/kythe/edge/is" 2463 target { root:"3" } 2464 })")); 2465 ASSERT_TRUE(v.PrepareDatabase()); 2466 ASSERT_FALSE(v.VerifyAllGoals()); 2467 } 2468 2469 TEST_P(VerifierTest, UnifyVersusVname) { 2470 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2471 #- vname(Signature?, Corpus?, Root?, Path?, Language?) defines SomeNode 2472 source { 2473 signature:"Signature" 2474 corpus:"Corpus" 2475 root:"Root" 2476 path:"Path" 2477 language:"Language" 2478 } 2479 edge_kind: "/kythe/edge/defines" 2480 target { root:"2" } 2481 fact_name: "/" 2482 fact_value: "" 2483 })")); 2484 ASSERT_TRUE(v.PrepareDatabase()); 2485 bool signature = false; 2486 bool corpus = false; 2487 bool root = false; 2488 bool path = false; 2489 bool language = false; 2490 ASSERT_TRUE(v.VerifyAllGoals( 2491 [&signature, &corpus, &root, &path, &language]( 2492 Verifier* cxt, const Inspection& inspection, std::string_view s) { 2493 if (inspection.label == "Signature") signature = true; 2494 if (inspection.label == "Corpus") corpus = true; 2495 if (inspection.label == "Root") root = true; 2496 if (inspection.label == "Path") path = true; 2497 if (inspection.label == "Language") language = true; 2498 return (s == inspection.label); 2499 })); 2500 EXPECT_TRUE(signature); 2501 EXPECT_TRUE(corpus); 2502 EXPECT_TRUE(root); 2503 EXPECT_TRUE(path); 2504 EXPECT_TRUE(language); 2505 } 2506 2507 TEST_P(VerifierTest, UnifyVersusVnameWithDontCare) { 2508 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2509 #- vname(Signature?, Corpus?, Root?, _?, Language?) defines SomeNode 2510 source { 2511 signature:"Signature" 2512 corpus:"Corpus" 2513 root:"Root" 2514 path:"Path" 2515 language:"Language" 2516 } 2517 edge_kind: "/kythe/edge/defines" 2518 target { root:"2" } 2519 fact_name: "/" 2520 fact_value: "" 2521 })")); 2522 ASSERT_TRUE(v.PrepareDatabase()); 2523 bool signature = false; 2524 bool corpus = false; 2525 bool root = false; 2526 bool path = false; 2527 bool language = false; 2528 ASSERT_TRUE(v.VerifyAllGoals( 2529 [&signature, &corpus, &root, &path, &language]( 2530 Verifier* cxt, const Inspection& inspection, std::string_view s) { 2531 if ((inspection.label != "Path" && s == inspection.label) || 2532 (inspection.label == "_" && s == "Path")) { 2533 if (inspection.label == "Signature") signature = true; 2534 if (inspection.label == "Corpus") corpus = true; 2535 if (inspection.label == "Root") root = true; 2536 if (inspection.label == "_") path = true; 2537 if (inspection.label == "Language") language = true; 2538 return true; 2539 } 2540 return false; 2541 })); 2542 EXPECT_TRUE(signature); 2543 EXPECT_TRUE(corpus); 2544 EXPECT_TRUE(root); 2545 EXPECT_TRUE(path); 2546 EXPECT_TRUE(language); 2547 } 2548 2549 TEST_P(VerifierTest, UnifyVersusVnameWithEmptyStringSpelledOut) { 2550 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2551 #- vname(Signature?, Corpus?, Root?, "", Language?) defines SomeNode 2552 source { 2553 signature:"Signature" 2554 corpus:"Corpus" 2555 root:"Root" 2556 language:"Language" 2557 } 2558 edge_kind: "/kythe/edge/defines" 2559 target { root:"2" } 2560 fact_name: "/" 2561 fact_value: "" 2562 })")); 2563 ASSERT_TRUE(v.PrepareDatabase()); 2564 bool signature = false; 2565 bool corpus = false; 2566 bool root = false; 2567 bool path = false; 2568 bool language = false; 2569 ASSERT_TRUE(v.VerifyAllGoals( 2570 [&signature, &corpus, &root, &language]( 2571 Verifier* cxt, const Inspection& inspection, std::string_view s) { 2572 if (inspection.label == "Signature") signature = true; 2573 if (inspection.label == "Corpus") corpus = true; 2574 if (inspection.label == "Root") root = true; 2575 if (inspection.label == "Language") language = true; 2576 return (s == inspection.label); 2577 })); 2578 EXPECT_TRUE(signature); 2579 EXPECT_TRUE(corpus); 2580 EXPECT_TRUE(root); 2581 EXPECT_TRUE(language); 2582 } 2583 2584 TEST_P(VerifierTest, UnifyVersusVnameWithEmptyStringBound) { 2585 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2586 #- vname(Signature?, Corpus?, Root?, Path?, Language?) defines SomeNode 2587 source { 2588 signature:"Signature" 2589 corpus:"Corpus" 2590 root:"Root" 2591 language:"Language" 2592 } 2593 edge_kind: "/kythe/edge/defines" 2594 target { root:"2" } 2595 fact_name: "/" 2596 fact_value: "" 2597 })")); 2598 ASSERT_TRUE(v.PrepareDatabase()); 2599 bool signature = false; 2600 bool corpus = false; 2601 bool root = false; 2602 bool path = false; 2603 bool language = false; 2604 ASSERT_TRUE(v.VerifyAllGoals( 2605 [&signature, &corpus, &root, &path, &language]( 2606 Verifier* cxt, const Inspection& inspection, std::string_view s) { 2607 if ((inspection.label != "Path" && s == inspection.label) || 2608 (inspection.label == "Path" && s == "\"\"")) { 2609 if (inspection.label == "Signature") signature = true; 2610 if (inspection.label == "Corpus") corpus = true; 2611 if (inspection.label == "Root") root = true; 2612 if (inspection.label == "Path") path = true; 2613 if (inspection.label == "Language") language = true; 2614 return true; 2615 } 2616 2617 return false; 2618 })); 2619 EXPECT_TRUE(signature); 2620 EXPECT_TRUE(corpus); 2621 EXPECT_TRUE(root); 2622 EXPECT_TRUE(path); 2623 EXPECT_TRUE(language); 2624 } 2625 2626 TEST_P(VerifierTest, LastGoalToFailIsSelected) { 2627 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2628 #- SomeNode.content 43 2629 #- SomeNode.content 43 2630 #- SomeNode.content 42 2631 #- SomeNode.content 46 2632 source { root:"1" } 2633 fact_name: "/kythe/content" 2634 fact_value: "43" 2635 })")); 2636 ASSERT_TRUE(v.PrepareDatabase()); 2637 ASSERT_FALSE(v.VerifyAllGoals()); 2638 ASSERT_EQ(2, v.highest_goal_reached()); 2639 } 2640 2641 TEST_P(VerifierTest, ReadGoalsFromFileNodeFailure) { 2642 v.UseFileNodes(); 2643 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2644 source { path:"test" } 2645 fact_name: "/kythe/node/kind" 2646 fact_value: "file" 2647 } 2648 entries { 2649 source { path:"test" } 2650 fact_name: "/kythe/text" 2651 fact_value: "//- A.node/kind file\n//- A.notafact yes\n" 2652 })")); 2653 ASSERT_TRUE(v.PrepareDatabase()); 2654 ASSERT_FALSE(v.VerifyAllGoals()); 2655 ASSERT_EQ(1, v.highest_goal_reached()); 2656 } 2657 2658 TEST_P(VerifierTest, ReadGoalsFromFileNodeSuccess) { 2659 v.UseFileNodes(); 2660 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2661 source { path:"test" } 2662 fact_name: "/kythe/node/kind" 2663 fact_value: "file" 2664 } 2665 entries { 2666 source { path:"test" } 2667 fact_name: "/kythe/text" 2668 fact_value: "//- A.node/kind file\n" 2669 })")); 2670 ASSERT_TRUE(v.PrepareDatabase()); 2671 ASSERT_TRUE(v.VerifyAllGoals()); 2672 } 2673 2674 TEST_P(VerifierTest, ReadGoalsFromFileNodeEmptyCorpusSuccess) { 2675 v.UseFileNodes(); 2676 v.UseDefaultFileCorpus("testcorpus"); 2677 ASSERT_TRUE(v.LoadInlineProtoFile(R"(entries { 2678 source { path:"test" } 2679 fact_name: "/kythe/node/kind" 2680 fact_value: "file" 2681 } 2682 entries { 2683 source { path:"test" } 2684 fact_name: "/kythe/text" 2685 fact_value: "//- @a.node/kind anchor\na" 2686 } 2687 entries { 2688 source { signature: "a" corpus:"testcorpus" path:"test" } 2689 fact_name: "/kythe/node/kind" 2690 fact_value: "anchor" 2691 } 2692 entries { 2693 source { signature: "a" corpus:"testcorpus" path:"test" } 2694 fact_name: "/kythe/loc/start" 2695 fact_value: "24" 2696 } 2697 entries { 2698 source { signature: "a" corpus:"testcorpus" path:"test" } 2699 fact_name: "/kythe/loc/end" 2700 fact_value: "25" 2701 } 2702 )")); 2703 ASSERT_TRUE(v.PrepareDatabase()); 2704 ASSERT_TRUE(v.VerifyAllGoals()); 2705 } 2706 2707 TEST_P(VerifierTest, ReadGoalsFromFileNodeFailParse) { 2708 v.UseFileNodes(); 2709 bool parsed = v.LoadInlineProtoFile(R"(entries { 2710 source { path:"test" } 2711 fact_name: "/kythe/node/kind" 2712 fact_value: "file" 2713 } 2714 entries { 2715 source { path:"test" } 2716 fact_name: "/kythe/text" 2717 fact_value: "//- A->node/kind file\n" 2718 })"); 2719 if (GetParam() == Solver::Old) { 2720 ASSERT_TRUE(parsed); 2721 ASSERT_FALSE(v.PrepareDatabase()); 2722 } else { 2723 ASSERT_FALSE(parsed); 2724 } 2725 } 2726 2727 TEST_P(VerifierTest, DontConvertMarkedSource) { 2728 MarkedSource source; 2729 std::string source_string; 2730 ASSERT_TRUE(source.SerializeToString(&source_string)); 2731 google::protobuf::TextFormat::FieldValuePrinter printer; 2732 std::string enc_source = printer.PrintBytes(source_string); 2733 ASSERT_TRUE(v.LoadInlineProtoFile(R"( 2734 entries { 2735 source { signature:"test" } 2736 fact_name: "/kythe/code" 2737 fact_value: )" + enc_source + R"( 2738 } 2739 #- vname("test","","","","").code _ 2740 #- !{vname("test","","","","") code _} 2741 )")); 2742 ASSERT_TRUE(v.PrepareDatabase()); 2743 ASSERT_TRUE(v.VerifyAllGoals()); 2744 } 2745 2746 enum class MsFormat { kTextProto, kJson }; 2747 2748 class VerifierMarkedSourceUnitTest 2749 : public ::testing::TestWithParam<std::tuple<MsFormat, Solver>> { 2750 protected: 2751 std::string Entries(const MarkedSource& source) const { 2752 kythe::proto::Entries entries; 2753 auto entry = entries.add_entries(); 2754 entry->mutable_source()->set_signature("test"); 2755 entry->set_fact_name(FactName()); 2756 entry->set_fact_value(Encode(source)); 2757 std::string result; 2758 GTEST_CHECK_(google::protobuf::TextFormat::PrintToString(entries, &result)); 2759 return result; 2760 } 2761 2762 void ConfigureVerifier(Verifier& v) { 2763 v.UseFastSolver(std::get<1>(GetParam()) == Solver::Old ? false : true); 2764 } 2765 2766 private: 2767 std::string FactName() const { 2768 return std::get<0>(GetParam()) == MsFormat::kTextProto ? "/kythe/code" 2769 : "/kythe/code/json"; 2770 } 2771 2772 std::string Encode(const MarkedSource& source) const { 2773 if (std::get<0>(GetParam()) == MsFormat::kTextProto) { 2774 std::string source_string; 2775 GTEST_CHECK_(source.SerializeToString(&source_string)) 2776 << "Failure serializing MarkedSource"; 2777 return source_string; 2778 } else { 2779 std::string source_string; 2780 GTEST_CHECK_( 2781 google::protobuf::util::MessageToJsonString(source, &source_string) 2782 .ok()) 2783 << "Failure serializing MarkedSource to JSON"; 2784 return source_string; 2785 } 2786 } 2787 }; 2788 2789 TEST_P(VerifierMarkedSourceUnitTest, ConvertMarkedSource) { 2790 Verifier v; 2791 ConfigureVerifier(v); 2792 v.ConvertMarkedSource(); 2793 MarkedSource source; 2794 ASSERT_TRUE(v.LoadInlineProtoFile(Entries(source) + R"( 2795 #- !{vname("test","","","","").code _} 2796 #- vname("test","","","","") code Tree 2797 #- Tree.kind "BOX" 2798 #- Tree.pre_text "" 2799 #- Tree.post_child_text "" 2800 #- Tree.post_text "" 2801 #- Tree.lookup_index 0 2802 #- Tree.default_children_count 0 2803 #- Tree.add_final_list_token false 2804 )")); 2805 ASSERT_TRUE(v.PrepareDatabase()); 2806 ASSERT_TRUE(v.VerifyAllGoals()); 2807 } 2808 2809 TEST_P(VerifierMarkedSourceUnitTest, ConvertMarkedSourceKindEnums) { 2810 for (int kind = MarkedSource::Kind_MIN; kind <= MarkedSource::Kind_MAX; 2811 ++kind) { 2812 if (!MarkedSource::Kind_IsValid(kind)) { 2813 continue; 2814 } 2815 auto kind_enum = static_cast<MarkedSource::Kind>(kind); 2816 Verifier v; 2817 ConfigureVerifier(v); 2818 v.ConvertMarkedSource(); 2819 MarkedSource source; 2820 source.set_kind(kind_enum); 2821 ASSERT_TRUE(v.LoadInlineProtoFile(Entries(source) + R"( 2822 #- vname("test","","","","") code Tree 2823 #- Tree.kind ")" + MarkedSource::Kind_Name(kind_enum) + 2824 R"(" 2825 )")); 2826 ASSERT_TRUE(v.PrepareDatabase()); 2827 ASSERT_TRUE(v.VerifyAllGoals()); 2828 } 2829 } 2830 2831 TEST_P(VerifierMarkedSourceUnitTest, ConvertMarkedSourceLinks) { 2832 Verifier v; 2833 ConfigureVerifier(v); 2834 v.ConvertMarkedSource(); 2835 MarkedSource source; 2836 source.add_link()->add_definition("kythe://corpus#sig"); 2837 ASSERT_TRUE(v.LoadInlineProtoFile(Entries(source) + R"( 2838 #- vname("test","","","","") code Tree 2839 #- Tree link vname("sig", "corpus", "", "", "") 2840 )")); 2841 ASSERT_TRUE(v.PrepareDatabase()); 2842 ASSERT_TRUE(v.VerifyAllGoals()); 2843 } 2844 2845 TEST_P(VerifierMarkedSourceUnitTest, ConvertMarkedSourceLinksBadUri) { 2846 Verifier v; 2847 ConfigureVerifier(v); 2848 v.ConvertMarkedSource(); 2849 MarkedSource source; 2850 source.add_link()->add_definition("kythe:/&bad"); 2851 ASSERT_FALSE(v.LoadInlineProtoFile(Entries(source))); 2852 } 2853 2854 TEST_P(VerifierMarkedSourceUnitTest, ConvertMarkedSourceLinksMissingUri) { 2855 Verifier v; 2856 ConfigureVerifier(v); 2857 v.ConvertMarkedSource(); 2858 MarkedSource source; 2859 source.add_link(); 2860 ASSERT_FALSE(v.LoadInlineProtoFile(Entries(source))); 2861 } 2862 2863 TEST_P(VerifierMarkedSourceUnitTest, ConvertMarkedSourceLinksMultipleUri) { 2864 Verifier v; 2865 ConfigureVerifier(v); 2866 v.ConvertMarkedSource(); 2867 MarkedSource source; 2868 auto* link = source.add_link(); 2869 link->add_definition("kythe://corpus#sig"); 2870 link->add_definition("kythe://corpus#sig2"); 2871 ASSERT_FALSE(v.LoadInlineProtoFile(Entries(source))); 2872 } 2873 2874 TEST_P(VerifierMarkedSourceUnitTest, ConvertMarkedSourceChildren) { 2875 Verifier v; 2876 ConfigureVerifier(v); 2877 v.ConvertMarkedSource(); 2878 MarkedSource source; 2879 auto* child = source.add_child(); 2880 child->set_kind(MarkedSource::IDENTIFIER); 2881 child = source.add_child(); 2882 child->set_kind(MarkedSource::CONTEXT); 2883 ASSERT_TRUE(v.LoadInlineProtoFile(Entries(source) + R"( 2884 #- vname("test","","","","") code Tree 2885 #- Tree child.0 IdChild 2886 #- IdChild.kind "IDENTIFIER" 2887 #- Tree child.1 ContextChild 2888 #- ContextChild.kind "CONTEXT" 2889 )")); 2890 ASSERT_TRUE(v.PrepareDatabase()); 2891 ASSERT_TRUE(v.VerifyAllGoals()); 2892 } 2893 2894 TEST_P(VerifierMarkedSourceUnitTest, ConvertMarkedSourceBadChildren) { 2895 Verifier v; 2896 ConfigureVerifier(v); 2897 v.ConvertMarkedSource(); 2898 MarkedSource parent; 2899 MarkedSource* child = parent.add_child(); 2900 auto* link = child->add_link(); 2901 link->add_definition("kythe://corpus#sig"); 2902 link->add_definition("kythe://corpus#sig2"); 2903 ASSERT_FALSE(v.LoadInlineProtoFile(Entries(parent))); 2904 } 2905 2906 TEST_P(VerifierMarkedSourceUnitTest, ConvertMarkedSourceFields) { 2907 Verifier v; 2908 ConfigureVerifier(v); 2909 v.ConvertMarkedSource(); 2910 MarkedSource source; 2911 source.set_pre_text("pre_text"); 2912 source.set_post_child_text("post_child_text"); 2913 source.set_post_text("post_text"); 2914 source.set_lookup_index(42); 2915 source.set_default_children_count(43); 2916 source.set_add_final_list_token(true); 2917 ASSERT_TRUE(v.LoadInlineProtoFile(Entries(source) + R"( 2918 #- vname("test","","","","") code Tree 2919 #- Tree.pre_text "pre_text" 2920 #- Tree.post_child_text "post_child_text" 2921 #- Tree.post_text "post_text" 2922 #- Tree.lookup_index 42 2923 #- Tree.default_children_count 43 2924 #- Tree.add_final_list_token true 2925 )")); 2926 ASSERT_TRUE(v.PrepareDatabase()); 2927 ASSERT_TRUE(v.VerifyAllGoals()); 2928 } 2929 2930 TEST_P(VerifierMarkedSourceUnitTest, 2931 DontConvertMarkedSourceDuplicateFactsWellFormed) { 2932 Verifier v; 2933 ConfigureVerifier(v); 2934 MarkedSource source; 2935 v.IgnoreDuplicateFacts(); 2936 ASSERT_TRUE(v.LoadInlineProtoFile(Entries(source) + "\n" + Entries(source))); 2937 ASSERT_TRUE(v.PrepareDatabase()); 2938 ASSERT_TRUE(v.VerifyAllGoals()); 2939 } 2940 2941 TEST_P(VerifierMarkedSourceUnitTest, 2942 ConvertMarkedSourceDuplicateFactsWellFormed) { 2943 Verifier v; 2944 ConfigureVerifier(v); 2945 v.ConvertMarkedSource(); 2946 MarkedSource source; 2947 ASSERT_TRUE(v.LoadInlineProtoFile(Entries(source) + "\n" + Entries(source))); 2948 ASSERT_TRUE(v.PrepareDatabase()); 2949 ASSERT_TRUE(v.VerifyAllGoals()); 2950 } 2951 2952 TEST_P(VerifierMarkedSourceUnitTest, ConflictingCodeFactsNotWellFormed) { 2953 if (std::get<1>(GetParam()) == Solver::New) { 2954 // The new solver doesn't currently perform conflict checks. 2955 GTEST_SKIP(); 2956 } 2957 Verifier v; 2958 ConfigureVerifier(v); 2959 MarkedSource source; 2960 2961 MarkedSource source_conflict; 2962 source_conflict.set_pre_text("pre_text"); 2963 ASSERT_TRUE( 2964 v.LoadInlineProtoFile(Entries(source) + "\n" + Entries(source_conflict))); 2965 ASSERT_FALSE(v.PrepareDatabase()); 2966 ASSERT_FALSE(v.VerifyAllGoals()); 2967 } 2968 2969 TEST_P(VerifierMarkedSourceUnitTest, ConflictingCodeFactsIgnoreWellFormed) { 2970 Verifier v; 2971 ConfigureVerifier(v); 2972 v.IgnoreCodeConflicts(); 2973 MarkedSource source; 2974 MarkedSource source_conflict; 2975 source_conflict.set_pre_text("pre_text"); 2976 ASSERT_TRUE( 2977 v.LoadInlineProtoFile(Entries(source) + "\n" + Entries(source_conflict))); 2978 ASSERT_TRUE(v.PrepareDatabase()); 2979 ASSERT_TRUE(v.VerifyAllGoals()); 2980 } 2981 2982 INSTANTIATE_TEST_SUITE_P( 2983 JsonAndProto, VerifierMarkedSourceUnitTest, 2984 ::testing::Combine(::testing::Values(MsFormat::kTextProto, MsFormat::kJson), 2985 ::testing::Values(Solver::Old, Solver::New)), 2986 [](const auto& p) { 2987 if (std::get<0>(p.param) == MsFormat::kTextProto) 2988 return std::get<1>(p.param) == Solver::Old ? "textold" : "textnew"; 2989 else 2990 return std::get<1>(p.param) == Solver::Old ? "jsonold" : "jsonnew"; 2991 }); 2992 2993 } // anonymous namespace 2994 } // namespace verifier 2995 } // namespace kythe 2996 2997 int main(int argc, char** argv) { 2998 GOOGLE_PROTOBUF_VERIFY_VERSION; 2999 ::absl::InitializeLog(); 3000 ::testing::InitGoogleTest(&argc, argv); 3001 return RUN_ALL_TESTS(); 3002 }