diff --git a/flang/unittests/CMakeLists.txt b/flang/unittests/CMakeLists.txt --- a/flang/unittests/CMakeLists.txt +++ b/flang/unittests/CMakeLists.txt @@ -40,7 +40,6 @@ add_subdirectory(Decimal) add_subdirectory(Evaluate) add_subdirectory(Runtime) -add_subdirectory(RuntimeGTest) if (FLANG_BUILD_NEW_DRIVER) add_subdirectory(Frontend) diff --git a/flang/unittests/RuntimeGTest/BufferTest.cpp b/flang/unittests/Runtime/BufferTest.cpp rename from flang/unittests/RuntimeGTest/BufferTest.cpp rename to flang/unittests/Runtime/BufferTest.cpp diff --git a/flang/unittests/Runtime/CMakeLists.txt b/flang/unittests/Runtime/CMakeLists.txt --- a/flang/unittests/Runtime/CMakeLists.txt +++ b/flang/unittests/Runtime/CMakeLists.txt @@ -1,24 +1,23 @@ -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - -# RuntimeTesting needs exceptions enabled -set(LLVM_REQUIRES_EH ON) -set(LLVM_REQUIRES_RTTI ON) -add_library(RuntimeTesting - testing.cpp -) -llvm_update_compile_flags(RuntimeTesting) - -if (LLVM_LINK_LLVM_DYLIB) - set(llvm_libs LLVM) -else() - llvm_map_components_to_libnames(llvm_libs Support) -endif() -target_link_libraries(RuntimeTesting - FortranRuntime - ${llvm_libs} +add_flang_unittest(FlangRuntimeTests + BufferTest.cpp + CharacterTest.cpp + CrashHandlerFixture.cpp + ExternalIOTest.cpp + Format.cpp + ListInputTest.cpp + Matmul.cpp + MiscIntrinsic.cpp + Namelist.cpp + Numeric.cpp + NumericalFormatTest.cpp + Random.cpp + Reduction.cpp + RuntimeCrashTest.cpp + Time.cpp + Transformational.cpp ) -add_flang_nongtest_unittest(external-io - RuntimeTesting +target_link_libraries(FlangRuntimeTests + PRIVATE FortranRuntime ) diff --git a/flang/unittests/RuntimeGTest/CharacterTest.cpp b/flang/unittests/Runtime/CharacterTest.cpp rename from flang/unittests/RuntimeGTest/CharacterTest.cpp rename to flang/unittests/Runtime/CharacterTest.cpp --- a/flang/unittests/RuntimeGTest/CharacterTest.cpp +++ b/flang/unittests/Runtime/CharacterTest.cpp @@ -10,8 +10,8 @@ // in Fortran. #include "../../runtime/character.h" -#include "../../runtime/descriptor.h" #include "gtest/gtest.h" +#include "../../runtime/descriptor.h" #include #include #include @@ -264,17 +264,12 @@ TYPED_TEST_SUITE(ExtremumTests, CharacterTypes, ); TYPED_TEST(ExtremumTests, MinTests) { - static std::vector tests{ - {{}, {"a"}, {"z"}, {"a"}}, + static std::vector tests{{{}, {"a"}, {"z"}, {"a"}}, {{1}, {"zaaa"}, {"aa"}, {"aa "}}, {{1, 1}, {"aaz"}, {"aaaaa"}, {"aaaaa"}}, - { - { 2, 3 }, - { "a", "b", "c", "d", "E", "f" }, - { "xa", "ya", "az", "dd", "Sz", "cc"}, - { "a ", "b ", "az", "d ", "E ", "cc"} - } - }; + {{2, 3}, {"a", "b", "c", "d", "E", "f"}, + {"xa", "ya", "az", "dd", "Sz", "cc"}, + {"a ", "b ", "az", "d ", "E ", "cc"}}}; RunExtremumTests("MIN", RTNAME(CharacterMin), tests); } diff --git a/flang/unittests/RuntimeGTest/CrashHandlerFixture.h b/flang/unittests/Runtime/CrashHandlerFixture.h rename from flang/unittests/RuntimeGTest/CrashHandlerFixture.h rename to flang/unittests/Runtime/CrashHandlerFixture.h diff --git a/flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp b/flang/unittests/Runtime/CrashHandlerFixture.cpp rename from flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp rename to flang/unittests/Runtime/CrashHandlerFixture.cpp diff --git a/flang/unittests/Runtime/ExternalIOTest.cpp b/flang/unittests/Runtime/ExternalIOTest.cpp new file mode 100644 --- /dev/null +++ b/flang/unittests/Runtime/ExternalIOTest.cpp @@ -0,0 +1,448 @@ +//===-- flang/unittests/RuntimeGTest/ExternalIOTest.cpp ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Sanity test for all external I/O modes +// +//===----------------------------------------------------------------------===// + +#include "CrashHandlerFixture.h" +#include "gtest/gtest.h" +#include "../../runtime/io-api.h" +#include "../../runtime/main.h" +#include "../../runtime/stop.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace Fortran::runtime::io; + +struct ExternalIOTests : public CrashHandlerFixture {}; + +TEST(ExternalIOTests, TestDirectUnformatted) { + // OPEN(NEWUNIT=unit,ACCESS='DIRECT',ACTION='READWRITE',& + // FORM='UNFORMATTED',RECL=8,STATUS='SCRATCH') + Cookie io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; + ASSERT_TRUE(IONAME(SetAccess)(io, "DIRECT", 6)) << "SetAccess(DIRECT)"; + ASSERT_TRUE(IONAME(SetAction)(io, "READWRITE", 9)) << "SetAction(READWRITE)"; + ASSERT_TRUE(IONAME(SetForm)(io, "UNFORMATTED", 11)) << "SetForm(UNFORMATTED)"; + + std::int64_t buffer; + static constexpr std::size_t recl{sizeof buffer}; + ASSERT_TRUE(IONAME(SetRecl)(io, recl)) << "SetRecl()"; + ASSERT_TRUE(IONAME(SetStatus)(io, "SCRATCH", 7)) << "SetStatus(SCRATCH)"; + + int unit{-1}; + ASSERT_TRUE(IONAME(GetNewUnit)(io, unit)) << "GetNewUnit()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OpenNewUnit"; + + static constexpr int records{10}; + for (int j{1}; j <= records; ++j) { + // WRITE(UNIT=unit,REC=j) j + io = IONAME(BeginUnformattedOutput)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetRec)(io, j)) << "SetRec(" << j << ')'; + + buffer = j; + ASSERT_TRUE(IONAME(OutputUnformattedBlock)( + io, reinterpret_cast(&buffer), recl, recl)) + << "OutputUnformattedBlock()"; + + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OutputUnformattedBlock"; + } + + for (int j{records}; j >= 1; --j) { + // READ(UNIT=unit,REC=j) n + io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetRec)(io, j)) << "SetRec(" << j << ')'; + ASSERT_TRUE(IONAME(InputUnformattedBlock)( + io, reinterpret_cast(&buffer), recl, recl)) + << "InputUnformattedBlock()"; + + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for InputUnformattedBlock"; + + ASSERT_EQ(buffer, j) << "Read back " << buffer + << " from direct unformatted record " << j + << ", expected " << j << '\n'; + } + // CLOSE(UNIT=unit,STATUS='DELETE') + io = IONAME(BeginClose)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetStatus)(io, "DELETE", 6)) << "SetStatus(DELETE)"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Close"; +} + +TEST(ExternalIOTests, TestDirectUnformattedSwapped) { + // OPEN(NEWUNIT=unit,ACCESS='DIRECT',ACTION='READWRITE',& + // FORM='UNFORMATTED',RECL=8,STATUS='SCRATCH',CONVERT='NATIVE') + auto *io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; + ASSERT_TRUE(IONAME(SetAccess)(io, "DIRECT", 6)) << "SetAccess(DIRECT)"; + ASSERT_TRUE(IONAME(SetAction)(io, "READWRITE", 9)) << "SetAction(READWRITE)"; + ASSERT_TRUE(IONAME(SetForm)(io, "UNFORMATTED", 11)) << "SetForm(UNFORMATTED)"; + ASSERT_TRUE(IONAME(SetConvert)(io, "NATIVE", 6)) << "SetConvert(NATIVE)"; + + std::int64_t buffer; + static constexpr std::size_t recl{sizeof buffer}; + ASSERT_TRUE(IONAME(SetRecl)(io, recl)) << "SetRecl()"; + ASSERT_TRUE(IONAME(SetStatus)(io, "SCRATCH", 7)) << "SetStatus(SCRATCH)"; + + int unit{-1}; + ASSERT_TRUE(IONAME(GetNewUnit)(io, unit)) << "GetNewUnit()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OpenNewUnit"; + + static constexpr int records{10}; + for (int j{1}; j <= records; ++j) { + // WRITE(UNIT=unit,REC=j) j + io = IONAME(BeginUnformattedOutput)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetRec)(io, j)) << "SetRec(" << j << ')'; + buffer = j; + ASSERT_TRUE(IONAME(OutputUnformattedBlock)( + io, reinterpret_cast(&buffer), recl, recl)) + << "OutputUnformattedBlock()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OutputUnformattedBlock"; + } + + // OPEN(UNIT=unit,STATUS='OLD',CONVERT='SWAP') + io = IONAME(BeginOpenUnit)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetStatus)(io, "OLD", 3)) << "SetStatus(OLD)"; + ASSERT_TRUE(IONAME(SetConvert)(io, "SWAP", 4)) << "SetConvert(SWAP)"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OpenUnit"; + + for (int j{records}; j >= 1; --j) { + // READ(UNIT=unit,REC=j) n + io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetRec)(io, j)) << "SetRec(" << j << ')'; + ASSERT_TRUE(IONAME(InputUnformattedBlock)( + io, reinterpret_cast(&buffer), recl, recl)) + << "InputUnformattedBlock()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for InputUnformattedBlock"; + ASSERT_EQ(buffer >> 56, j) + << "Read back " << (buffer >> 56) << " from direct unformatted record " + << j << ", expected " << j << '\n'; + } + + // CLOSE(UNIT=unit,STATUS='DELETE') + io = IONAME(BeginClose)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetStatus)(io, "DELETE", 6)) << "SetStatus(DELETE)"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Close"; +} + +TEST(ExternalIOTests, TestSequentialFixedUnformatted) { + // OPEN(NEWUNIT=unit,ACCESS='SEQUENTIAL',ACTION='READWRITE',& + // FORM='UNFORMATTED',RECL=8,STATUS='SCRATCH') + auto * io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; + ASSERT_TRUE(IONAME(SetAccess)(io, "SEQUENTIAL", 10)) + << "SetAccess(SEQUENTIAL)"; + ASSERT_TRUE(IONAME(SetAction)(io, "READWRITE", 9)) << "SetAction(READWRITE)"; + ASSERT_TRUE(IONAME(SetForm)(io, "UNFORMATTED", 11)) << "SetForm(UNFORMATTED)"; + + std::int64_t buffer; + static constexpr std::size_t recl{sizeof buffer}; + + ASSERT_TRUE(IONAME(SetRecl)(io, recl)) << "SetRecl()"; + ASSERT_TRUE(IONAME(SetStatus)(io, "SCRATCH", 7)) << "SetStatus(SCRATCH)"; + + int unit{-1}; + ASSERT_TRUE(IONAME(GetNewUnit)(io, unit)) << "GetNewUnit()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OpenNewUnit"; + + static const int records{10}; + for (int j{1}; j <= records; ++j) { + // DO J=1,RECORDS; WRITE(UNIT=unit) j; END DO + io = IONAME(BeginUnformattedOutput)(unit, __FILE__, __LINE__); + buffer = j; + ASSERT_TRUE(IONAME(OutputUnformattedBlock)( + io, reinterpret_cast(&buffer), recl, recl)) + << "OutputUnformattedBlock()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OutputUnformattedBlock"; + } + + // REWIND(UNIT=unit) + io = IONAME(BeginRewind)(unit, __FILE__, __LINE__); + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Rewind"; + + for (int j{1}; j <= records; ++j) { + // DO J=1,RECORDS; READ(UNIT=unit) n; check n; END DO + io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(InputUnformattedBlock)( + io, reinterpret_cast(&buffer), recl, recl)) + << "InputUnformattedBlock()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for InputUnformattedBlock"; + ASSERT_EQ(buffer, j) << "Read back " << buffer + << " from sequential fixed unformatted record " << j + << ", expected " << j << '\n'; + } + + for (int j{records}; j >= 1; --j) { + // BACKSPACE(UNIT=unit) + io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Backspace (before read)"; + // READ(UNIT=unit) n + io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(InputUnformattedBlock)( + io, reinterpret_cast(&buffer), recl, recl)) + << "InputUnformattedBlock()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for InputUnformattedBlock"; + ASSERT_EQ(buffer, j) << "Read back " << buffer + << " from sequential fixed unformatted record " << j + << " after backspacing, expected " << j << '\n'; + // BACKSPACE(UNIT=unit) + io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Backspace (after read)"; + } + + // CLOSE(UNIT=unit,STATUS='DELETE') + io = IONAME(BeginClose)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetStatus)(io, "DELETE", 6)) << "SetStatus(DELETE)"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Close"; +} + +TEST(ExternalIOTests, TestSequentialVariableUnformatted) { + // OPEN(NEWUNIT=unit,ACCESS='SEQUENTIAL',ACTION='READWRITE',& + // FORM='UNFORMATTED',STATUS='SCRATCH') + auto *io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; + + ASSERT_TRUE(IONAME(SetAccess)(io, "SEQUENTIAL", 10)) + << "SetAccess(SEQUENTIAL)"; + ASSERT_TRUE(IONAME(SetAction)(io, "READWRITE", 9)) << "SetAction(READWRITE)"; + ASSERT_TRUE(IONAME(SetForm)(io, "UNFORMATTED", 11)) << "SetForm(UNFORMATTED)"; + ASSERT_TRUE(IONAME(SetStatus)(io, "SCRATCH", 7)) << "SetStatus(SCRATCH)"; + + int unit{-1}; + ASSERT_TRUE(IONAME(GetNewUnit)(io, unit)) << "GetNewUnit()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OpenNewUnit"; + + static const int records{10}; + std::int64_t buffer[records]; // INTEGER*8 :: BUFFER(0:9) = [(j,j=0,9)] + for (int j{0}; j < records; ++j) { + buffer[j] = j; + } + + for (int j{1}; j <= records; ++j) { + // DO J=1,RECORDS; WRITE(UNIT=unit) BUFFER(0:j); END DO + io = IONAME(BeginUnformattedOutput)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(OutputUnformattedBlock)(io, + reinterpret_cast(&buffer), j * sizeof *buffer, + sizeof *buffer)) + << "OutputUnformattedBlock()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OutputUnformattedBlock"; + } + + // REWIND(UNIT=unit) + io = IONAME(BeginRewind)(unit, __FILE__, __LINE__); + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Rewind"; + for (int j{1}; j <= records; ++j) { + // DO J=1,RECORDS; READ(UNIT=unit) n; check n; END DO + io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(InputUnformattedBlock)(io, + reinterpret_cast(&buffer), j * sizeof *buffer, sizeof *buffer)) + << "InputUnformattedBlock()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for InputUnformattedBlock"; + for (int k{0}; k < j; ++k) { + ASSERT_EQ(buffer[k], k) << "Read back [" << k << "]=" << buffer[k] + << " from direct unformatted record " << j + << ", expected " << k << '\n'; + } + } + + for (int j{records}; j >= 1; --j) { + // BACKSPACE(unit) + io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Backspace (before read)"; + // READ(unit=unit) n; check + io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(InputUnformattedBlock)(io, + reinterpret_cast(&buffer), j * sizeof *buffer, sizeof *buffer)) + << "InputUnformattedBlock()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for InputUnformattedBlock"; + for (int k{0}; k < j; ++k) { + ASSERT_EQ(buffer[k], k) << "Read back [" << k << "]=" << buffer[k] + << " from sequential variable unformatted record " + << j << ", expected " << k << '\n'; + } + // BACKSPACE(unit) + io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Backspace (after read)"; + } + + // CLOSE(UNIT=unit,STATUS='DELETE') + io = IONAME(BeginClose)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetStatus)(io, "DELETE", 6)) << "SetStatus(DELETE)"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Close"; +} + +TEST(ExternalIOTests, TestDirectFormatted) { + // OPEN(NEWUNIT=unit,ACCESS='DIRECT',ACTION='READWRITE',& + // FORM='FORMATTED',RECL=8,STATUS='SCRATCH') + auto *io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; + ASSERT_TRUE(IONAME(SetAccess)(io, "DIRECT", 6)) << "SetAccess(DIRECT)"; + ASSERT_TRUE(IONAME(SetAction)(io, "READWRITE", 9)) << "SetAction(READWRITE)"; + ASSERT_TRUE(IONAME(SetForm)(io, "FORMATTED", 9)) << "SetForm(FORMATTED)"; + + static constexpr std::size_t recl{8}; + ASSERT_TRUE(IONAME(SetRecl)(io, recl)) << "SetRecl()"; + ASSERT_TRUE(IONAME(SetStatus)(io, "SCRATCH", 7)) << "SetStatus(SCRATCH)"; + + int unit{-1}; + ASSERT_TRUE(IONAME(GetNewUnit)(io, unit)) << "GetNewUnit()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OpenNewUnit"; + + static constexpr int records{10}; + static const char fmt[]{"(I4)"}; + for (int j{1}; j <= records; ++j) { + // WRITE(UNIT=unit,FMT=fmt,REC=j) j + io = IONAME(BeginExternalFormattedOutput)( + fmt, sizeof fmt - 1, unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetRec)(io, j)) << "SetRec(" << j << ')'; + ASSERT_TRUE(IONAME(OutputInteger64)(io, j)) << "OutputInteger64()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OutputInteger64"; + } + + for (int j{records}; j >= 1; --j) { + // READ(UNIT=unit,FMT=fmt,REC=j) n + io = IONAME(BeginExternalFormattedInput)( + fmt, sizeof fmt - 1, unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetRec)(io, j)) << "SetRec(" << j << ')'; + std::int64_t buffer; + ASSERT_TRUE(IONAME(InputInteger)(io, buffer)) << "InputInteger()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for InputInteger"; + + ASSERT_EQ(buffer, j) << "Read back " << buffer + << " from direct formatted record " << j + << ", expected " << j << '\n'; + } + + // CLOSE(UNIT=unit,STATUS='DELETE') + io = IONAME(BeginClose)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetStatus)(io, "DELETE", 6)) << "SetStatus(DELETE)"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Close"; +} + +TEST(ExternalIOTests, TestSequentialVariableFormatted) { + // OPEN(NEWUNIT=unit,ACCESS='SEQUENTIAL',ACTION='READWRITE',& + // FORM='FORMATTED',STATUS='SCRATCH') + auto *io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; + ASSERT_TRUE(IONAME(SetAccess)(io, "SEQUENTIAL", 10)) + << "SetAccess(SEQUENTIAL)"; + ASSERT_TRUE(IONAME(SetAction)(io, "READWRITE", 9)) << "SetAction(READWRITE)"; + ASSERT_TRUE(IONAME(SetForm)(io, "FORMATTED", 9)) << "SetForm(FORMATTED)"; + ASSERT_TRUE(IONAME(SetStatus)(io, "SCRATCH", 7)) << "SetStatus(SCRATCH)"; + + int unit{-1}; + ASSERT_TRUE(IONAME(GetNewUnit)(io, unit)) << "GetNewUnit()"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OpenNewUnit"; + + static const int records{10}; + std::int64_t buffer[records]; // INTEGER*8 :: BUFFER(0:9) = [(j,j=0,9)] + for (int j{0}; j < records; ++j) { + buffer[j] = j; + } + + char fmt[32]; + for (int j{1}; j <= records; ++j) { + std::snprintf(fmt, sizeof fmt, "(%dI4)", j); + // DO J=1,RECORDS; WRITE(UNIT=unit,FMT=fmt) BUFFER(0:j); END DO + io = IONAME(BeginExternalFormattedOutput)( + fmt, std::strlen(fmt), unit, __FILE__, __LINE__); + for (int k{0}; k < j; ++k) { + ASSERT_TRUE(IONAME(OutputInteger64)(io, buffer[k])) + << "OutputInteger64()"; + } + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for OutputInteger64"; + } + + // REWIND(UNIT=unit) + io = IONAME(BeginRewind)(unit, __FILE__, __LINE__); + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Rewind"; + + for (int j{1}; j <= records; ++j) { + std::snprintf(fmt, sizeof fmt, "(%dI4)", j); + // DO J=1,RECORDS; READ(UNIT=unit,FMT=fmt) n; check n; END DO + io = IONAME(BeginExternalFormattedInput)( + fmt, std::strlen(fmt), unit, __FILE__, __LINE__); + + std::int64_t check[records]; + for (int k{0}; k < j; ++k) { + ASSERT_TRUE(IONAME(InputInteger)(io, check[k])) << "InputInteger()"; + } + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for InputInteger"; + + for (int k{0}; k < j; ++k) { + ASSERT_EQ(buffer[k], check[k]) + << "Read back [" << k << "]=" << check[k] + << " from sequential variable formatted record " << j << ", expected " + << buffer[k] << '\n'; + } + } + + for (int j{records}; j >= 1; --j) { + // BACKSPACE(unit) + io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Backspace (before read)"; + + std::snprintf(fmt, sizeof fmt, "(%dI4)", j); + // READ(UNIT=unit,FMT=fmt) n; check + io = IONAME(BeginExternalFormattedInput)( + fmt, std::strlen(fmt), unit, __FILE__, __LINE__); + + std::int64_t check[records]; + for (int k{0}; k < j; ++k) { + ASSERT_TRUE(IONAME(InputInteger)(io, check[k])) << "InputInteger()"; + } + + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for InputInteger"; + for (int k{0}; k < j; ++k) { + ASSERT_EQ(buffer[k], check[k]) + << "Read back [" << k << "]=" << buffer[k] + << " from sequential variable formatted record " << j << ", expected " + << buffer[k] << '\n'; + } + + // BACKSPACE(unit) + io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Backspace (after read)"; + } + + // CLOSE(UNIT=unit,STATUS='DELETE') + io = IONAME(BeginClose)(unit, __FILE__, __LINE__); + ASSERT_TRUE(IONAME(SetStatus)(io, "DELETE", 6)) << "SetStatus(DELETE)"; + ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk) + << "EndIoStatement() for Close"; +} diff --git a/flang/unittests/RuntimeGTest/Format.cpp b/flang/unittests/Runtime/Format.cpp rename from flang/unittests/RuntimeGTest/Format.cpp rename to flang/unittests/Runtime/Format.cpp diff --git a/flang/unittests/RuntimeGTest/ListInputTest.cpp b/flang/unittests/Runtime/ListInputTest.cpp rename from flang/unittests/RuntimeGTest/ListInputTest.cpp rename to flang/unittests/Runtime/ListInputTest.cpp diff --git a/flang/unittests/RuntimeGTest/Matmul.cpp b/flang/unittests/Runtime/Matmul.cpp rename from flang/unittests/RuntimeGTest/Matmul.cpp rename to flang/unittests/Runtime/Matmul.cpp diff --git a/flang/unittests/RuntimeGTest/MiscIntrinsic.cpp b/flang/unittests/Runtime/MiscIntrinsic.cpp rename from flang/unittests/RuntimeGTest/MiscIntrinsic.cpp rename to flang/unittests/Runtime/MiscIntrinsic.cpp diff --git a/flang/unittests/RuntimeGTest/Namelist.cpp b/flang/unittests/Runtime/Namelist.cpp rename from flang/unittests/RuntimeGTest/Namelist.cpp rename to flang/unittests/Runtime/Namelist.cpp diff --git a/flang/unittests/RuntimeGTest/Numeric.cpp b/flang/unittests/Runtime/Numeric.cpp rename from flang/unittests/RuntimeGTest/Numeric.cpp rename to flang/unittests/Runtime/Numeric.cpp diff --git a/flang/unittests/RuntimeGTest/NumericalFormatTest.cpp b/flang/unittests/Runtime/NumericalFormatTest.cpp rename from flang/unittests/RuntimeGTest/NumericalFormatTest.cpp rename to flang/unittests/Runtime/NumericalFormatTest.cpp diff --git a/flang/unittests/RuntimeGTest/Random.cpp b/flang/unittests/Runtime/Random.cpp rename from flang/unittests/RuntimeGTest/Random.cpp rename to flang/unittests/Runtime/Random.cpp diff --git a/flang/unittests/RuntimeGTest/Reduction.cpp b/flang/unittests/Runtime/Reduction.cpp rename from flang/unittests/RuntimeGTest/Reduction.cpp rename to flang/unittests/Runtime/Reduction.cpp diff --git a/flang/unittests/RuntimeGTest/RuntimeCrashTest.cpp b/flang/unittests/Runtime/RuntimeCrashTest.cpp rename from flang/unittests/RuntimeGTest/RuntimeCrashTest.cpp rename to flang/unittests/Runtime/RuntimeCrashTest.cpp diff --git a/flang/unittests/RuntimeGTest/Time.cpp b/flang/unittests/Runtime/Time.cpp rename from flang/unittests/RuntimeGTest/Time.cpp rename to flang/unittests/Runtime/Time.cpp diff --git a/flang/unittests/RuntimeGTest/Transformational.cpp b/flang/unittests/Runtime/Transformational.cpp rename from flang/unittests/RuntimeGTest/Transformational.cpp rename to flang/unittests/Runtime/Transformational.cpp diff --git a/flang/unittests/Runtime/external-io.cpp b/flang/unittests/Runtime/external-io.cpp deleted file mode 100644 --- a/flang/unittests/Runtime/external-io.cpp +++ /dev/null @@ -1,469 +0,0 @@ -// Sanity test for all external I/O modes - -#include "testing.h" -#include "../../runtime/io-api.h" -#include "../../runtime/main.h" -#include "../../runtime/stop.h" -#include "llvm/Support/raw_ostream.h" -#include - -using namespace Fortran::runtime::io; - -void TestDirectUnformatted() { - llvm::errs() << "begin TestDirectUnformatted()\n"; - // OPEN(NEWUNIT=unit,ACCESS='DIRECT',ACTION='READWRITE',& - // FORM='UNFORMATTED',RECL=8,STATUS='SCRATCH') - auto io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; - IONAME(SetAccess)(io, "DIRECT", 6) || (Fail() << "SetAccess(DIRECT)", 0); - IONAME(SetAction) - (io, "READWRITE", 9) || (Fail() << "SetAction(READWRITE)", 0); - IONAME(SetForm) - (io, "UNFORMATTED", 11) || (Fail() << "SetForm(UNFORMATTED)", 0); - std::int64_t buffer; - static constexpr std::size_t recl{sizeof buffer}; - IONAME(SetRecl)(io, recl) || (Fail() << "SetRecl()", 0); - IONAME(SetStatus)(io, "SCRATCH", 7) || (Fail() << "SetStatus(SCRATCH)", 0); - int unit{-1}; - IONAME(GetNewUnit)(io, unit) || (Fail() << "GetNewUnit()", 0); - llvm::errs() << "unit=" << unit << '\n'; - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for OpenNewUnit", 0); - static constexpr int records{10}; - for (int j{1}; j <= records; ++j) { - // WRITE(UNIT=unit,REC=j) j - io = IONAME(BeginUnformattedOutput)(unit, __FILE__, __LINE__); - IONAME(SetRec)(io, j) || (Fail() << "SetRec(" << j << ')', 0); - buffer = j; - IONAME(OutputUnformattedBlock) - (io, reinterpret_cast(&buffer), recl, recl) || - (Fail() << "OutputUnformattedBlock()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for OutputUnformattedBlock", 0); - } - for (int j{records}; j >= 1; --j) { - // READ(UNIT=unit,REC=j) n - io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); - IONAME(SetRec) - (io, j) || (Fail() << "SetRec(" << j << ')', 0); - IONAME(InputUnformattedBlock) - (io, reinterpret_cast(&buffer), recl, recl) || - (Fail() << "InputUnformattedBlock()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for InputUnformattedBlock", 0); - if (buffer != j) { - Fail() << "Read back " << buffer << " from direct unformatted record " - << j << ", expected " << j << '\n'; - } - } - // CLOSE(UNIT=unit,STATUS='DELETE') - io = IONAME(BeginClose)(unit, __FILE__, __LINE__); - IONAME(SetStatus)(io, "DELETE", 6) || (Fail() << "SetStatus(DELETE)", 0); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for Close", 0); - llvm::errs() << "end TestDirectUnformatted()\n"; -} - -void TestDirectUnformattedSwapped() { - llvm::errs() << "begin TestDirectUnformattedSwapped()\n"; - // OPEN(NEWUNIT=unit,ACCESS='DIRECT',ACTION='READWRITE',& - // FORM='UNFORMATTED',RECL=8,STATUS='SCRATCH',CONVERT='NATIVE') - auto io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; - IONAME(SetAccess)(io, "DIRECT", 6) || (Fail() << "SetAccess(DIRECT)", 0); - IONAME(SetAction) - (io, "READWRITE", 9) || (Fail() << "SetAction(READWRITE)", 0); - IONAME(SetForm) - (io, "UNFORMATTED", 11) || (Fail() << "SetForm(UNFORMATTED)", 0); - IONAME(SetConvert) - (io, "NATIVE", 6) || (Fail() << "SetConvert(NATIVE)", 0); - std::int64_t buffer; - static constexpr std::size_t recl{sizeof buffer}; - IONAME(SetRecl)(io, recl) || (Fail() << "SetRecl()", 0); - IONAME(SetStatus)(io, "SCRATCH", 7) || (Fail() << "SetStatus(SCRATCH)", 0); - int unit{-1}; - IONAME(GetNewUnit)(io, unit) || (Fail() << "GetNewUnit()", 0); - llvm::errs() << "unit=" << unit << '\n'; - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for OpenNewUnit", 0); - static constexpr int records{10}; - for (int j{1}; j <= records; ++j) { - // WRITE(UNIT=unit,REC=j) j - io = IONAME(BeginUnformattedOutput)(unit, __FILE__, __LINE__); - IONAME(SetRec)(io, j) || (Fail() << "SetRec(" << j << ')', 0); - buffer = j; - IONAME(OutputUnformattedBlock) - (io, reinterpret_cast(&buffer), recl, recl) || - (Fail() << "OutputUnformattedBlock()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for OutputUnformattedBlock", 0); - } - // OPEN(UNIT=unit,STATUS='OLD',CONVERT='SWAP') - io = IONAME(BeginOpenUnit)(unit, __FILE__, __LINE__); - IONAME(SetStatus)(io, "OLD", 3) || (Fail() << "SetStatus(OLD)", 0); - IONAME(SetConvert) - (io, "SWAP", 4) || (Fail() << "SetConvert(SWAP)", 0); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for OpenUnit", 0); - for (int j{records}; j >= 1; --j) { - // READ(UNIT=unit,REC=j) n - io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); - IONAME(SetRec) - (io, j) || (Fail() << "SetRec(" << j << ')', 0); - IONAME(InputUnformattedBlock) - (io, reinterpret_cast(&buffer), recl, recl) || - (Fail() << "InputUnformattedBlock()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for InputUnformattedBlock", 0); - if (buffer >> 56 != j) { - Fail() << "Read back " << (buffer >> 56) - << " from direct unformatted record " << j << ", expected " << j - << '\n'; - } - } - // CLOSE(UNIT=unit,STATUS='DELETE') - io = IONAME(BeginClose)(unit, __FILE__, __LINE__); - IONAME(SetStatus)(io, "DELETE", 6) || (Fail() << "SetStatus(DELETE)", 0); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for Close", 0); - llvm::errs() << "end TestDirectUnformatted()\n"; -} - -void TestSequentialFixedUnformatted() { - llvm::errs() << "begin TestSequentialFixedUnformatted()\n"; - // OPEN(NEWUNIT=unit,ACCESS='SEQUENTIAL',ACTION='READWRITE',& - // FORM='UNFORMATTED',RECL=8,STATUS='SCRATCH') - auto io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; - IONAME(SetAccess) - (io, "SEQUENTIAL", 10) || (Fail() << "SetAccess(SEQUENTIAL)", 0); - IONAME(SetAction) - (io, "READWRITE", 9) || (Fail() << "SetAction(READWRITE)", 0); - IONAME(SetForm) - (io, "UNFORMATTED", 11) || (Fail() << "SetForm(UNFORMATTED)", 0); - std::int64_t buffer; - static constexpr std::size_t recl{sizeof buffer}; - IONAME(SetRecl)(io, recl) || (Fail() << "SetRecl()", 0); - IONAME(SetStatus)(io, "SCRATCH", 7) || (Fail() << "SetStatus(SCRATCH)", 0); - int unit{-1}; - IONAME(GetNewUnit)(io, unit) || (Fail() << "GetNewUnit()", 0); - llvm::errs() << "unit=" << unit << '\n'; - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for OpenNewUnit", 0); - static const int records{10}; - for (int j{1}; j <= records; ++j) { - // DO J=1,RECORDS; WRITE(UNIT=unit) j; END DO - io = IONAME(BeginUnformattedOutput)(unit, __FILE__, __LINE__); - buffer = j; - IONAME(OutputUnformattedBlock) - (io, reinterpret_cast(&buffer), recl, recl) || - (Fail() << "OutputUnformattedBlock()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for OutputUnformattedBlock", 0); - } - // REWIND(UNIT=unit) - io = IONAME(BeginRewind)(unit, __FILE__, __LINE__); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for Rewind", 0); - for (int j{1}; j <= records; ++j) { - // DO J=1,RECORDS; READ(UNIT=unit) n; check n; END DO - io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); - IONAME(InputUnformattedBlock) - (io, reinterpret_cast(&buffer), recl, recl) || - (Fail() << "InputUnformattedBlock()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for InputUnformattedBlock", 0); - if (buffer != j) { - Fail() << "Read back " << buffer - << " from sequential fixed unformatted record " << j - << ", expected " << j << '\n'; - } - } - for (int j{records}; j >= 1; --j) { - // BACKSPACE(UNIT=unit) - io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for Backspace (before read)", 0); - // READ(UNIT=unit) n - io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); - IONAME(InputUnformattedBlock) - (io, reinterpret_cast(&buffer), recl, recl) || - (Fail() << "InputUnformattedBlock()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for InputUnformattedBlock", 0); - if (buffer != j) { - Fail() << "Read back " << buffer - << " from sequential fixed unformatted record " << j - << " after backspacing, expected " << j << '\n'; - } - // BACKSPACE(UNIT=unit) - io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for Backspace (after read)", 0); - } - // CLOSE(UNIT=unit,STATUS='DELETE') - io = IONAME(BeginClose)(unit, __FILE__, __LINE__); - IONAME(SetStatus)(io, "DELETE", 6) || (Fail() << "SetStatus(DELETE)", 0); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for Close", 0); - llvm::errs() << "end TestSequentialFixedUnformatted()\n"; -} - -void TestSequentialVariableUnformatted() { - llvm::errs() << "begin TestSequentialVariableUnformatted()\n"; - // OPEN(NEWUNIT=unit,ACCESS='SEQUENTIAL',ACTION='READWRITE',& - // FORM='UNFORMATTED',STATUS='SCRATCH') - auto io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; - IONAME(SetAccess) - (io, "SEQUENTIAL", 10) || (Fail() << "SetAccess(SEQUENTIAL)", 0); - IONAME(SetAction) - (io, "READWRITE", 9) || (Fail() << "SetAction(READWRITE)", 0); - IONAME(SetForm) - (io, "UNFORMATTED", 11) || (Fail() << "SetForm(UNFORMATTED)", 0); - IONAME(SetStatus)(io, "SCRATCH", 7) || (Fail() << "SetStatus(SCRATCH)", 0); - int unit{-1}; - IONAME(GetNewUnit)(io, unit) || (Fail() << "GetNewUnit()", 0); - llvm::errs() << "unit=" << unit << '\n'; - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for OpenNewUnit", 0); - static const int records{10}; - std::int64_t buffer[records]; // INTEGER*8 :: BUFFER(0:9) = [(j,j=0,9)] - for (int j{0}; j < records; ++j) { - buffer[j] = j; - } - for (int j{1}; j <= records; ++j) { - // DO J=1,RECORDS; WRITE(UNIT=unit) BUFFER(0:j); END DO - io = IONAME(BeginUnformattedOutput)(unit, __FILE__, __LINE__); - IONAME(OutputUnformattedBlock) - (io, reinterpret_cast(&buffer), j * sizeof *buffer, - sizeof *buffer) || - (Fail() << "OutputUnformattedBlock()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for OutputUnformattedBlock", 0); - } - // REWIND(UNIT=unit) - io = IONAME(BeginRewind)(unit, __FILE__, __LINE__); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for Rewind", 0); - for (int j{1}; j <= records; ++j) { - // DO J=1,RECORDS; READ(UNIT=unit) n; check n; END DO - io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); - IONAME(InputUnformattedBlock) - (io, reinterpret_cast(&buffer), j * sizeof *buffer, - sizeof *buffer) || - (Fail() << "InputUnformattedBlock()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for InputUnformattedBlock", 0); - for (int k{0}; k < j; ++k) { - if (buffer[k] != k) { - Fail() << "Read back [" << k << "]=" << buffer[k] - << " from direct unformatted record " << j << ", expected " << k - << '\n'; - } - } - } - for (int j{records}; j >= 1; --j) { - // BACKSPACE(unit) - io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for Backspace (before read)", 0); - // READ(unit=unit) n; check - io = IONAME(BeginUnformattedInput)(unit, __FILE__, __LINE__); - IONAME(InputUnformattedBlock) - (io, reinterpret_cast(&buffer), j * sizeof *buffer, - sizeof *buffer) || - (Fail() << "InputUnformattedBlock()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for InputUnformattedBlock", 0); - for (int k{0}; k < j; ++k) { - if (buffer[k] != k) { - Fail() << "Read back [" << k << "]=" << buffer[k] - << " from sequential variable unformatted record " << j - << ", expected " << k << '\n'; - } - } - // BACKSPACE(unit) - io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for Backspace (after read)", 0); - } - // CLOSE(UNIT=unit,STATUS='DELETE') - io = IONAME(BeginClose)(unit, __FILE__, __LINE__); - IONAME(SetStatus)(io, "DELETE", 6) || (Fail() << "SetStatus(DELETE)", 0); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for Close", 0); - llvm::errs() << "end TestSequentialVariableUnformatted()\n"; -} - -void TestDirectFormatted() { - llvm::errs() << "begin TestDirectFormatted()\n"; - // OPEN(NEWUNIT=unit,ACCESS='DIRECT',ACTION='READWRITE',& - // FORM='FORMATTED',RECL=8,STATUS='SCRATCH') - auto io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; - IONAME(SetAccess)(io, "DIRECT", 6) || (Fail() << "SetAccess(DIRECT)", 0); - IONAME(SetAction) - (io, "READWRITE", 9) || (Fail() << "SetAction(READWRITE)", 0); - IONAME(SetForm) - (io, "FORMATTED", 9) || (Fail() << "SetForm(FORMATTED)", 0); - static constexpr std::size_t recl{8}; - IONAME(SetRecl)(io, recl) || (Fail() << "SetRecl()", 0); - IONAME(SetStatus)(io, "SCRATCH", 7) || (Fail() << "SetStatus(SCRATCH)", 0); - int unit{-1}; - IONAME(GetNewUnit)(io, unit) || (Fail() << "GetNewUnit()", 0); - llvm::errs() << "unit=" << unit << '\n'; - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for OpenNewUnit", 0); - static constexpr int records{10}; - static const char fmt[]{"(I4)"}; - for (int j{1}; j <= records; ++j) { - // WRITE(UNIT=unit,FMT=fmt,REC=j) j - io = IONAME(BeginExternalFormattedOutput)( - fmt, sizeof fmt - 1, unit, __FILE__, __LINE__); - IONAME(SetRec)(io, j) || (Fail() << "SetRec(" << j << ')', 0); - IONAME(OutputInteger64)(io, j) || (Fail() << "OutputInteger64()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for OutputInteger64", 0); - } - for (int j{records}; j >= 1; --j) { - // READ(UNIT=unit,FMT=fmt,REC=j) n - io = IONAME(BeginExternalFormattedInput)( - fmt, sizeof fmt - 1, unit, __FILE__, __LINE__); - IONAME(SetRec)(io, j) || (Fail() << "SetRec(" << j << ')', 0); - std::int64_t buffer; - IONAME(InputInteger)(io, buffer) || (Fail() << "InputInteger()", 0); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for InputInteger", 0); - if (buffer != j) { - Fail() << "Read back " << buffer << " from direct formatted record " << j - << ", expected " << j << '\n'; - } - } - // CLOSE(UNIT=unit,STATUS='DELETE') - io = IONAME(BeginClose)(unit, __FILE__, __LINE__); - IONAME(SetStatus)(io, "DELETE", 6) || (Fail() << "SetStatus(DELETE)", 0); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for Close", 0); - llvm::errs() << "end TestDirectformatted()\n"; -} - -void TestSequentialVariableFormatted() { - llvm::errs() << "begin TestSequentialVariableFormatted()\n"; - // OPEN(NEWUNIT=unit,ACCESS='SEQUENTIAL',ACTION='READWRITE',& - // FORM='FORMATTED',STATUS='SCRATCH') - auto io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)}; - IONAME(SetAccess) - (io, "SEQUENTIAL", 10) || (Fail() << "SetAccess(SEQUENTIAL)", 0); - IONAME(SetAction) - (io, "READWRITE", 9) || (Fail() << "SetAction(READWRITE)", 0); - IONAME(SetForm) - (io, "FORMATTED", 9) || (Fail() << "SetForm(FORMATTED)", 0); - IONAME(SetStatus)(io, "SCRATCH", 7) || (Fail() << "SetStatus(SCRATCH)", 0); - int unit{-1}; - IONAME(GetNewUnit)(io, unit) || (Fail() << "GetNewUnit()", 0); - llvm::errs() << "unit=" << unit << '\n'; - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for OpenNewUnit", 0); - static const int records{10}; - std::int64_t buffer[records]; // INTEGER*8 :: BUFFER(0:9) = [(j,j=0,9)] - for (int j{0}; j < records; ++j) { - buffer[j] = j; - } - char fmt[32]; - for (int j{1}; j <= records; ++j) { - std::snprintf(fmt, sizeof fmt, "(%dI4)", j); - // DO J=1,RECORDS; WRITE(UNIT=unit,FMT=fmt) BUFFER(0:j); END DO - io = IONAME(BeginExternalFormattedOutput)( - fmt, std::strlen(fmt), unit, __FILE__, __LINE__); - for (int k{0}; k < j; ++k) { - IONAME(OutputInteger64) - (io, buffer[k]) || (Fail() << "OutputInteger64()", 0); - } - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for OutputInteger64", 0); - } - // REWIND(UNIT=unit) - io = IONAME(BeginRewind)(unit, __FILE__, __LINE__); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for Rewind", 0); - for (int j{1}; j <= records; ++j) { - std::snprintf(fmt, sizeof fmt, "(%dI4)", j); - // DO J=1,RECORDS; READ(UNIT=unit,FMT=fmt) n; check n; END DO - io = IONAME(BeginExternalFormattedInput)( - fmt, std::strlen(fmt), unit, __FILE__, __LINE__); - std::int64_t check[records]; - for (int k{0}; k < j; ++k) { - IONAME(InputInteger)(io, check[k]) || (Fail() << "InputInteger()", 0); - } - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for InputInteger", 0); - for (int k{0}; k < j; ++k) { - if (buffer[k] != check[k]) { - Fail() << "Read back [" << k << "]=" << check[k] - << " from sequential variable formatted record " << j - << ", expected " << buffer[k] << '\n'; - } - } - } - for (int j{records}; j >= 1; --j) { - // BACKSPACE(unit) - io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for Backspace (before read)", 0); - std::snprintf(fmt, sizeof fmt, "(%dI4)", j); - // READ(UNIT=unit,FMT=fmt) n; check - io = IONAME(BeginExternalFormattedInput)( - fmt, std::strlen(fmt), unit, __FILE__, __LINE__); - std::int64_t check[records]; - for (int k{0}; k < j; ++k) { - IONAME(InputInteger)(io, check[k]) || (Fail() << "InputInteger()", 0); - } - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for InputInteger", 0); - for (int k{0}; k < j; ++k) { - if (buffer[k] != check[k]) { - Fail() << "Read back [" << k << "]=" << buffer[k] - << " from sequential variable formatted record " << j - << ", expected " << buffer[k] << '\n'; - } - } - // BACKSPACE(unit) - io = IONAME(BeginBackspace)(unit, __FILE__, __LINE__); - IONAME(EndIoStatement) - (io) == IostatOk || - (Fail() << "EndIoStatement() for Backspace (after read)", 0); - } - // CLOSE(UNIT=unit,STATUS='DELETE') - io = IONAME(BeginClose)(unit, __FILE__, __LINE__); - IONAME(SetStatus)(io, "DELETE", 6) || (Fail() << "SetStatus(DELETE)", 0); - IONAME(EndIoStatement) - (io) == IostatOk || (Fail() << "EndIoStatement() for Close", 0); - llvm::errs() << "end TestSequentialVariableFormatted()\n"; -} - -void TestStreamUnformatted() { - // TODO -} - -int main() { - StartTests(); - TestDirectUnformatted(); - TestDirectUnformattedSwapped(); - TestSequentialFixedUnformatted(); - TestSequentialVariableUnformatted(); - TestDirectFormatted(); - TestSequentialVariableFormatted(); - TestStreamUnformatted(); - return EndTests(); -} diff --git a/flang/unittests/Runtime/testing.h b/flang/unittests/Runtime/testing.h deleted file mode 100644 --- a/flang/unittests/Runtime/testing.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef FORTRAN_TEST_RUNTIME_TESTING_H_ -#define FORTRAN_TEST_RUNTIME_TESTING_H_ - -#include "llvm/Support/raw_ostream.h" -#include - -namespace llvm { -class raw_ostream; -} - -void StartTests(); -llvm::raw_ostream &Fail(); -int EndTests(); - -#endif // FORTRAN_TEST_RUNTIME_TESTING_H_ diff --git a/flang/unittests/Runtime/testing.cpp b/flang/unittests/Runtime/testing.cpp deleted file mode 100644 --- a/flang/unittests/Runtime/testing.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "testing.h" -#include "../../runtime/terminator.h" -#include -#include -#include -#include -#include - -static int failures{0}; - -// Override the Fortran runtime's Crash() for testing purposes -[[noreturn]] static void CatchCrash( - const char *sourceFile, int sourceLine, const char *message, va_list &ap) { - char buffer[1000]; - std::vsnprintf(buffer, sizeof buffer, message, ap); - va_end(ap); - llvm::errs() << (sourceFile ? sourceFile : "unknown source file") << '(' - << sourceLine << "): CRASH: " << buffer << '\n'; - throw std::string{buffer}; -} - -void StartTests() { - Fortran::runtime::Terminator::RegisterCrashHandler(CatchCrash); -} - -llvm::raw_ostream &Fail() { - ++failures; - return llvm::errs(); -} - -int EndTests() { - if (failures == 0) { - llvm::outs() << "PASS\n"; - } else { - llvm::outs() << "FAIL " << failures << " tests\n"; - } - return failures != 0; -} diff --git a/flang/unittests/RuntimeGTest/tools.h b/flang/unittests/Runtime/tools.h rename from flang/unittests/RuntimeGTest/tools.h rename to flang/unittests/Runtime/tools.h diff --git a/flang/unittests/RuntimeGTest/CMakeLists.txt b/flang/unittests/RuntimeGTest/CMakeLists.txt deleted file mode 100644 --- a/flang/unittests/RuntimeGTest/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -add_flang_unittest(FlangRuntimeTests - BufferTest.cpp - CharacterTest.cpp - CrashHandlerFixture.cpp - Format.cpp - ListInputTest.cpp - Matmul.cpp - MiscIntrinsic.cpp - Namelist.cpp - Numeric.cpp - NumericalFormatTest.cpp - Random.cpp - Reduction.cpp - RuntimeCrashTest.cpp - Time.cpp - Transformational.cpp -) - -target_link_libraries(FlangRuntimeTests - PRIVATE - FortranRuntime -)