1 // Tests basic FORMAT string traversal
2
3 #include "testing.h"
4 #include "../runtime/format-implementation.h"
5 #include "../runtime/io-error.h"
6 #include <cstdarg>
7 #include <cstring>
8 #include <string>
9 #include <vector>
10
11 using namespace Fortran::runtime;
12 using namespace Fortran::runtime::io;
13 using namespace std::literals::string_literals;
14
15 using Results = std::vector<std::string>;
16
17 // A test harness context for testing FormatControl
18 class TestFormatContext : public IoErrorHandler {
19 public:
20 using CharType = char;
TestFormatContext()21 TestFormatContext() : IoErrorHandler{"format.cpp", 1} {}
22 bool Emit(const char *, std::size_t);
23 bool Emit(const char16_t *, std::size_t);
24 bool Emit(const char32_t *, std::size_t);
25 bool AdvanceRecord(int = 1);
26 void HandleRelativePosition(std::int64_t);
27 void HandleAbsolutePosition(std::int64_t);
28 void Report(const DataEdit &);
29 void Check(Results &);
30 Results results;
mutableModes()31 MutableModes &mutableModes() { return mutableModes_; }
32
33 private:
34 MutableModes mutableModes_;
35 };
36
Emit(const char * s,std::size_t len)37 bool TestFormatContext::Emit(const char *s, std::size_t len) {
38 std::string str{s, len};
39 results.push_back("'"s + str + '\'');
40 return true;
41 }
Emit(const char16_t *,std::size_t)42 bool TestFormatContext::Emit(const char16_t *, std::size_t) {
43 Crash("TestFormatContext::Emit(const char16_t *) called");
44 return false;
45 }
Emit(const char32_t *,std::size_t)46 bool TestFormatContext::Emit(const char32_t *, std::size_t) {
47 Crash("TestFormatContext::Emit(const char32_t *) called");
48 return false;
49 }
50
AdvanceRecord(int n)51 bool TestFormatContext::AdvanceRecord(int n) {
52 while (n-- > 0) {
53 results.emplace_back("/");
54 }
55 return true;
56 }
57
HandleAbsolutePosition(std::int64_t n)58 void TestFormatContext::HandleAbsolutePosition(std::int64_t n) {
59 results.push_back("T"s + std::to_string(n));
60 }
61
HandleRelativePosition(std::int64_t n)62 void TestFormatContext::HandleRelativePosition(std::int64_t n) {
63 if (n < 0) {
64 results.push_back("TL"s + std::to_string(-n));
65 } else {
66 results.push_back(std::to_string(n) + 'X');
67 }
68 }
69
Report(const DataEdit & edit)70 void TestFormatContext::Report(const DataEdit &edit) {
71 std::string str{edit.descriptor};
72 if (edit.repeat != 1) {
73 str = std::to_string(edit.repeat) + '*' + str;
74 }
75 if (edit.variation) {
76 str += edit.variation;
77 }
78 if (edit.width) {
79 str += std::to_string(*edit.width);
80 }
81 if (edit.digits) {
82 str += "."s + std::to_string(*edit.digits);
83 }
84 if (edit.expoDigits) {
85 str += "E"s + std::to_string(*edit.expoDigits);
86 }
87 // modes?
88 results.push_back(str);
89 }
90
Check(Results & expect)91 void TestFormatContext::Check(Results &expect) {
92 if (expect != results) {
93 Fail() << "expected:";
94 for (const std::string &s : expect) {
95 llvm::errs() << ' ' << s;
96 }
97 llvm::errs() << "\ngot:";
98 for (const std::string &s : results) {
99 llvm::errs() << ' ' << s;
100 }
101 llvm::errs() << '\n';
102 }
103 expect.clear();
104 results.clear();
105 }
106
Test(int n,const char * format,Results && expect,int repeat=1)107 static void Test(int n, const char *format, Results &&expect, int repeat = 1) {
108 TestFormatContext context;
109 FormatControl<TestFormatContext> control{
110 context, format, std::strlen(format)};
111 try {
112 for (int j{0}; j < n; ++j) {
113 context.Report(control.GetNextDataEdit(context, repeat));
114 }
115 control.Finish(context);
116 if (int iostat{context.GetIoStat()}) {
117 context.Crash("GetIoStat() == %d", iostat);
118 }
119 } catch (const std::string &crash) {
120 context.results.push_back("Crash:"s + crash);
121 }
122 context.Check(expect);
123 }
124
main()125 int main() {
126 StartTests();
127 Test(1, "('PI=',F9.7)", Results{"'PI='", "F9.7"});
128 Test(1, "(3HPI=F9.7)", Results{"'PI='", "F9.7"});
129 Test(1, "(3HPI=/F9.7)", Results{"'PI='", "/", "F9.7"});
130 Test(2, "('PI=',F9.7)", Results{"'PI='", "F9.7", "/", "'PI='", "F9.7"});
131 Test(2, "(2('PI=',F9.7),'done')",
132 Results{"'PI='", "F9.7", "'PI='", "F9.7", "'done'"});
133 Test(2, "(3('PI=',F9.7,:),'tooFar')",
134 Results{"'PI='", "F9.7", "'PI='", "F9.7"});
135 Test(2, "(*('PI=',F9.7,:),'tooFar')",
136 Results{"'PI='", "F9.7", "'PI='", "F9.7"});
137 Test(1, "(3F9.7)", Results{"2*F9.7"}, 2);
138 return EndTests();
139 }
140