forked from OSchip/llvm-project
[flang] Basic tests of external I/O runtime (part 9/9)
Add new unit tests for external Fortran I/O that drive the Fortran I/O runtime API from C++ and exercise basic writing and read-back in the various combinations of access modes, record length variability, and formatting. Sequential modes are tested with positioning. More thorough tests written in Fortran will follow when they can be compiled and run. The Fortran runtime's error termination callback registration was extended with source file and line number positions for better failure messages in unit testing. Reviewed By: sscalpone Differential Revision: https://reviews.llvm.org/D83164
This commit is contained in:
parent
39d2ae0afb
commit
a39e9cf6be
flang
runtime
unittests/Runtime
|
@ -18,17 +18,18 @@ namespace Fortran::runtime {
|
|||
CrashArgs(message, ap);
|
||||
}
|
||||
|
||||
static void (*crashHandler)(const char *, va_list &){nullptr};
|
||||
static void (*crashHandler)(const char *, int, const char *, va_list &){
|
||||
nullptr};
|
||||
|
||||
void Terminator::RegisterCrashHandler(
|
||||
void (*handler)(const char *, va_list &)) {
|
||||
void (*handler)(const char *, int, const char *, va_list &)) {
|
||||
crashHandler = handler;
|
||||
}
|
||||
|
||||
[[noreturn]] void Terminator::CrashArgs(
|
||||
const char *message, va_list &ap) const {
|
||||
if (crashHandler) {
|
||||
crashHandler(message, ap);
|
||||
crashHandler(sourceFileName_, sourceLine_, message, ap);
|
||||
}
|
||||
std::fputs("\nfatal Fortran runtime error", stderr);
|
||||
if (sourceFileName_) {
|
||||
|
|
|
@ -34,7 +34,8 @@ public:
|
|||
const char *predicate, const char *file, int line) const;
|
||||
|
||||
// For test harnessing - overrides CrashArgs().
|
||||
static void RegisterCrashHandler(void (*)(const char *, va_list &));
|
||||
static void RegisterCrashHandler(void (*)(const char *sourceFile,
|
||||
int sourceLine, const char *message, va_list &ap));
|
||||
|
||||
private:
|
||||
const char *sourceFileName_{nullptr};
|
||||
|
|
|
@ -41,6 +41,18 @@ target_link_libraries(external-hello-world
|
|||
LLVMSupport
|
||||
)
|
||||
|
||||
add_executable(external-io
|
||||
external-io.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(external-io
|
||||
RuntimeTesting
|
||||
FortranRuntime
|
||||
LLVMSupport
|
||||
)
|
||||
|
||||
add_test(NAME ExternalIO COMMAND external-io)
|
||||
|
||||
add_executable(list-input-test
|
||||
list-input.cpp
|
||||
)
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
|
||||
using namespace Fortran::runtime::io;
|
||||
|
||||
int main(int argc, const char *argv[], const char *envp[]) {
|
||||
RTNAME(ProgramStart)(argc, argv, envp);
|
||||
auto *io{IONAME(BeginExternalListOutput)()};
|
||||
void output1() {
|
||||
auto io{IONAME(BeginExternalListOutput)()};
|
||||
const char str[]{"Hello, world!"};
|
||||
IONAME(OutputAscii)(io, str, std::strlen(str));
|
||||
IONAME(OutputInteger64)(io, 678);
|
||||
|
@ -21,6 +20,31 @@ int main(int argc, const char *argv[], const char *envp[]) {
|
|||
IONAME(OutputLogical)(io, false);
|
||||
IONAME(OutputLogical)(io, true);
|
||||
IONAME(EndIoStatement)(io);
|
||||
}
|
||||
|
||||
void input1() {
|
||||
auto io{IONAME(BeginExternalListOutput)()};
|
||||
const char prompt[]{"Enter an integer value:"};
|
||||
IONAME(OutputAscii)(io, prompt, std::strlen(prompt));
|
||||
IONAME(EndIoStatement)(io);
|
||||
|
||||
io = IONAME(BeginExternalListInput)();
|
||||
std::int64_t n{-666};
|
||||
IONAME(InputInteger)(io, n);
|
||||
IONAME(EndIoStatement)(io);
|
||||
|
||||
io = IONAME(BeginExternalListOutput)();
|
||||
const char str[]{"Result:"};
|
||||
IONAME(OutputAscii)(io, str, std::strlen(str));
|
||||
IONAME(OutputInteger64)(io, n);
|
||||
IONAME(EndIoStatement)(io);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[], const char *envp[]) {
|
||||
RTNAME(ProgramStart)(argc, argv, envp);
|
||||
output1();
|
||||
input1();
|
||||
RTNAME(PauseStatement)();
|
||||
RTNAME(ProgramEndStatement)();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,399 @@
|
|||
// 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) ||
|
||||
(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) ||
|
||||
(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 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) ||
|
||||
(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) ||
|
||||
(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) ||
|
||||
(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) ||
|
||||
(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) ||
|
||||
(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) ||
|
||||
(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();
|
||||
TestSequentialFixedUnformatted();
|
||||
TestSequentialVariableUnformatted();
|
||||
TestDirectFormatted();
|
||||
TestSequentialVariableFormatted();
|
||||
TestStreamUnformatted();
|
||||
return EndTests();
|
||||
}
|
|
@ -9,10 +9,13 @@
|
|||
static int failures{0};
|
||||
|
||||
// Override the Fortran runtime's Crash() for testing purposes
|
||||
[[noreturn]] static void CatchCrash(const char *message, va_list &ap) {
|
||||
[[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};
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ void StartTests();
|
|||
llvm::raw_ostream &Fail();
|
||||
int EndTests();
|
||||
|
||||
// Defines a CHARACTER object with padding when needed
|
||||
void SetCharacter(char *, std::size_t, const char *);
|
||||
|
||||
#endif // FORTRAN_TEST_RUNTIME_TESTING_H_
|
||||
|
|
Loading…
Reference in New Issue