mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 10:51:06 +01:00
Add support for testing with stdin (#4819)
In order to write language-server tests, we need some way to pass stdin input. This adds support for a split "// --- STDIN" which will be provided as a temp file for testing. Note this does more stdin -> input_stream style renaming, this is just bugging me more since I know shadowing works but it can be subtle to read, particularly since I'm now making direct use of stdin in a handful of spots.
This commit is contained in:
@@ -23,7 +23,8 @@ class FileTestBaseTest : public FileTestBase {
|
||||
|
||||
auto Run(const llvm::SmallVector<llvm::StringRef>& test_args,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem>& fs,
|
||||
llvm::raw_pwrite_stream& stdout, llvm::raw_pwrite_stream& stderr)
|
||||
FILE* input_stream, llvm::raw_pwrite_stream& output_stream,
|
||||
llvm::raw_pwrite_stream& error_stream)
|
||||
-> ErrorOr<RunResult> override;
|
||||
|
||||
auto GetArgReplacements() -> llvm::StringMap<std::string> override {
|
||||
@@ -55,13 +56,13 @@ class FileTestBaseTest : public FileTestBase {
|
||||
|
||||
// Prints arguments so that they can be validated in tests.
|
||||
static auto PrintArgs(llvm::ArrayRef<llvm::StringRef> args,
|
||||
llvm::raw_pwrite_stream& stdout) -> void {
|
||||
llvm::raw_pwrite_stream& output_stream) -> void {
|
||||
llvm::ListSeparator sep;
|
||||
stdout << args.size() << " args: ";
|
||||
output_stream << args.size() << " args: ";
|
||||
for (auto arg : args) {
|
||||
stdout << sep << "`" << arg << "`";
|
||||
output_stream << sep << "`" << arg << "`";
|
||||
}
|
||||
stdout << "\n";
|
||||
output_stream << "\n";
|
||||
}
|
||||
|
||||
// Verifies arguments are well-structured, and returns the files in them.
|
||||
@@ -85,113 +86,131 @@ static auto GetFilesFromArgs(llvm::ArrayRef<llvm::StringRef> args,
|
||||
struct TestParams {
|
||||
// These are the arguments to `Run()`.
|
||||
llvm::vfs::InMemoryFileSystem& fs;
|
||||
llvm::raw_pwrite_stream& stdout;
|
||||
llvm::raw_pwrite_stream& stderr;
|
||||
FILE* input_stream;
|
||||
llvm::raw_pwrite_stream& output_stream;
|
||||
llvm::raw_pwrite_stream& error_stream;
|
||||
|
||||
// This is assigned after construction.
|
||||
llvm::ArrayRef<llvm::StringRef> files;
|
||||
};
|
||||
|
||||
// Does printing and returns expected results for alternating_files.carbon.
|
||||
// Prints and returns expected results for alternating_files.carbon.
|
||||
static auto TestAlternatingFiles(TestParams& params)
|
||||
-> ErrorOr<FileTestBaseTest::RunResult> {
|
||||
params.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";
|
||||
params.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";
|
||||
params.output_stream << "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";
|
||||
params.error_stream << "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}};
|
||||
}
|
||||
|
||||
// Does printing and returns expected results for capture_console_output.carbon.
|
||||
// Prints and returns expected results for capture_console_output.carbon.
|
||||
static auto TestCaptureConsoleOutput(TestParams& params)
|
||||
-> ErrorOr<FileTestBaseTest::RunResult> {
|
||||
llvm::errs() << "llvm::errs\n";
|
||||
params.stderr << "params.stderr\n";
|
||||
params.error_stream << "params.error_stream\n";
|
||||
llvm::outs() << "llvm::outs\n";
|
||||
params.stdout << "params.stdout\n";
|
||||
params.output_stream << "params.output_stream\n";
|
||||
return {{.success = true}};
|
||||
}
|
||||
|
||||
// Does printing and returns expected results for example.carbon.
|
||||
// Prints and returns expected results for example.carbon.
|
||||
static auto TestExample(TestParams& params)
|
||||
-> ErrorOr<FileTestBaseTest::RunResult> {
|
||||
int delta_line = 10;
|
||||
params.stdout << "something\n"
|
||||
<< "\n"
|
||||
<< "example.carbon:" << delta_line + 1 << ": Line delta\n"
|
||||
<< "example.carbon:" << delta_line << ": Negative line delta\n"
|
||||
<< "+*[]{}\n"
|
||||
<< "Foo baz\n";
|
||||
params.output_stream << "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}};
|
||||
}
|
||||
|
||||
// Does printing and returns expected results for fail_example.carbon.
|
||||
// Prints and returns expected results for fail_example.carbon.
|
||||
static auto TestFailExample(TestParams& params)
|
||||
-> ErrorOr<FileTestBaseTest::RunResult> {
|
||||
params.stderr << "Oops\n";
|
||||
params.error_stream << "Oops\n";
|
||||
return {{.success = false}};
|
||||
}
|
||||
|
||||
// Does printing and returns expected results for
|
||||
// Prints and returns expected results for
|
||||
// file_only_re_multi_file.carbon.
|
||||
static auto TestFileOnlyREMultiFile(TestParams& params)
|
||||
-> ErrorOr<FileTestBaseTest::RunResult> {
|
||||
int msg_count = 0;
|
||||
params.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";
|
||||
params.output_stream << "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}};
|
||||
}
|
||||
|
||||
// Does printing and returns expected results for file_only_re_one_file.carbon.
|
||||
// Prints and returns expected results for file_only_re_one_file.carbon.
|
||||
static auto TestFileOnlyREOneFile(TestParams& params)
|
||||
-> ErrorOr<FileTestBaseTest::RunResult> {
|
||||
params.stdout << "unattached message 1\n"
|
||||
<< "file: file_only_re_one_file.carbon\n"
|
||||
<< "line: 1\n"
|
||||
<< "unattached message 2\n";
|
||||
params.output_stream << "unattached message 1\n"
|
||||
<< "file: file_only_re_one_file.carbon\n"
|
||||
<< "line: 1\n"
|
||||
<< "unattached message 2\n";
|
||||
return {{.success = true}};
|
||||
}
|
||||
|
||||
// Does printing and returns expected results for no_line_number.carbon.
|
||||
// Prints and returns expected results for no_line_number.carbon.
|
||||
static auto TestNoLineNumber(TestParams& params)
|
||||
-> ErrorOr<FileTestBaseTest::RunResult> {
|
||||
params.stdout << "a.carbon: msg1\n"
|
||||
"msg2\n"
|
||||
"b.carbon: msg3\n"
|
||||
"msg4\n"
|
||||
"a.carbon: msg5\n";
|
||||
params.output_stream << "a.carbon: msg1\n"
|
||||
"msg2\n"
|
||||
"b.carbon: msg3\n"
|
||||
"msg4\n"
|
||||
"a.carbon: msg5\n";
|
||||
return {{.success = true}};
|
||||
}
|
||||
|
||||
// Does printing and returns expected results for unattached_multi_file.carbon.
|
||||
// Prints and returns expected results for stdin.carbon.
|
||||
static auto TestStdin(TestParams& params)
|
||||
-> ErrorOr<FileTestBaseTest::RunResult> {
|
||||
CARBON_CHECK(params.input_stream);
|
||||
constexpr int ReadSize = 256;
|
||||
char buf[ReadSize];
|
||||
while (feof(params.input_stream) == 0) {
|
||||
auto read = fread(&buf, sizeof(char), ReadSize, params.input_stream);
|
||||
if (read > 0) {
|
||||
params.error_stream.write(buf, read);
|
||||
}
|
||||
}
|
||||
return {{.success = true}};
|
||||
}
|
||||
|
||||
// Prints and returns expected results for unattached_multi_file.carbon.
|
||||
static auto TestUnattachedMultiFile(TestParams& params)
|
||||
-> ErrorOr<FileTestBaseTest::RunResult> {
|
||||
params.stdout << "unattached message 1\n"
|
||||
<< "unattached message 2\n";
|
||||
params.stderr << "unattached message 3\n"
|
||||
<< "unattached message 4\n";
|
||||
params.output_stream << "unattached message 1\n"
|
||||
<< "unattached message 2\n";
|
||||
params.error_stream << "unattached message 3\n"
|
||||
<< "unattached message 4\n";
|
||||
return {{.success = true}};
|
||||
}
|
||||
|
||||
// Does printing and returns expected results for:
|
||||
// Prints and returns expected results for:
|
||||
// - fail_multi_success_overall_fail.carbon
|
||||
// - multi_success.carbon
|
||||
// - multi_success_and_fail.carbon
|
||||
@@ -220,8 +239,8 @@ static auto EchoFileContent(TestParams& params)
|
||||
for (int line_number = 1; !buffer.empty(); ++line_number) {
|
||||
auto [line, remainder] = buffer.split('\n');
|
||||
if (!line.empty() && !line.starts_with("//")) {
|
||||
params.stdout << test_file << ":" << line_number << ": " << line
|
||||
<< "\n";
|
||||
params.output_stream << test_file << ":" << line_number << ": " << line
|
||||
<< "\n";
|
||||
}
|
||||
buffer = remainder;
|
||||
}
|
||||
@@ -232,9 +251,9 @@ static auto EchoFileContent(TestParams& params)
|
||||
auto FileTestBaseTest::Run(
|
||||
const llvm::SmallVector<llvm::StringRef>& test_args,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem>& fs,
|
||||
llvm::raw_pwrite_stream& stdout, llvm::raw_pwrite_stream& stderr)
|
||||
-> ErrorOr<RunResult> {
|
||||
PrintArgs(test_args, stdout);
|
||||
FILE* input_stream, llvm::raw_pwrite_stream& output_stream,
|
||||
llvm::raw_pwrite_stream& error_stream) -> ErrorOr<RunResult> {
|
||||
PrintArgs(test_args, output_stream);
|
||||
|
||||
auto filename = std::filesystem::path(test_name().str()).filename();
|
||||
if (filename == "args.carbon") {
|
||||
@@ -254,6 +273,8 @@ auto FileTestBaseTest::Run(
|
||||
.Case("file_only_re_one_file.carbon", &TestFileOnlyREOneFile)
|
||||
.Case("file_only_re_multi_file.carbon", &TestFileOnlyREMultiFile)
|
||||
.Case("no_line_number.carbon", &TestNoLineNumber)
|
||||
.Case("stdin.carbon", &TestStdin)
|
||||
.Case("stdin_and_autoupdate_split.carbon", &TestStdin)
|
||||
.Case("unattached_multi_file.carbon", &TestUnattachedMultiFile)
|
||||
.Case("fail_multi_success_overall_fail.carbon",
|
||||
[&](TestParams&) {
|
||||
@@ -273,7 +294,10 @@ auto FileTestBaseTest::Run(
|
||||
.Default(&EchoFileContent);
|
||||
|
||||
// Call the appropriate test function for the file.
|
||||
TestParams params = {.fs = *fs, .stdout = stdout, .stderr = stderr};
|
||||
TestParams params = {.fs = *fs,
|
||||
.input_stream = input_stream,
|
||||
.output_stream = output_stream,
|
||||
.error_stream = error_stream};
|
||||
CARBON_ASSIGN_OR_RETURN(params.files, GetFilesFromArgs(test_args, *fs));
|
||||
return test_fn(params);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user