[flang-commits] [flang] 65436e6 - [flang] Move External IO tests to use GTest

Asher Mancinelli via flang-commits flang-commits at lists.llvm.org
Fri Jul 30 09:22:20 PDT 2021


Author: Asher Mancinelli
Date: 2021-07-30T10:22:01-06:00
New Revision: 65436e6ba12786dd27785b21e9436ded750ce8e3

URL: https://github.com/llvm/llvm-project/commit/65436e6ba12786dd27785b21e9436ded750ce8e3
DIFF: https://github.com/llvm/llvm-project/commit/65436e6ba12786dd27785b21e9436ded750ce8e3.diff

LOG: [flang] Move External IO tests to use GTest

Port external-io test to use GTest. Remove Runtime tests directory.
Rename RuntimeGTest directory to Runtime.

This is the last in a series of patches which ported tests from the old
flang/unittests/Runtime test directory to use GTest in a temporary
unittest directory under flang/unittests/RuntimeGTest. Now that all the
tests in the old directory have been ported to use GTest, the old
directory has been removed and the GTest directory has been renamed to
flang/unittests/Runtime.

Differential Revision: https://reviews.llvm.org/D105315
Reviewed by: Meinersbur, awarzynski

Added: 
    flang/unittests/Runtime/BufferTest.cpp
    flang/unittests/Runtime/CharacterTest.cpp
    flang/unittests/Runtime/CrashHandlerFixture.cpp
    flang/unittests/Runtime/CrashHandlerFixture.h
    flang/unittests/Runtime/ExternalIOTest.cpp
    flang/unittests/Runtime/Format.cpp
    flang/unittests/Runtime/ListInputTest.cpp
    flang/unittests/Runtime/Matmul.cpp
    flang/unittests/Runtime/MiscIntrinsic.cpp
    flang/unittests/Runtime/Namelist.cpp
    flang/unittests/Runtime/Numeric.cpp
    flang/unittests/Runtime/NumericalFormatTest.cpp
    flang/unittests/Runtime/Random.cpp
    flang/unittests/Runtime/Reduction.cpp
    flang/unittests/Runtime/RuntimeCrashTest.cpp
    flang/unittests/Runtime/Time.cpp
    flang/unittests/Runtime/Transformational.cpp
    flang/unittests/Runtime/tools.h

Modified: 
    flang/unittests/CMakeLists.txt
    flang/unittests/Runtime/CMakeLists.txt

Removed: 
    flang/unittests/Runtime/external-io.cpp
    flang/unittests/Runtime/testing.cpp
    flang/unittests/Runtime/testing.h
    flang/unittests/RuntimeGTest/BufferTest.cpp
    flang/unittests/RuntimeGTest/CMakeLists.txt
    flang/unittests/RuntimeGTest/CharacterTest.cpp
    flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp
    flang/unittests/RuntimeGTest/CrashHandlerFixture.h
    flang/unittests/RuntimeGTest/Format.cpp
    flang/unittests/RuntimeGTest/ListInputTest.cpp
    flang/unittests/RuntimeGTest/Matmul.cpp
    flang/unittests/RuntimeGTest/MiscIntrinsic.cpp
    flang/unittests/RuntimeGTest/Namelist.cpp
    flang/unittests/RuntimeGTest/Numeric.cpp
    flang/unittests/RuntimeGTest/NumericalFormatTest.cpp
    flang/unittests/RuntimeGTest/Random.cpp
    flang/unittests/RuntimeGTest/Reduction.cpp
    flang/unittests/RuntimeGTest/RuntimeCrashTest.cpp
    flang/unittests/RuntimeGTest/Time.cpp
    flang/unittests/RuntimeGTest/Transformational.cpp
    flang/unittests/RuntimeGTest/tools.h


################################################################################
diff  --git a/flang/unittests/CMakeLists.txt b/flang/unittests/CMakeLists.txt
index dd4ee4f37a72c..54af3aff21d62 100644
--- a/flang/unittests/CMakeLists.txt
+++ b/flang/unittests/CMakeLists.txt
@@ -40,7 +40,6 @@ add_subdirectory(Optimizer)
 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
similarity index 100%
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
index fa6952737ad02..6ae2f6443d67e 100644
--- 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
similarity index 98%
rename from flang/unittests/RuntimeGTest/CharacterTest.cpp
rename to flang/unittests/Runtime/CharacterTest.cpp
index 4450621667005..a386365f57b5f 100644
--- 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 <cstring>
 #include <functional>
 #include <tuple>
@@ -264,17 +264,12 @@ template <typename CHAR> struct ExtremumTests : public ::testing::Test {};
 TYPED_TEST_SUITE(ExtremumTests, CharacterTypes, );
 
 TYPED_TEST(ExtremumTests, MinTests) {
-  static std::vector<ExtremumTestCase> tests{
-      {{}, {"a"}, {"z"}, {"a"}},
+  static std::vector<ExtremumTestCase> 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<TypeParam>("MIN", RTNAME(CharacterMin), tests);
 }
 

diff  --git a/flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp b/flang/unittests/Runtime/CrashHandlerFixture.cpp
similarity index 100%
rename from flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp
rename to flang/unittests/Runtime/CrashHandlerFixture.cpp

diff  --git a/flang/unittests/RuntimeGTest/CrashHandlerFixture.h b/flang/unittests/Runtime/CrashHandlerFixture.h
similarity index 100%
rename from flang/unittests/RuntimeGTest/CrashHandlerFixture.h
rename to flang/unittests/Runtime/CrashHandlerFixture.h

diff  --git a/flang/unittests/Runtime/ExternalIOTest.cpp b/flang/unittests/Runtime/ExternalIOTest.cpp
new file mode 100644
index 0000000000000..e1621edca40df
--- /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 <cstring>
+
+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<const char *>(&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<char *>(&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<const char *>(&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<char *>(&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<const char *>(&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<char *>(&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<char *>(&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<const char *>(&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<char *>(&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<char *>(&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
similarity index 100%
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
similarity index 100%
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
similarity index 100%
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
similarity index 100%
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
similarity index 100%
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
similarity index 100%
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
similarity index 100%
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
similarity index 100%
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
similarity index 100%
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
similarity index 100%
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
similarity index 100%
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
similarity index 100%
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
index c307f1ce9e0c3..0000000000000
--- 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 <cstring>
-
-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<const char *>(&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<char *>(&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<const char *>(&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<char *>(&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<const char *>(&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<char *>(&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<char *>(&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<const char *>(&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<char *>(&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<char *>(&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.cpp b/flang/unittests/Runtime/testing.cpp
deleted file mode 100644
index ab2b5c25bcb91..0000000000000
--- a/flang/unittests/Runtime/testing.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "testing.h"
-#include "../../runtime/terminator.h"
-#include <algorithm>
-#include <cstdarg>
-#include <cstdio>
-#include <cstring>
-#include <string>
-
-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/Runtime/testing.h b/flang/unittests/Runtime/testing.h
deleted file mode 100644
index 21c2acd9b0aae..0000000000000
--- 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 <cstddef>
-
-namespace llvm {
-class raw_ostream;
-}
-
-void StartTests();
-llvm::raw_ostream &Fail();
-int EndTests();
-
-#endif // FORTRAN_TEST_RUNTIME_TESTING_H_

diff  --git a/flang/unittests/RuntimeGTest/tools.h b/flang/unittests/Runtime/tools.h
similarity index 100%
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
index fb842c7d69f8e..0000000000000
--- 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
-)


        


More information about the flang-commits mailing list