Files
carbon-lang/testing/file_test/file_test_base_test.cpp
T
Chandler CarruthandJon Ross-Perkins d3a5b0eee7 Add utilities for managing a toolchain install, and install and use LLD. (#3993)
The install directory contains the BUILD logic for creating an
installable tree of data files and executables for the toolchain, and
a library to facilitate toolchain code accessing the paths to their data
within this installation.

Then adds an installation of LLD in a synthetic LLVM installation, and
teaches the Clang runner to configure this and use it for linking
instead of the system linker.

Currently, the install paths only really manage access to the LLVM
binaries installed and used by the Clang runner for linking, but
eventually other data files like the prelude and runtime libraries will
be fleshed out as well. There are TODOs for moving more things over here
such as the prelude.

One interesting aspect of this is where to put helpers like parts of
LLVM in our install. This PR suggests nesting those files under
`lib/carbon`. While using a `lib` subdirectory isn't a perfect fit for
the FHS (Filesystem Hierarchy Standard), having a single location where
private data is collected is significantly superior to spreading them
across the system. This also matches similar patterns used by Clang
itself and several other language toolchains and standard libraries.

The install directory also provides a natural place for us to build out
packaging rules to create installable packages in various formats, but
that remains future work.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2024-06-01 03:19:52 +00:00

168 lines
6.4 KiB
C++

// 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/file_test_base.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "common/ostream.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/FormatVariadic.h"
namespace Carbon::Testing {
namespace {
class FileTestBaseTest : public FileTestBase {
public:
FileTestBaseTest(llvm::StringRef /*exe_path*/, llvm::StringRef test_name)
: FileTestBase(test_name) {}
auto Run(const llvm::SmallVector<llvm::StringRef>& test_args,
llvm::vfs::InMemoryFileSystem& fs, llvm::raw_pwrite_stream& stdout,
llvm::raw_pwrite_stream& stderr) -> ErrorOr<RunResult> override {
llvm::ArrayRef<llvm::StringRef> args = test_args;
llvm::ListSeparator sep;
stdout << args.size() << " args: ";
for (auto arg : args) {
stdout << sep << "`" << arg << "`";
}
stdout << "\n";
auto filename = std::filesystem::path(test_name().str()).filename();
if (filename == "args.carbon") {
// 'args.carbon' has custom arguments, so don't do regular argument
// validation for it.
return {{.success = true}};
}
if (args.empty() || args.front() != "default_args") {
return ErrorBuilder() << "missing `default_args` argument";
}
args = args.drop_front();
for (auto arg : args) {
if (!fs.exists(arg)) {
return ErrorBuilder() << "Missing file: " << arg;
}
}
if (filename == "example.carbon") {
int delta_line = 10;
stdout << "something\n"
<< "\n"
<< "example.carbon:" << delta_line + 1 << ": Line delta\n"
<< "example.carbon:" << delta_line << ": Negative line delta\n"
<< "+*[]{}\n"
<< "Foo baz\n";
return {{.success = true}};
} else if (filename == "fail_example.carbon") {
stderr << "Oops\n";
return {{.success = false}};
} else if (filename == "two_files.carbon" ||
filename == "not_split.carbon") {
for (auto arg : args) {
// Describe file contents to stdout to validate splitting.
auto file = fs.getBufferForFile(arg, /*FileSize=*/-1,
/*RequiresNullTerminator=*/false);
if (file.getError()) {
return Error(file.getError().message());
}
llvm::StringRef content = file.get()->getBuffer();
stdout << arg << ":1: starts with \"";
stdout.write_escaped(content.take_front(40));
stdout << "\", length " << content.count('\n') << " lines\n";
}
return {{.success = true}};
} else if (filename == "alternating_files.carbon") {
stdout << "unattached message 1\n"
<< "a.carbon:2: message 2\n"
<< "b.carbon:5: message 3\n"
<< "a.carbon:2: message 4\n"
<< "b.carbon:5: message 5\n"
<< "unattached message 6\n";
stderr << "unattached message 1\n"
<< "a.carbon:2: message 2\n"
<< "b.carbon:5: message 3\n"
<< "a.carbon:2: message 4\n"
<< "b.carbon:5: message 5\n"
<< "unattached message 6\n";
return {{.success = true}};
} else if (filename == "unattached_multi_file.carbon") {
stdout << "unattached message 1\n"
<< "unattached message 2\n";
stderr << "unattached message 3\n"
<< "unattached message 4\n";
return {{.success = true}};
} else if (filename == "file_only_re_one_file.carbon") {
stdout << "unattached message 1\n"
<< "file: file_only_re_one_file.carbon\n"
<< "line: 1\n"
<< "unattached message 2\n";
return {{.success = true}};
} else if (filename == "file_only_re_multi_file.carbon") {
int msg_count = 0;
stdout << "unattached message " << ++msg_count << "\n"
<< "file: a.carbon\n"
<< "unattached message " << ++msg_count << "\n"
<< "line: 3: attached message " << ++msg_count << "\n"
<< "unattached message " << ++msg_count << "\n"
<< "line: 8: late message " << ++msg_count << "\n"
<< "unattached message " << ++msg_count << "\n"
<< "file: b.carbon\n"
<< "line: 2: attached message " << ++msg_count << "\n"
<< "unattached message " << ++msg_count << "\n"
<< "line: 7: late message " << ++msg_count << "\n"
<< "unattached message " << ++msg_count << "\n";
return {{.success = true}};
} else if (filename == "fail_multi_success_overall_fail.carbon") {
RunResult result = {.success = false};
result.per_file_success.push_back({"a.carbon", true});
result.per_file_success.push_back({"b.carbon", true});
return result;
} else if (filename == "multi_success.carbon") {
RunResult result = {.success = true};
result.per_file_success.push_back({"a.carbon", true});
result.per_file_success.push_back({"b.carbon", true});
return result;
} else if (filename == "multi_success_and_fail.carbon") {
RunResult result = {.success = false};
result.per_file_success.push_back({"a.carbon", true});
result.per_file_success.push_back({"fail_b.carbon", false});
return result;
} else {
return ErrorBuilder() << "Unexpected file: " << filename;
}
}
auto GetDefaultArgs() -> llvm::SmallVector<std::string> override {
return {"default_args", "%s"};
}
auto GetDefaultFileRE(llvm::ArrayRef<llvm::StringRef> filenames)
-> std::optional<RE2> override {
return std::make_optional<RE2>(
llvm::formatv(R"(file: ({0}))", llvm::join(filenames, "|")));
}
auto GetLineNumberReplacements(llvm::ArrayRef<llvm::StringRef> filenames)
-> llvm::SmallVector<LineNumberReplacement> override {
auto replacements = FileTestBase::GetLineNumberReplacements(filenames);
auto filename = std::filesystem::path(test_name().str()).filename();
if (llvm::StringRef(filename).starts_with("file_only_re_")) {
replacements.push_back({.has_file = false,
.re = std::make_shared<RE2>(R"(line: (\d+))"),
.line_formatv = "{0}"});
}
return replacements;
}
};
} // namespace
CARBON_FILE_TEST_FACTORY(FileTestBaseTest);
} // namespace Carbon::Testing