// 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(); }