• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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