Skip to content

Commit 44e74c7

Browse files
committed
[flang][driver] Refactor unit tests for frontend actions (nfc)
These patch implements a few non-functional-changes: * switch to using test fixtures for better code sharing * rename some variables (e.g. to communicate their purpose a bit better) This patch doesn't change _what_ is being tested. Differential Revision: https://reviews.llvm.org/D93544
1 parent c4fc8a2 commit 44e74c7

File tree

1 file changed

+90
-88
lines changed

1 file changed

+90
-88
lines changed

flang/unittests/Frontend/FrontendActionTest.cpp

Lines changed: 90 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "gtest/gtest.h"
1010
#include "flang/Frontend/CompilerInstance.h"
11+
#include "flang/Frontend/CompilerInvocation.h"
1112
#include "flang/Frontend/FrontendOptions.h"
1213
#include "flang/FrontendTool/Utils.h"
1314
#include "llvm/Support/FileSystem.h"
@@ -17,119 +18,120 @@ using namespace Fortran::frontend;
1718

1819
namespace {
1920

20-
TEST(FrontendAction, PrintPreprocessedInput) {
21-
std::string inputFile = "pp-test-file.f";
22-
std::error_code ec;
21+
class FrontendActionTest : public ::testing::Test {
22+
protected:
23+
// AllSources (which is used to manage files inside every compiler
24+
// instance), works with paths. So we need a filename and a path for the
25+
// input file.
26+
// TODO: We could use `-` for inputFilePath_, but then we'd need a way to
27+
// write to stdin that's then read by AllSources. Ideally, AllSources should
28+
// be capable of reading from any stream.
29+
std::string inputFileName_;
30+
std::string inputFilePath_;
31+
// The output stream for the input file. Use this to populate the input.
32+
std::unique_ptr<llvm::raw_fd_ostream> inputFileOs_;
33+
34+
std::error_code ec_;
35+
36+
CompilerInstance compInst_;
37+
std::shared_ptr<CompilerInvocation> invocation_;
38+
39+
void SetUp() override {
40+
// Generate a unique test file name.
41+
const testing::TestInfo *const test_info =
42+
testing::UnitTest::GetInstance()->current_test_info();
43+
inputFileName_ = std::string(test_info->name()) + "_test-file.f";
44+
45+
// Create the input file stream. Note that this stream is populated
46+
// separately in every test (i.e. the input is test specific).
47+
inputFileOs_ = std::make_unique<llvm::raw_fd_ostream>(
48+
inputFileName_, ec_, llvm::sys::fs::OF_None);
49+
if (ec_)
50+
FAIL() << "Failed to create the input file";
51+
52+
// Get the path of the input file.
53+
llvm::SmallString<256> cwd;
54+
if (std::error_code ec_ = llvm::sys::fs::current_path(cwd))
55+
FAIL() << "Failed to obtain the current working directory";
56+
inputFilePath_ = cwd.c_str();
57+
inputFilePath_ += "/" + inputFileName_;
58+
59+
// Prepare the compiler (CompilerInvocation + CompilerInstance)
60+
compInst_.CreateDiagnostics();
61+
invocation_ = std::make_shared<CompilerInvocation>();
62+
63+
compInst_.set_invocation(std::move(invocation_));
64+
compInst_.frontendOpts().inputs_.push_back(
65+
FrontendInputFile(inputFilePath_, Language::Fortran));
66+
}
67+
68+
void TearDown() override {
69+
// Clear the input file.
70+
llvm::sys::fs::remove(inputFileName_);
71+
72+
// Clear the output files.
73+
// Note that these tests use an output buffer (as opposed to an output
74+
// file), hence there are no physical output files to delete and
75+
// `EraseFiles` is set to `false`. Also, some actions (e.g.
76+
// `ParseSyntaxOnly`) don't generated output. In such cases there's no
77+
// output to clear and `ClearOutputFile` returns immediately.
78+
compInst_.ClearOutputFiles(/*EraseFiles=*/false);
79+
}
80+
};
81+
82+
TEST_F(FrontendActionTest, PrintPreprocessedInput) {
83+
// Populate the input file with the pre-defined input and flush it.
84+
*(inputFileOs_) << "#ifdef NEW\n"
85+
<< " Program A \n"
86+
<< "#else\n"
87+
<< " Program B\n"
88+
<< "#endif";
89+
inputFileOs_.reset();
2390

24-
// 1. Create the input file for the file manager
25-
// AllSources (which is used to manage files inside every compiler instance),
26-
// works with paths. This means that it requires a physical file. Create one.
27-
std::unique_ptr<llvm::raw_fd_ostream> os{
28-
new llvm::raw_fd_ostream(inputFile, ec, llvm::sys::fs::OF_None)};
29-
if (ec)
30-
FAIL() << "Fail to create the file need by the test";
91+
// Set-up the action kind.
92+
compInst_.invocation().frontendOpts().programAction_ = PrintPreprocessedInput;
3193

32-
// Populate the input file with the pre-defined input and flush it.
33-
*(os) << "! test-file.F:\n"
34-
<< "#ifdef NEW\n"
35-
<< " Program A \n"
36-
<< "#else\n"
37-
<< " Program B\n"
38-
<< "#endif";
39-
os.reset();
40-
41-
// Get the path of the input file
42-
llvm::SmallString<64> cwd;
43-
if (std::error_code ec = llvm::sys::fs::current_path(cwd))
44-
FAIL() << "Failed to obtain the current working directory";
45-
std::string testFilePath(cwd.c_str());
46-
testFilePath += "/" + inputFile;
47-
48-
// 2. Prepare the compiler (CompilerInvocation + CompilerInstance)
49-
CompilerInstance compInst;
50-
compInst.CreateDiagnostics();
51-
auto invocation = std::make_shared<CompilerInvocation>();
52-
invocation->frontendOpts().programAction_ = PrintPreprocessedInput;
53-
54-
compInst.set_invocation(std::move(invocation));
55-
compInst.frontendOpts().inputs_.push_back(
56-
FrontendInputFile(testFilePath, Language::Fortran));
57-
58-
// 3. Set-up the output stream. Using output buffer wrapped as an output
94+
// Set-up the output stream. We are using output buffer wrapped as an output
5995
// stream, as opposed to an actual file (or a file descriptor).
6096
llvm::SmallVector<char, 256> outputFileBuffer;
6197
std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(
6298
new llvm::raw_svector_ostream(outputFileBuffer));
63-
compInst.set_outputStream(std::move(outputFileStream));
99+
compInst_.set_outputStream(std::move(outputFileStream));
64100

65-
// 4. Run the earlier defined FrontendAction
66-
bool success = ExecuteCompilerInvocation(&compInst);
101+
// Execute the action.
102+
bool success = ExecuteCompilerInvocation(&compInst_);
67103

68-
// 5. Validate the expected output
104+
// Validate the expected output.
69105
EXPECT_TRUE(success);
70106
EXPECT_TRUE(!outputFileBuffer.empty());
71107
EXPECT_TRUE(
72108
llvm::StringRef(outputFileBuffer.data()).startswith("program b\n"));
73-
74-
// 6. Clear the input and the output files. Since we used an output buffer,
75-
// there are no physical output files to delete.
76-
llvm::sys::fs::remove(inputFile);
77-
compInst.ClearOutputFiles(/*EraseFiles=*/true);
78109
}
79110

80-
TEST(FrontendAction, ParseSyntaxOnly) {
81-
std::string inputFile = "syntax-only-test-file.f";
82-
std::error_code ec;
111+
TEST_F(FrontendActionTest, ParseSyntaxOnly) {
112+
// Populate the input file with the pre-defined input and flush it.
113+
*(inputFileOs_) << "IF (A > 0.0) IF (B < 0.0) A = LOG (A)\n"
114+
<< "END";
115+
inputFileOs_.reset();
83116

84-
// 1. Create the input file for the file manager
85-
// AllSources (which is used to manage files inside every compiler instance),
86-
// works with paths. This means that it requires a physical file. Create one.
87-
std::unique_ptr<llvm::raw_fd_ostream> os{
88-
new llvm::raw_fd_ostream(inputFile, ec, llvm::sys::fs::OF_None)};
89-
if (ec)
90-
FAIL() << "Fail to create the file need by the test";
117+
// Set-up the action kind.
118+
compInst_.invocation().frontendOpts().programAction_ = ParseSyntaxOnly;
91119

92-
// Populate the input file with the pre-defined input and flush it.
93-
*(os) << "! if_stmt.f90:\n"
94-
<< "IF (A > 0.0) IF (B < 0.0) A = LOG (A)\n"
95-
<< "END";
96-
os.reset();
97-
98-
// Get the path of the input file
99-
llvm::SmallString<64> cwd;
100-
if (std::error_code ec = llvm::sys::fs::current_path(cwd))
101-
FAIL() << "Failed to obtain the current working directory";
102-
std::string testFilePath(cwd.c_str());
103-
testFilePath += "/" + inputFile;
104-
105-
// 2. Prepare the compiler (CompilerInvocation + CompilerInstance)
106-
CompilerInstance compInst;
107-
compInst.CreateDiagnostics();
108-
auto invocation = std::make_shared<CompilerInvocation>();
109-
invocation->frontendOpts().programAction_ = ParseSyntaxOnly;
110-
111-
compInst.set_invocation(std::move(invocation));
112-
compInst.frontendOpts().inputs_.push_back(
113-
FrontendInputFile(testFilePath, Language::Fortran));
114-
115-
// 3. Set-up the output stream for the semantic diagnostics.
120+
// Set-up the output stream for the semantic diagnostics.
116121
llvm::SmallVector<char, 256> outputDiagBuffer;
117122
std::unique_ptr<llvm::raw_pwrite_stream> outputStream(
118123
new llvm::raw_svector_ostream(outputDiagBuffer));
119-
compInst.set_semaOutputStream(std::move(outputStream));
124+
compInst_.set_semaOutputStream(std::move(outputStream));
120125

121-
// 4. Execute the ParseSyntaxOnly action
122-
bool success = ExecuteCompilerInvocation(&compInst);
126+
// Execute the action.
127+
bool success = ExecuteCompilerInvocation(&compInst_);
123128

124-
// 5. Validate the expected output
129+
// Validate the expected output.
125130
EXPECT_FALSE(success);
126131
EXPECT_TRUE(!outputDiagBuffer.empty());
127132
EXPECT_TRUE(
128133
llvm::StringRef(outputDiagBuffer.data())
129134
.startswith(
130-
":2:14: error: IF statement is not allowed in IF statement\n"));
131-
132-
// 6. Clear the input files.
133-
llvm::sys::fs::remove(inputFile);
135+
":1:14: error: IF statement is not allowed in IF statement\n"));
134136
}
135137
} // namespace

0 commit comments

Comments
 (0)