You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
3.8 KiB
140 lines
3.8 KiB
// Tests basic FORMAT string traversal
|
|
|
|
#include "testing.h"
|
|
#include "../runtime/format-implementation.h"
|
|
#include "../runtime/io-error.h"
|
|
#include <cstdarg>
|
|
#include <cstring>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace Fortran::runtime;
|
|
using namespace Fortran::runtime::io;
|
|
using namespace std::literals::string_literals;
|
|
|
|
using Results = std::vector<std::string>;
|
|
|
|
// A test harness context for testing FormatControl
|
|
class TestFormatContext : public IoErrorHandler {
|
|
public:
|
|
using CharType = char;
|
|
TestFormatContext() : IoErrorHandler{"format.cpp", 1} {}
|
|
bool Emit(const char *, std::size_t);
|
|
bool Emit(const char16_t *, std::size_t);
|
|
bool Emit(const char32_t *, std::size_t);
|
|
bool AdvanceRecord(int = 1);
|
|
void HandleRelativePosition(std::int64_t);
|
|
void HandleAbsolutePosition(std::int64_t);
|
|
void Report(const DataEdit &);
|
|
void Check(Results &);
|
|
Results results;
|
|
MutableModes &mutableModes() { return mutableModes_; }
|
|
|
|
private:
|
|
MutableModes mutableModes_;
|
|
};
|
|
|
|
bool TestFormatContext::Emit(const char *s, std::size_t len) {
|
|
std::string str{s, len};
|
|
results.push_back("'"s + str + '\'');
|
|
return true;
|
|
}
|
|
bool TestFormatContext::Emit(const char16_t *, std::size_t) {
|
|
Crash("TestFormatContext::Emit(const char16_t *) called");
|
|
return false;
|
|
}
|
|
bool TestFormatContext::Emit(const char32_t *, std::size_t) {
|
|
Crash("TestFormatContext::Emit(const char32_t *) called");
|
|
return false;
|
|
}
|
|
|
|
bool TestFormatContext::AdvanceRecord(int n) {
|
|
while (n-- > 0) {
|
|
results.emplace_back("/");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void TestFormatContext::HandleAbsolutePosition(std::int64_t n) {
|
|
results.push_back("T"s + std::to_string(n));
|
|
}
|
|
|
|
void TestFormatContext::HandleRelativePosition(std::int64_t n) {
|
|
if (n < 0) {
|
|
results.push_back("TL"s + std::to_string(-n));
|
|
} else {
|
|
results.push_back(std::to_string(n) + 'X');
|
|
}
|
|
}
|
|
|
|
void TestFormatContext::Report(const DataEdit &edit) {
|
|
std::string str{edit.descriptor};
|
|
if (edit.repeat != 1) {
|
|
str = std::to_string(edit.repeat) + '*' + str;
|
|
}
|
|
if (edit.variation) {
|
|
str += edit.variation;
|
|
}
|
|
if (edit.width) {
|
|
str += std::to_string(*edit.width);
|
|
}
|
|
if (edit.digits) {
|
|
str += "."s + std::to_string(*edit.digits);
|
|
}
|
|
if (edit.expoDigits) {
|
|
str += "E"s + std::to_string(*edit.expoDigits);
|
|
}
|
|
// modes?
|
|
results.push_back(str);
|
|
}
|
|
|
|
void TestFormatContext::Check(Results &expect) {
|
|
if (expect != results) {
|
|
Fail() << "expected:";
|
|
for (const std::string &s : expect) {
|
|
llvm::errs() << ' ' << s;
|
|
}
|
|
llvm::errs() << "\ngot:";
|
|
for (const std::string &s : results) {
|
|
llvm::errs() << ' ' << s;
|
|
}
|
|
llvm::errs() << '\n';
|
|
}
|
|
expect.clear();
|
|
results.clear();
|
|
}
|
|
|
|
static void Test(int n, const char *format, Results &&expect, int repeat = 1) {
|
|
TestFormatContext context;
|
|
FormatControl<TestFormatContext> control{
|
|
context, format, std::strlen(format)};
|
|
try {
|
|
for (int j{0}; j < n; ++j) {
|
|
context.Report(control.GetNextDataEdit(context, repeat));
|
|
}
|
|
control.Finish(context);
|
|
if (int iostat{context.GetIoStat()}) {
|
|
context.Crash("GetIoStat() == %d", iostat);
|
|
}
|
|
} catch (const std::string &crash) {
|
|
context.results.push_back("Crash:"s + crash);
|
|
}
|
|
context.Check(expect);
|
|
}
|
|
|
|
int main() {
|
|
StartTests();
|
|
Test(1, "('PI=',F9.7)", Results{"'PI='", "F9.7"});
|
|
Test(1, "(3HPI=F9.7)", Results{"'PI='", "F9.7"});
|
|
Test(1, "(3HPI=/F9.7)", Results{"'PI='", "/", "F9.7"});
|
|
Test(2, "('PI=',F9.7)", Results{"'PI='", "F9.7", "/", "'PI='", "F9.7"});
|
|
Test(2, "(2('PI=',F9.7),'done')",
|
|
Results{"'PI='", "F9.7", "'PI='", "F9.7", "'done'"});
|
|
Test(2, "(3('PI=',F9.7,:),'tooFar')",
|
|
Results{"'PI='", "F9.7", "'PI='", "F9.7"});
|
|
Test(2, "(*('PI=',F9.7,:),'tooFar')",
|
|
Results{"'PI='", "F9.7", "'PI='", "F9.7"});
|
|
Test(1, "(3F9.7)", Results{"2*F9.7"}, 2);
|
|
return EndTests();
|
|
}
|