1 // Tests basic FORMAT string traversal
4 #include "../runtime/format-implementation.h"
5 #include "../runtime/io-error.h"
11 using namespace Fortran::runtime
;
12 using namespace Fortran::runtime::io
;
13 using namespace std::literals::string_literals
;
15 using Results
= std::vector
<std::string
>;
17 // A test harness context for testing FormatControl
18 class TestFormatContext
: public IoErrorHandler
{
20 using CharType
= char;
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
&);
31 MutableModes
&mutableModes() { return mutableModes_
; }
34 MutableModes mutableModes_
;
37 bool TestFormatContext::Emit(const char *s
, std::size_t len
) {
38 std::string str
{s
, len
};
39 results
.push_back("'"s
+ str
+ '\'');
42 bool TestFormatContext::Emit(const char16_t
*, std::size_t) {
43 Crash("TestFormatContext::Emit(const char16_t *) called");
46 bool TestFormatContext::Emit(const char32_t
*, std::size_t) {
47 Crash("TestFormatContext::Emit(const char32_t *) called");
51 bool TestFormatContext::AdvanceRecord(int n
) {
53 results
.emplace_back("/");
58 void TestFormatContext::HandleAbsolutePosition(std::int64_t n
) {
59 results
.push_back("T"s
+ std::to_string(n
));
62 void TestFormatContext::HandleRelativePosition(std::int64_t n
) {
64 results
.push_back("TL"s
+ std::to_string(-n
));
66 results
.push_back(std::to_string(n
) + 'X');
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
;
76 str
+= edit
.variation
;
79 str
+= std::to_string(*edit
.width
);
82 str
+= "."s
+ std::to_string(*edit
.digits
);
84 if (edit
.expoDigits
) {
85 str
+= "E"s
+ std::to_string(*edit
.expoDigits
);
88 results
.push_back(str
);
91 void TestFormatContext::Check(Results
&expect
) {
92 if (expect
!= results
) {
93 Fail() << "expected:";
94 for (const std::string
&s
: expect
) {
95 llvm::errs() << ' ' << s
;
97 llvm::errs() << "\ngot:";
98 for (const std::string
&s
: results
) {
99 llvm::errs() << ' ' << s
;
101 llvm::errs() << '\n';
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
)};
112 for (int j
{0}; j
< n
; ++j
) {
113 context
.Report(control
.GetNextDataEdit(context
, repeat
));
115 control
.Finish(context
);
116 if (int iostat
{context
.GetIoStat()}) {
117 context
.Crash("GetIoStat() == %d", iostat
);
119 } catch (const std::string
&crash
) {
120 context
.results
.push_back("Crash:"s
+ crash
);
122 context
.Check(expect
);
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);