1 //===- unittests/Frontend/PrintPreprocessedTest.cpp  FrontendAction tests--===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "gtest/gtest.h"
10 #include "flang/Frontend/CompilerInstance.h"
11 #include "flang/Frontend/FrontendOptions.h"
12 #include "flang/FrontendTool/Utils.h"
13 #include "llvm/Support/FileSystem.h"
14 #include "llvm/Support/raw_ostream.h"
15 
16 using namespace Fortran::frontend;
17 
18 namespace {
19 
TEST(FrontendAction,PrintPreprocessedInput)20 TEST(FrontendAction, PrintPreprocessedInput) {
21   std::string inputFile = "test-file.f";
22   std::error_code ec;
23 
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";
31 
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
59   // stream, as opposed to an actual file (or a file descriptor).
60   llvm::SmallVector<char, 256> outputFileBuffer;
61   std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(
62       new llvm::raw_svector_ostream(outputFileBuffer));
63   compInst.set_outputStream(std::move(outputFileStream));
64 
65   // 4. Run the earlier defined FrontendAction
66   bool success = ExecuteCompilerInvocation(&compInst);
67 
68   // 5. Validate the expected output
69   EXPECT_TRUE(success);
70   EXPECT_TRUE(!outputFileBuffer.empty());
71   EXPECT_TRUE(
72       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);
78 }
79 } // namespace
80