From: Andrzej Warzynski Date: Tue, 22 Dec 2020 11:07:58 +0000 (+0000) Subject: [flang][driver] Refactor unit tests for frontend actions (nfc) X-Git-Tag: llvmorg-13-init~2743 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=44e74c75e614af453f4824cb9bf1f0056d7cf426;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/flang/unittests/Frontend/FrontendActionTest.cpp b/flang/unittests/Frontend/FrontendActionTest.cpp index b49b731..fb4de6d 100644 --- a/flang/unittests/Frontend/FrontendActionTest.cpp +++ b/flang/unittests/Frontend/FrontendActionTest.cpp @@ -8,6 +8,7 @@ #include "gtest/gtest.h" #include "flang/Frontend/CompilerInstance.h" +#include "flang/Frontend/CompilerInvocation.h" #include "flang/Frontend/FrontendOptions.h" #include "flang/FrontendTool/Utils.h" #include "llvm/Support/FileSystem.h" @@ -17,119 +18,120 @@ using namespace Fortran::frontend; namespace { -TEST(FrontendAction, PrintPreprocessedInput) { - std::string inputFile = "pp-test-file.f"; - std::error_code ec; +class FrontendActionTest : public ::testing::Test { +protected: + // AllSources (which is used to manage files inside every compiler + // instance), works with paths. So we need a filename and a path for the + // input file. + // TODO: We could use `-` for inputFilePath_, but then we'd need a way to + // write to stdin that's then read by AllSources. Ideally, AllSources should + // be capable of reading from any stream. + std::string inputFileName_; + std::string inputFilePath_; + // The output stream for the input file. Use this to populate the input. + std::unique_ptr inputFileOs_; + + std::error_code ec_; + + CompilerInstance compInst_; + std::shared_ptr invocation_; + + void SetUp() override { + // Generate a unique test file name. + const testing::TestInfo *const test_info = + testing::UnitTest::GetInstance()->current_test_info(); + inputFileName_ = std::string(test_info->name()) + "_test-file.f"; + + // Create the input file stream. Note that this stream is populated + // separately in every test (i.e. the input is test specific). + inputFileOs_ = std::make_unique( + inputFileName_, ec_, llvm::sys::fs::OF_None); + if (ec_) + FAIL() << "Failed to create the input file"; + + // Get the path of the input file. + llvm::SmallString<256> cwd; + if (std::error_code ec_ = llvm::sys::fs::current_path(cwd)) + FAIL() << "Failed to obtain the current working directory"; + inputFilePath_ = cwd.c_str(); + inputFilePath_ += "/" + inputFileName_; + + // Prepare the compiler (CompilerInvocation + CompilerInstance) + compInst_.CreateDiagnostics(); + invocation_ = std::make_shared(); + + compInst_.set_invocation(std::move(invocation_)); + compInst_.frontendOpts().inputs_.push_back( + FrontendInputFile(inputFilePath_, Language::Fortran)); + } + + void TearDown() override { + // Clear the input file. + llvm::sys::fs::remove(inputFileName_); + + // Clear the output files. + // Note that these tests use an output buffer (as opposed to an output + // file), hence there are no physical output files to delete and + // `EraseFiles` is set to `false`. Also, some actions (e.g. + // `ParseSyntaxOnly`) don't generated output. In such cases there's no + // output to clear and `ClearOutputFile` returns immediately. + compInst_.ClearOutputFiles(/*EraseFiles=*/false); + } +}; + +TEST_F(FrontendActionTest, PrintPreprocessedInput) { + // Populate the input file with the pre-defined input and flush it. + *(inputFileOs_) << "#ifdef NEW\n" + << " Program A \n" + << "#else\n" + << " Program B\n" + << "#endif"; + inputFileOs_.reset(); - // 1. Create the input file for the file manager - // AllSources (which is used to manage files inside every compiler instance), - // works with paths. This means that it requires a physical file. Create one. - std::unique_ptr os{ - new llvm::raw_fd_ostream(inputFile, ec, llvm::sys::fs::OF_None)}; - if (ec) - FAIL() << "Fail to create the file need by the test"; + // Set-up the action kind. + compInst_.invocation().frontendOpts().programAction_ = PrintPreprocessedInput; - // Populate the input file with the pre-defined input and flush it. - *(os) << "! test-file.F:\n" - << "#ifdef NEW\n" - << " Program A \n" - << "#else\n" - << " Program B\n" - << "#endif"; - os.reset(); - - // Get the path of the input file - llvm::SmallString<64> cwd; - if (std::error_code ec = llvm::sys::fs::current_path(cwd)) - FAIL() << "Failed to obtain the current working directory"; - std::string testFilePath(cwd.c_str()); - testFilePath += "/" + inputFile; - - // 2. Prepare the compiler (CompilerInvocation + CompilerInstance) - CompilerInstance compInst; - compInst.CreateDiagnostics(); - auto invocation = std::make_shared(); - invocation->frontendOpts().programAction_ = PrintPreprocessedInput; - - compInst.set_invocation(std::move(invocation)); - compInst.frontendOpts().inputs_.push_back( - FrontendInputFile(testFilePath, Language::Fortran)); - - // 3. Set-up the output stream. Using output buffer wrapped as an output + // Set-up the output stream. We are using output buffer wrapped as an output // stream, as opposed to an actual file (or a file descriptor). llvm::SmallVector outputFileBuffer; std::unique_ptr outputFileStream( new llvm::raw_svector_ostream(outputFileBuffer)); - compInst.set_outputStream(std::move(outputFileStream)); + compInst_.set_outputStream(std::move(outputFileStream)); - // 4. Run the earlier defined FrontendAction - bool success = ExecuteCompilerInvocation(&compInst); + // Execute the action. + bool success = ExecuteCompilerInvocation(&compInst_); - // 5. Validate the expected output + // Validate the expected output. EXPECT_TRUE(success); EXPECT_TRUE(!outputFileBuffer.empty()); EXPECT_TRUE( llvm::StringRef(outputFileBuffer.data()).startswith("program b\n")); - - // 6. Clear the input and the output files. Since we used an output buffer, - // there are no physical output files to delete. - llvm::sys::fs::remove(inputFile); - compInst.ClearOutputFiles(/*EraseFiles=*/true); } -TEST(FrontendAction, ParseSyntaxOnly) { - std::string inputFile = "syntax-only-test-file.f"; - std::error_code ec; +TEST_F(FrontendActionTest, ParseSyntaxOnly) { + // Populate the input file with the pre-defined input and flush it. + *(inputFileOs_) << "IF (A > 0.0) IF (B < 0.0) A = LOG (A)\n" + << "END"; + inputFileOs_.reset(); - // 1. Create the input file for the file manager - // AllSources (which is used to manage files inside every compiler instance), - // works with paths. This means that it requires a physical file. Create one. - std::unique_ptr os{ - new llvm::raw_fd_ostream(inputFile, ec, llvm::sys::fs::OF_None)}; - if (ec) - FAIL() << "Fail to create the file need by the test"; + // Set-up the action kind. + compInst_.invocation().frontendOpts().programAction_ = ParseSyntaxOnly; - // Populate the input file with the pre-defined input and flush it. - *(os) << "! if_stmt.f90:\n" - << "IF (A > 0.0) IF (B < 0.0) A = LOG (A)\n" - << "END"; - os.reset(); - - // Get the path of the input file - llvm::SmallString<64> cwd; - if (std::error_code ec = llvm::sys::fs::current_path(cwd)) - FAIL() << "Failed to obtain the current working directory"; - std::string testFilePath(cwd.c_str()); - testFilePath += "/" + inputFile; - - // 2. Prepare the compiler (CompilerInvocation + CompilerInstance) - CompilerInstance compInst; - compInst.CreateDiagnostics(); - auto invocation = std::make_shared(); - invocation->frontendOpts().programAction_ = ParseSyntaxOnly; - - compInst.set_invocation(std::move(invocation)); - compInst.frontendOpts().inputs_.push_back( - FrontendInputFile(testFilePath, Language::Fortran)); - - // 3. Set-up the output stream for the semantic diagnostics. + // Set-up the output stream for the semantic diagnostics. llvm::SmallVector outputDiagBuffer; std::unique_ptr outputStream( new llvm::raw_svector_ostream(outputDiagBuffer)); - compInst.set_semaOutputStream(std::move(outputStream)); + compInst_.set_semaOutputStream(std::move(outputStream)); - // 4. Execute the ParseSyntaxOnly action - bool success = ExecuteCompilerInvocation(&compInst); + // Execute the action. + bool success = ExecuteCompilerInvocation(&compInst_); - // 5. Validate the expected output + // Validate the expected output. EXPECT_FALSE(success); EXPECT_TRUE(!outputDiagBuffer.empty()); EXPECT_TRUE( llvm::StringRef(outputDiagBuffer.data()) .startswith( - ":2:14: error: IF statement is not allowed in IF statement\n")); - - // 6. Clear the input files. - llvm::sys::fs::remove(inputFile); + ":1:14: error: IF statement is not allowed in IF statement\n")); } } // namespace