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
1819namespace {
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