// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "testing/file_test/test_file.h" #include #include #include "common/error_test_helpers.h" #include "testing/base/file_helpers.h" #include "testing/file_test/file_test_base.h" // The current BUILD structure of this library means that in order to unit-test // test_file.h, we have to pretend to be a file_test. That means there has to // be a definition of CarbonFileTestManifest (normally generated by a file_test // Bazel rule), and there has to be a registered FileTestFactory, so we define // them both as dummies. // TODO: restructure BUILD rules to avoid the need for this hack. // Dummy empty manifest. // NOLINTNEXTLINE(readability-identifier-naming): manifest.cpp dictates spelling const char* CarbonFileTestManifest[] = {nullptr}; namespace Carbon::Testing { // Dummy unusable FileTestBase. class DummyFileTest : public FileTestBase { public: DummyFileTest(llvm::StringRef /*exe_path*/, llvm::StringRef test_name) : FileTestBase(test_name) {} auto Run(const llvm::SmallVector& /*test_args*/, llvm::IntrusiveRefCntPtr& /*fs*/, FILE* /*input_stream*/, llvm::raw_pwrite_stream& /*output_stream*/, llvm::raw_pwrite_stream& /*error_stream*/) const -> ErrorOr override { CARBON_FATAL("Called method of dummy object"); } auto GetDefaultArgs() const -> llvm::SmallVector override { CARBON_FATAL("Called method of dummy object"); } }; CARBON_FILE_TEST_FACTORY(DummyFileTest) namespace { using ::testing::_; using ::testing::StrEq; // Returns the non-check lines of test_file as a string. auto NonCheckFileContents(const TestFile& test_file) -> std::string { std::string buffer; llvm::raw_string_ostream out(buffer); for (const auto& line : test_file.non_check_lines) { line.Print(out); out << "\n"; } return buffer; } // Returns a string consisting of 7 repetitions of `c`, for use as a simulated // merge conflict marker. We use this in test inputs instead of writing the // conflict markers directly in the string literals so that tools don't treat // them as genuine merge conflicts in this file. auto Marker(char c) -> std::string { return std::string(7, c); } TEST(AutoupdateTest, SnapshotMergeConflict) { std::string initial_contents = R"( // AUTOUPDATE Some text )" + Marker('<') + R"( // CHECK:STDOUT: side 1 )" + Marker('=') + R"( // CHECK:STDOUT: side 2 )" + Marker('>') + R"( More text )"; constexpr std::string_view ExpectedContents = R"( // AUTOUPDATE Some text More text )"; auto file_path = *WriteTestFile("tmp", initial_contents); auto test_file = ProcessTestFile(file_path.c_str(), /*running_autoupdate=*/true); ASSERT_THAT(test_file, IsSuccess(_)) << test_file.error(); EXPECT_THAT(NonCheckFileContents(*test_file), StrEq(ExpectedContents)); } TEST(AutoupdateTest, SnapshotTheeWayMergeConflict) { std::string initial_contents = R"( // AUTOUPDATE Some text )" + Marker('<') + R"( // CHECK:STDOUT: side 1 )" + Marker('|') + R"( // CHECK:STDOUT: base )" + Marker('=') + R"( // CHECK:STDOUT: side 2 )" + Marker('>') + R"( More text )"; constexpr std::string_view ExpectedContents = R"( // AUTOUPDATE Some text More text )"; auto file_path = *WriteTestFile("tmp", initial_contents); auto test_file = ProcessTestFile(file_path.c_str(), /*running_autoupdate=*/true); ASSERT_THAT(test_file, IsSuccess(_)) << test_file.error(); EXPECT_THAT(NonCheckFileContents(*test_file), StrEq(ExpectedContents)); } TEST(AutoupdateTest, DiffMergeConflict) { std::string initial_contents = R"( // AUTOUPDATE Some text )" + Marker('<') + R"( )" + Marker('%') + R"( )" + Marker('\\') + R"( // CHECK:STDOUT: unchanged -// CHECK:STDOUT: base +// CHECK:STDOUT: side 1 )" + Marker('+') + R"( // CHECK:STDOUT: side 2 )" + Marker('>') + R"( More text )"; constexpr std::string_view ExpectedContents = R"( // AUTOUPDATE Some text More text )"; auto file_path = *WriteTestFile("tmp", initial_contents); auto test_file = ProcessTestFile(file_path.c_str(), /*running_autoupdate=*/true); ASSERT_THAT(test_file, IsSuccess(_)) << test_file.error(); EXPECT_THAT(NonCheckFileContents(*test_file), StrEq(ExpectedContents)); } TEST(AutoupdateTest, NonCheckInDiffRegion) { std::string initial_contents = R"( // AUTOUPDATE Some text )" + Marker('<') + R"( )" + Marker('%') + R"( )" + Marker('\\') + R"( // unchanged -// CHECK:STDOUT: base +// CHECK:STDOUT: side 1 )" + Marker('+') + R"( // CHECK:STDOUT: side 2 )" + Marker('>') + R"( More text )"; auto file_path = *WriteTestFile("tmp", initial_contents); auto test_file = ProcessTestFile(file_path.c_str(), /*running_autoupdate=*/true); ASSERT_THAT(test_file, IsError(_)); } } // namespace } // namespace Carbon::Testing