blob: 249392eb22882e6efe8e8eb9f18176e75b9a7cd8 [file] [log] [blame]
peter klausler3338ef92021-07-23 16:41:04 -07001//===- unittests/Frontend/FrontendActionTest.cpp FrontendAction tests-----===//
Caroline Concattod28de0d2020-10-27 12:26:47 +00002//
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
Caroline Concattod28de0d2020-10-27 12:26:47 +00009#include "flang/Frontend/CompilerInstance.h"
Andrzej Warzynski44e74c72020-12-22 11:07:58 +000010#include "flang/Frontend/CompilerInvocation.h"
Caroline Concattod28de0d2020-10-27 12:26:47 +000011#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
Andrzej Warzynskib564b122021-01-20 18:27:04 +000016#include "gtest/gtest.h"
17
Caroline Concattod28de0d2020-10-27 12:26:47 +000018using namespace Fortran::frontend;
19
20namespace {
21
Andrzej Warzynski44e74c72020-12-22 11:07:58 +000022class FrontendActionTest : public ::testing::Test {
23protected:
24 // AllSources (which is used to manage files inside every compiler
25 // instance), works with paths. So we need a filename and a path for the
26 // input file.
27 // TODO: We could use `-` for inputFilePath_, but then we'd need a way to
28 // write to stdin that's then read by AllSources. Ideally, AllSources should
29 // be capable of reading from any stream.
30 std::string inputFileName_;
31 std::string inputFilePath_;
32 // The output stream for the input file. Use this to populate the input.
33 std::unique_ptr<llvm::raw_fd_ostream> inputFileOs_;
Caroline Concattod28de0d2020-10-27 12:26:47 +000034
Andrzej Warzynski44e74c72020-12-22 11:07:58 +000035 std::error_code ec_;
Caroline Concattod28de0d2020-10-27 12:26:47 +000036
Andrzej Warzynski44e74c72020-12-22 11:07:58 +000037 CompilerInstance compInst_;
38 std::shared_ptr<CompilerInvocation> invocation_;
39
40 void SetUp() override {
41 // Generate a unique test file name.
42 const testing::TestInfo *const test_info =
43 testing::UnitTest::GetInstance()->current_test_info();
Faris Rehman443d6952021-01-04 16:49:33 +000044 inputFileName_ = std::string(test_info->name()) + "_test-file.f90";
Andrzej Warzynski44e74c72020-12-22 11:07:58 +000045
46 // Create the input file stream. Note that this stream is populated
47 // separately in every test (i.e. the input is test specific).
48 inputFileOs_ = std::make_unique<llvm::raw_fd_ostream>(
49 inputFileName_, ec_, llvm::sys::fs::OF_None);
50 if (ec_)
51 FAIL() << "Failed to create the input file";
52
53 // Get the path of the input file.
54 llvm::SmallString<256> cwd;
55 if (std::error_code ec_ = llvm::sys::fs::current_path(cwd))
56 FAIL() << "Failed to obtain the current working directory";
57 inputFilePath_ = cwd.c_str();
58 inputFilePath_ += "/" + inputFileName_;
59
60 // Prepare the compiler (CompilerInvocation + CompilerInstance)
61 compInst_.CreateDiagnostics();
62 invocation_ = std::make_shared<CompilerInvocation>();
63
64 compInst_.set_invocation(std::move(invocation_));
Andrzej Warzynski23d4c4f2021-07-29 12:39:10 +000065 compInst_.frontendOpts().inputs.push_back(
Andrzej Warzynski44e74c72020-12-22 11:07:58 +000066 FrontendInputFile(inputFilePath_, Language::Fortran));
67 }
68
69 void TearDown() override {
70 // Clear the input file.
71 llvm::sys::fs::remove(inputFileName_);
72
73 // Clear the output files.
74 // Note that these tests use an output buffer (as opposed to an output
75 // file), hence there are no physical output files to delete and
76 // `EraseFiles` is set to `false`. Also, some actions (e.g.
77 // `ParseSyntaxOnly`) don't generated output. In such cases there's no
78 // output to clear and `ClearOutputFile` returns immediately.
79 compInst_.ClearOutputFiles(/*EraseFiles=*/false);
80 }
81};
82
Andrzej Warzynskib564b122021-01-20 18:27:04 +000083TEST_F(FrontendActionTest, TestInputOutput) {
84 // Populate the input file with the pre-defined input and flush it.
85 *(inputFileOs_) << "End Program arithmetic";
86 inputFileOs_.reset();
87
88 // Set-up the action kind.
Andrzej Warzynski23d4c4f2021-07-29 12:39:10 +000089 compInst_.invocation().frontendOpts().programAction = InputOutputTest;
Andrzej Warzynskib564b122021-01-20 18:27:04 +000090
91 // Set-up the output stream. Using output buffer wrapped as an output
92 // stream, as opposed to an actual file (or a file descriptor).
93 llvm::SmallVector<char, 256> outputFileBuffer;
94 std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(
95 new llvm::raw_svector_ostream(outputFileBuffer));
96 compInst_.set_outputStream(std::move(outputFileStream));
97
98 // Execute the action.
99 bool success = ExecuteCompilerInvocation(&compInst_);
100
101 // Validate the expected output.
102 EXPECT_TRUE(success);
103 EXPECT_TRUE(!outputFileBuffer.empty());
104 EXPECT_TRUE(llvm::StringRef(outputFileBuffer.data())
105 .startswith("End Program arithmetic"));
106}
107
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000108TEST_F(FrontendActionTest, PrintPreprocessedInput) {
Caroline Concattod28de0d2020-10-27 12:26:47 +0000109 // Populate the input file with the pre-defined input and flush it.
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000110 *(inputFileOs_) << "#ifdef NEW\n"
111 << " Program A \n"
112 << "#else\n"
113 << " Program B\n"
114 << "#endif";
115 inputFileOs_.reset();
Caroline Concattod28de0d2020-10-27 12:26:47 +0000116
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000117 // Set-up the action kind.
Andrzej Warzynski23d4c4f2021-07-29 12:39:10 +0000118 compInst_.invocation().frontendOpts().programAction = PrintPreprocessedInput;
peter klausler3338ef92021-07-23 16:41:04 -0700119 compInst_.invocation().preprocessorOpts().noReformat = true;
Caroline Concattod28de0d2020-10-27 12:26:47 +0000120
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000121 // Set-up the output stream. We are using output buffer wrapped as an output
Caroline Concattod28de0d2020-10-27 12:26:47 +0000122 // stream, as opposed to an actual file (or a file descriptor).
123 llvm::SmallVector<char, 256> outputFileBuffer;
124 std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(
125 new llvm::raw_svector_ostream(outputFileBuffer));
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000126 compInst_.set_outputStream(std::move(outputFileStream));
Caroline Concattod28de0d2020-10-27 12:26:47 +0000127
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000128 // Execute the action.
129 bool success = ExecuteCompilerInvocation(&compInst_);
Caroline Concattod28de0d2020-10-27 12:26:47 +0000130
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000131 // Validate the expected output.
Caroline Concattod28de0d2020-10-27 12:26:47 +0000132 EXPECT_TRUE(success);
133 EXPECT_TRUE(!outputFileBuffer.empty());
134 EXPECT_TRUE(
135 llvm::StringRef(outputFileBuffer.data()).startswith("program b\n"));
Caroline Concattod28de0d2020-10-27 12:26:47 +0000136}
Andrzej Warzynski7d246cb2020-12-08 16:27:46 +0000137
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000138TEST_F(FrontendActionTest, ParseSyntaxOnly) {
Andrzej Warzynski7d246cb2020-12-08 16:27:46 +0000139 // Populate the input file with the pre-defined input and flush it.
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000140 *(inputFileOs_) << "IF (A > 0.0) IF (B < 0.0) A = LOG (A)\n"
141 << "END";
142 inputFileOs_.reset();
Andrzej Warzynski7d246cb2020-12-08 16:27:46 +0000143
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000144 // Set-up the action kind.
Andrzej Warzynski23d4c4f2021-07-29 12:39:10 +0000145 compInst_.invocation().frontendOpts().programAction = ParseSyntaxOnly;
Andrzej Warzynski7d246cb2020-12-08 16:27:46 +0000146
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000147 // Set-up the output stream for the semantic diagnostics.
Andrzej Warzynski7d246cb2020-12-08 16:27:46 +0000148 llvm::SmallVector<char, 256> outputDiagBuffer;
149 std::unique_ptr<llvm::raw_pwrite_stream> outputStream(
150 new llvm::raw_svector_ostream(outputDiagBuffer));
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000151 compInst_.set_semaOutputStream(std::move(outputStream));
Andrzej Warzynski7d246cb2020-12-08 16:27:46 +0000152
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000153 // Execute the action.
154 bool success = ExecuteCompilerInvocation(&compInst_);
Andrzej Warzynski7d246cb2020-12-08 16:27:46 +0000155
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000156 // Validate the expected output.
Andrzej Warzynski7d246cb2020-12-08 16:27:46 +0000157 EXPECT_FALSE(success);
158 EXPECT_TRUE(!outputDiagBuffer.empty());
159 EXPECT_TRUE(
160 llvm::StringRef(outputDiagBuffer.data())
peter klausler6110e772021-01-26 13:57:44 -0800161 .contains(
Andrzej Warzynski44e74c72020-12-22 11:07:58 +0000162 ":1:14: error: IF statement is not allowed in IF statement\n"));
Andrzej Warzynski7d246cb2020-12-08 16:27:46 +0000163}
Caroline Concattod28de0d2020-10-27 12:26:47 +0000164} // namespace