1 | //===-- flang/unittests/Runtime/NumericalFormatTest.cpp ---------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "CrashHandlerFixture.h" |
10 | #include "flang/Runtime/descriptor.h" |
11 | #include "flang/Runtime/io-api.h" |
12 | #include <algorithm> |
13 | #include <array> |
14 | #include <cstring> |
15 | #include <gtest/gtest.h> |
16 | #include <tuple> |
17 | |
18 | using namespace Fortran::runtime; |
19 | using namespace Fortran::runtime::io; |
20 | |
21 | static bool CompareFormattedStrings( |
22 | const std::string &expect, const std::string &got) { |
23 | std::string want{expect}; |
24 | want.resize(n: got.size(), c: ' '); |
25 | return want == got; |
26 | } |
27 | |
28 | static bool CompareFormattedStrings( |
29 | const char *expect, const std::string &&got) { |
30 | return CompareFormattedStrings(expect: std::string(expect), got: std::move(got)); |
31 | } |
32 | |
33 | // Perform format and compare the result with expected value |
34 | static bool CompareFormatReal( |
35 | const char *format, double x, const char *expect, std::string &got) { |
36 | char buffer[800]; |
37 | auto cookie{IONAME(BeginInternalFormattedOutput)( |
38 | buffer, sizeof buffer, format, std::strlen(format))}; |
39 | EXPECT_TRUE(IONAME(OutputReal64)(cookie, x)); |
40 | auto status{IONAME(EndIoStatement)(cookie)}; |
41 | EXPECT_EQ(status, 0); |
42 | got = std::string{buffer, sizeof buffer}; |
43 | auto lastNonBlank{got.find_last_not_of(s: " " )}; |
44 | if (lastNonBlank != std::string::npos) { |
45 | got.resize(n: lastNonBlank + 1); |
46 | } |
47 | return CompareFormattedStrings(expect, got); |
48 | } |
49 | |
50 | // Convert raw uint64 into double, perform format, and compare with expected |
51 | static bool CompareFormatReal(const char *format, std::uint64_t xInt, |
52 | const char *expect, std::string &got) { |
53 | double x; |
54 | static_assert(sizeof(double) == sizeof(std::uint64_t), |
55 | "Size of double != size of uint64_t!" ); |
56 | std::memcpy(dest: &x, src: &xInt, n: sizeof xInt); |
57 | return CompareFormatReal(format, x, expect, got); |
58 | } |
59 | |
60 | static bool CompareFormatInteger( |
61 | const char *format, std::int64_t x, const char *expect, std::string &got) { |
62 | char buffer[800]; |
63 | auto cookie{IONAME(BeginInternalFormattedOutput)( |
64 | buffer, sizeof buffer, format, std::strlen(format))}; |
65 | EXPECT_TRUE(IONAME(OutputInteger64)(cookie, x)); |
66 | auto status{IONAME(EndIoStatement)(cookie)}; |
67 | EXPECT_EQ(status, 0); |
68 | got = std::string{buffer, sizeof buffer}; |
69 | auto lastNonBlank{got.find_last_not_of(s: " " )}; |
70 | if (lastNonBlank != std::string::npos) { |
71 | got.resize(n: lastNonBlank + 1); |
72 | } |
73 | return CompareFormattedStrings(expect, got); |
74 | } |
75 | |
76 | struct IOApiTests : CrashHandlerFixture {}; |
77 | |
78 | TEST(IOApiTests, HelloWorldOutputTest) { |
79 | static constexpr int bufferSize{32}; |
80 | char buffer[bufferSize]; |
81 | |
82 | // Create format for all types and values to be written |
83 | const char *format{"(6HHELLO,,A6,2X,I3,1X,'0x',Z8,1X,L1)" }; |
84 | auto cookie{IONAME(BeginInternalFormattedOutput)( |
85 | buffer, bufferSize, format, std::strlen(format))}; |
86 | |
87 | // Write string, integer, and logical values to buffer |
88 | IONAME(OutputAscii)(cookie, "WORLD" , 5); |
89 | IONAME(OutputInteger64)(cookie, 678); |
90 | IONAME(OutputInteger32)(cookie, 0xfeedface); |
91 | IONAME(OutputLogical)(cookie, true); |
92 | |
93 | // Ensure IO succeeded |
94 | auto status{IONAME(EndIoStatement)(cookie)}; |
95 | ASSERT_EQ(status, 0) << "hello: '" << format << "' failed, status " |
96 | << static_cast<int>(status); |
97 | |
98 | // Ensure final buffer matches expected string output |
99 | static const std::string expect{"HELLO, WORLD 678 0xFEEDFACE T" }; |
100 | ASSERT_TRUE( |
101 | CompareFormattedStrings(expect, std::string{buffer, sizeof buffer})) |
102 | << "Expected '" << expect << "', got " << buffer; |
103 | } |
104 | |
105 | TEST(IOApiTests, MultilineOutputTest) { |
106 | // Allocate buffer for multiline output |
107 | static constexpr int numLines{5}; |
108 | static constexpr int lineLength{32}; |
109 | char buffer[numLines][lineLength]; |
110 | |
111 | // Create descriptor for entire buffer |
112 | static constexpr int staticDescriptorMaxRank{1}; |
113 | StaticDescriptor<staticDescriptorMaxRank> wholeStaticDescriptor; |
114 | Descriptor &whole{wholeStaticDescriptor.descriptor()}; |
115 | static const SubscriptValue extent[]{numLines}; |
116 | whole.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/lineLength, &buffer, |
117 | staticDescriptorMaxRank, extent, CFI_attribute_pointer); |
118 | whole.Dump(stderr); |
119 | whole.Check(); |
120 | |
121 | // Create descriptor for buffer section |
122 | StaticDescriptor<staticDescriptorMaxRank> sectionStaticDescriptor; |
123 | Descriptor §ion{sectionStaticDescriptor.descriptor()}; |
124 | static const SubscriptValue lowers[]{0}, uppers[]{4}, strides[]{1}; |
125 | section.Establish(whole.type(), /*elementBytes=*/whole.ElementBytes(), |
126 | nullptr, /*maxRank=*/staticDescriptorMaxRank, extent, |
127 | CFI_attribute_pointer); |
128 | |
129 | // Ensure C descriptor address `section.raw()` is updated without error |
130 | const auto error{ |
131 | CFI_section(§ion.raw(), &whole.raw(), lowers, uppers, strides)}; |
132 | ASSERT_EQ(error, 0) << "multiline: CFI_section failed: " << error; |
133 | section.Dump(stderr); |
134 | section.Check(); |
135 | |
136 | // Create format string and initialize IO operation |
137 | const char *format{ |
138 | "('?abcde,',T1,'>',T9,A,TL12,A,TR25,'<'//G0,17X,'abcd',1(2I4))" }; |
139 | auto cookie{IONAME(BeginInternalArrayFormattedOutput)( |
140 | section, format, std::strlen(format))}; |
141 | |
142 | // Fill last line with periods |
143 | std::memset(s: buffer[numLines - 1], c: '.', n: lineLength); |
144 | |
145 | // Write data to buffer |
146 | IONAME(OutputAscii)(cookie, "WORLD" , 5); |
147 | IONAME(OutputAscii)(cookie, "HELLO" , 5); |
148 | IONAME(OutputInteger64)(cookie, 789); |
149 | for (int j{666}; j <= 999; j += 111) { |
150 | IONAME(OutputInteger64)(cookie, j); |
151 | } |
152 | |
153 | // Ensure no errors occured in write operations above |
154 | const auto status{IONAME(EndIoStatement)(cookie)}; |
155 | ASSERT_EQ(status, 0) << "multiline: '" << format << "' failed, status " |
156 | << static_cast<int>(status); |
157 | |
158 | static const std::string expect{">HELLO, WORLD <" |
159 | " " |
160 | "789 abcd 666 777" |
161 | " 888 999 " |
162 | "................................" }; |
163 | // Ensure formatted string matches expected output |
164 | EXPECT_TRUE( |
165 | CompareFormattedStrings(expect, std::string{buffer[0], sizeof buffer})) |
166 | << "Expected '" << expect << "' but got '" |
167 | << std::string{buffer[0], sizeof buffer} << "'" ; |
168 | } |
169 | |
170 | TEST(IOApiTests, ListInputTest) { |
171 | static const char input[]{",1*,(5.,6.),(7.0,8.0)" }; |
172 | auto cookie{IONAME(BeginInternalListInput)(input, sizeof input - 1)}; |
173 | |
174 | // Create real values for IO tests |
175 | static constexpr int numRealValues{8}; |
176 | float z[numRealValues]; |
177 | for (int j{0}; j < numRealValues; ++j) { |
178 | z[j] = -(j + 1); |
179 | } |
180 | |
181 | // Ensure reading complex values to floats does not result in an error |
182 | for (int j{0}; j < numRealValues; j += 2) { |
183 | ASSERT_TRUE(IONAME(InputComplex32)(cookie, &z[j])) |
184 | << "InputComplex32 failed with value " << z[j]; |
185 | } |
186 | |
187 | // Ensure no IO errors occured during IO operations above |
188 | auto status{IONAME(EndIoStatement)(cookie)}; |
189 | ASSERT_EQ(status, 0) << "Failed complex list-directed input, status " |
190 | << static_cast<int>(status); |
191 | |
192 | // Ensure writing complex values from floats does not result in an error |
193 | static constexpr int bufferSize{39}; |
194 | char output[bufferSize]; |
195 | output[bufferSize - 1] = '\0'; |
196 | cookie = IONAME(BeginInternalListOutput)(output, bufferSize - 1); |
197 | for (int j{0}; j < numRealValues; j += 2) { |
198 | ASSERT_TRUE(IONAME(OutputComplex32)(cookie, z[j], z[j + 1])) |
199 | << "OutputComplex32 failed when outputting value " << z[j] << ", " |
200 | << z[j + 1]; |
201 | } |
202 | |
203 | // Ensure no IO errors occured during IO operations above |
204 | status = IONAME(EndIoStatement)(cookie); |
205 | ASSERT_EQ(status, 0) << "Failed complex list-directed output, status " |
206 | << static_cast<int>(status); |
207 | |
208 | // Verify output buffer against expected value |
209 | static const char expect[bufferSize]{ |
210 | " (-1.,-2.) (-3.,-4.) (5.,6.) (7.,8.) " }; |
211 | ASSERT_EQ(std::strncmp(output, expect, bufferSize), 0) |
212 | << "Failed complex list-directed output, expected '" << expect |
213 | << "', but got '" << output << "'" ; |
214 | } |
215 | |
216 | TEST(IOApiTests, DescriptorOutputTest) { |
217 | static constexpr int bufferSize{10}; |
218 | char buffer[bufferSize]; |
219 | const char *format{"(2A4)" }; |
220 | auto cookie{IONAME(BeginInternalFormattedOutput)( |
221 | buffer, bufferSize, format, std::strlen(format))}; |
222 | |
223 | // Create descriptor for output |
224 | static constexpr int staticDescriptorMaxRank{1}; |
225 | StaticDescriptor<staticDescriptorMaxRank> staticDescriptor; |
226 | Descriptor &desc{staticDescriptor.descriptor()}; |
227 | static constexpr int subscriptExtent{2}; |
228 | static const SubscriptValue extent[]{subscriptExtent}; |
229 | |
230 | // Manually write to descriptor buffer |
231 | static constexpr int dataLength{4}; |
232 | char data[subscriptExtent][dataLength]; |
233 | std::memcpy(dest: data[0], src: "ABCD" , n: dataLength); |
234 | std::memcpy(dest: data[1], src: "EFGH" , n: dataLength); |
235 | desc.Establish(TypeCode{CFI_type_char}, dataLength, &data, |
236 | staticDescriptorMaxRank, extent); |
237 | desc.Dump(stderr); |
238 | desc.Check(); |
239 | IONAME(OutputDescriptor)(cookie, desc); |
240 | |
241 | // Ensure no errors were encountered in initializing the cookie and descriptor |
242 | auto formatStatus{IONAME(EndIoStatement)(cookie)}; |
243 | ASSERT_EQ(formatStatus, 0) |
244 | << "descrOutputTest: '" << format << "' failed, status " |
245 | << static_cast<int>(formatStatus); |
246 | |
247 | // Ensure buffer matches expected output |
248 | EXPECT_TRUE( |
249 | CompareFormattedStrings("ABCDEFGH " , std::string{buffer, sizeof buffer})) |
250 | << "descrOutputTest: formatted: got '" |
251 | << std::string{buffer, sizeof buffer} << "'" ; |
252 | |
253 | // Begin list-directed output on cookie by descriptor |
254 | cookie = IONAME(BeginInternalListOutput)(buffer, sizeof buffer); |
255 | IONAME(OutputDescriptor)(cookie, desc); |
256 | |
257 | // Ensure list-directed output does not result in an IO error |
258 | auto listDirectedStatus{IONAME(EndIoStatement)(cookie)}; |
259 | ASSERT_EQ(listDirectedStatus, 0) |
260 | << "descrOutputTest: list-directed failed, status " |
261 | << static_cast<int>(listDirectedStatus); |
262 | |
263 | // Ensure buffer matches expected output |
264 | EXPECT_TRUE( |
265 | CompareFormattedStrings(" ABCDEFGH " , std::string{buffer, sizeof buffer})) |
266 | << "descrOutputTest: list-directed: got '" |
267 | << std::string{buffer, sizeof buffer} << "'" ; |
268 | } |
269 | |
270 | //------------------------------------------------------------------------------ |
271 | /// Tests for output formatting real values |
272 | //------------------------------------------------------------------------------ |
273 | |
274 | TEST(IOApiTests, FormatZeroes) { |
275 | static constexpr std::pair<const char *, const char *> zeroes[]{ |
276 | {"(E32.17,';')" , " 0.00000000000000000E+00;" }, |
277 | {"(F32.17,';')" , " 0.00000000000000000;" }, |
278 | {"(G32.17,';')" , " 0.0000000000000000 ;" }, |
279 | {"(DC,E32.17,';')" , " 0,00000000000000000E+00;" }, |
280 | {"(DC,F32.17,';')" , " 0,00000000000000000;" }, |
281 | {"(DC,G32.17,';')" , " 0,0000000000000000 ;" }, |
282 | {"(D32.17,';')" , " 0.00000000000000000D+00;" }, |
283 | {"(E32.17E1,';')" , " 0.00000000000000000E+0;" }, |
284 | {"(G32.17E1,';')" , " 0.0000000000000000 ;" }, |
285 | {"(E32.17E0,';')" , " 0.00000000000000000E+0;" }, |
286 | {"(G32.17E0,';')" , " 0.0000000000000000 ;" }, |
287 | {"(1P,E32.17,';')" , " 0.00000000000000000E+00;" }, |
288 | {"(1PE32.17,';')" , " 0.00000000000000000E+00;" }, // no comma |
289 | {"(1P,F32.17,';')" , " 0.00000000000000000;" }, |
290 | {"(1P,G32.17,';')" , " 0.0000000000000000 ;" }, |
291 | {"(2P,E32.17,';')" , " 00.0000000000000000E+00;" }, |
292 | {"(-1P,E32.17,';')" , " 0.00000000000000000E+00;" }, |
293 | {"(EX32.17,';')" , " 0X0.00000000000000000P+0;" }, |
294 | {"(DC,EX32.17,';')" , " 0X0,00000000000000000P+0;" }, |
295 | {"(G0,';')" , "0.;" }, |
296 | }; |
297 | |
298 | for (auto const &[format, expect] : zeroes) { |
299 | std::string got; |
300 | ASSERT_TRUE(CompareFormatReal(format, 0.0, expect, got)) |
301 | << "Failed to format " << format << ", expected '" << expect |
302 | << "', got '" << got << "'" ; |
303 | } |
304 | } |
305 | |
306 | TEST(IOApiTests, FormatOnes) { |
307 | static constexpr std::pair<const char *, const char *> ones[]{ |
308 | {"(E32.17,';')" , " 0.10000000000000000E+01;" }, |
309 | {"(F32.17,';')" , " 1.00000000000000000;" }, |
310 | {"(G32.17,';')" , " 1.0000000000000000 ;" }, |
311 | {"(E32.17E1,';')" , " 0.10000000000000000E+1;" }, |
312 | {"(G32.17E1,';')" , " 1.0000000000000000 ;" }, |
313 | {"(E32.17E0,';')" , " 0.10000000000000000E+1;" }, |
314 | {"(G32.17E0,';')" , " 1.0000000000000000 ;" }, |
315 | {"(E32.17E4,';')" , " 0.10000000000000000E+0001;" }, |
316 | {"(G32.17E4,';')" , " 1.0000000000000000 ;" }, |
317 | {"(1P,E32.17,';')" , " 1.00000000000000000E+00;" }, |
318 | {"(1PE32.17,';')" , " 1.00000000000000000E+00;" }, // no comma |
319 | {"(1P,F32.17,';')" , " 10.00000000000000000;" }, |
320 | {"(1P,G32.17,';')" , " 1.0000000000000000 ;" }, |
321 | {"(ES32.17,';')" , " 1.00000000000000000E+00;" }, |
322 | {"(2P,E32.17,';')" , " 10.0000000000000000E-01;" }, |
323 | {"(2P,G32.17,';')" , " 1.0000000000000000 ;" }, |
324 | {"(-1P,E32.17,';')" , " 0.01000000000000000E+02;" }, |
325 | {"(-1P,G32.17,';')" , " 1.0000000000000000 ;" }, |
326 | {"(EX32.17,';')" , " 0X8.00000000000000000P-3;" }, |
327 | {"(DC,EX32.17,';')" , " 0X8,00000000000000000P-3;" }, |
328 | {"(G0,';')" , "1.;" }, |
329 | }; |
330 | |
331 | for (auto const &[format, expect] : ones) { |
332 | std::string got; |
333 | ASSERT_TRUE(CompareFormatReal(format, 1.0, expect, got)) |
334 | << "Failed to format " << format << ", expected '" << expect |
335 | << "', got '" << got << "'" ; |
336 | } |
337 | } |
338 | |
339 | TEST(IOApiTests, FormatNegativeOnes) { |
340 | static constexpr std::tuple<const char *, const char *> negOnes[]{ |
341 | {"(E32.17,';')" , " -0.10000000000000000E+01;" }, |
342 | {"(F32.17,';')" , " -1.00000000000000000;" }, |
343 | {"(G32.17,';')" , " -1.0000000000000000 ;" }, |
344 | {"(EX32.17,';')" , " -0X8.00000000000000000P-3;" }, |
345 | {"(G0,';')" , "-1.;" }, |
346 | }; |
347 | for (auto const &[format, expect] : negOnes) { |
348 | std::string got; |
349 | ASSERT_TRUE(CompareFormatReal(format, -1.0, expect, got)) |
350 | << "Failed to format " << format << ", expected '" << expect |
351 | << "', got '" << got << "'" ; |
352 | } |
353 | } |
354 | |
355 | // Each test case contains a raw uint64, a format string for a real value, and |
356 | // the expected resulting string from formatting the raw uint64. The double |
357 | // representation of the uint64 is commented above each test case. |
358 | TEST(IOApiTests, FormatDoubleValues) { |
359 | |
360 | using TestCaseTy = std::tuple<std::uint64_t, |
361 | std::vector<std::tuple<const char *, const char *>>>; |
362 | static const std::vector<TestCaseTy> testCases{ |
363 | {// -0 |
364 | 0x8000000000000000, |
365 | { |
366 | {"(E9.1,';')" , " -0.0E+00;" }, |
367 | {"(F4.0,';')" , " -0.;" }, |
368 | {"(F0.1,';')" , "-.0;" }, |
369 | {"(G8.0,';')" , "-0.0E+00;" }, |
370 | {"(G8.1,';')" , " -0. ;" }, |
371 | {"(G0,';')" , "-0.;" }, |
372 | {"(E9.1,';')" , " -0.0E+00;" }, |
373 | {"(EX9.1,';')" , "-0X0.0P+0;" }, |
374 | }}, |
375 | {// +Inf |
376 | 0x7ff0000000000000, |
377 | { |
378 | {"(E9.1,';')" , " Inf;" }, |
379 | {"(F9.1,';')" , " Inf;" }, |
380 | {"(G9.1,';')" , " Inf;" }, |
381 | {"(EX9.1,';')" , " Inf;" }, |
382 | {"(SP,E9.1,';')" , " +Inf;" }, |
383 | {"(SP,F9.1,';')" , " +Inf;" }, |
384 | {"(SP,G9.1,';')" , " +Inf;" }, |
385 | {"(SP,EX9.1,';')" , " +Inf;" }, |
386 | {"(G0,';')" , "Inf;" }, |
387 | }}, |
388 | {// -Inf |
389 | 0xfff0000000000000, |
390 | { |
391 | {"(E9.1,';')" , " -Inf;" }, |
392 | {"(F9.1,';')" , " -Inf;" }, |
393 | {"(G9.1,';')" , " -Inf;" }, |
394 | {"(EX9.1,';')" , " -Inf;" }, |
395 | {"(G0,';')" , "-Inf;" }, |
396 | }}, |
397 | {// NaN |
398 | 0x7ff0000000000001, |
399 | { |
400 | {"(E9.1,';')" , " NaN;" }, |
401 | {"(F9.1,';')" , " NaN;" }, |
402 | {"(G9.1,';')" , " NaN;" }, |
403 | {"(EX9.1,';')" , " NaN;" }, |
404 | {"(G0,';')" , "NaN;" }, |
405 | }}, |
406 | {// NaN (sign irrelevant) |
407 | 0xfff0000000000001, |
408 | { |
409 | {"(E9.1,';')" , " NaN;" }, |
410 | {"(F9.1,';')" , " NaN;" }, |
411 | {"(G9.1,';')" , " NaN;" }, |
412 | {"(SP,E9.1,';')" , " NaN;" }, |
413 | {"(SP,F9.1,';')" , " NaN;" }, |
414 | {"(SP,G9.1,';')" , " NaN;" }, |
415 | {"(SP,EX9.1,';')" , " NaN;" }, |
416 | {"(G0,';')" , "NaN;" }, |
417 | }}, |
418 | {// 0.1 rounded |
419 | 0x3fb999999999999a, |
420 | { |
421 | {"(E62.55,';')" , |
422 | " 0.1000000000000000055511151231257827021181583404541015625E+" |
423 | "00;" }, |
424 | {"(E0.1,';')" , ".1E+00;" }, |
425 | {"(E0.55,';')" , |
426 | ".1000000000000000055511151231257827021181583404541015625E+" |
427 | "00;" }, |
428 | {"(E0,';')" , ".1E+00;" }, |
429 | {"(F58.55,';')" , |
430 | " 0." |
431 | "1000000000000000055511151231257827021181583404541015625;" }, |
432 | {"(F0.0,';')" , "0.;" }, |
433 | {"(F0.55,';')" , |
434 | ".1000000000000000055511151231257827021181583404541015625;" }, |
435 | {"(F0,';')" , ".1;" }, |
436 | {"(G62.55,';')" , |
437 | " 0.1000000000000000055511151231257827021181583404541015625 " |
438 | " ;" }, |
439 | {"(G0.0,';')" , "0.;" }, |
440 | {"(G0.55,';')" , |
441 | ".1000000000000000055511151231257827021181583404541015625;" }, |
442 | {"(G0,';')" , ".1;" }, |
443 | {"(EX20.12,';')" , " 0XC.CCCCCCCCCCCDP-7;" }, |
444 | }}, |
445 | {// 1.5 |
446 | 0x3ff8000000000000, |
447 | { |
448 | {"(E9.2,';')" , " 0.15E+01;" }, |
449 | {"(F4.1,';')" , " 1.5;" }, |
450 | {"(G7.1,';')" , " 2. ;" }, |
451 | {"(EX9.1,';')" , " 0XC.0P-3;" }, |
452 | {"(RN,E8.1,';')" , " 0.2E+01;" }, |
453 | {"(RN,F3.0,';')" , " 2.;" }, |
454 | {"(RN,G7.0,';')" , " 0.E+01;" }, |
455 | {"(RN,G7.1,';')" , " 2. ;" }, |
456 | {"(RD,E8.1,';')" , " 0.1E+01;" }, |
457 | {"(RD,F3.0,';')" , " 1.;" }, |
458 | {"(RD,G7.0,';')" , " 0.E+01;" }, |
459 | {"(RD,G7.1,';')" , " 1. ;" }, |
460 | {"(RU,E8.1,';')" , " 0.2E+01;" }, |
461 | {"(RU,G7.0,';')" , " 0.E+01;" }, |
462 | {"(RU,G7.1,';')" , " 2. ;" }, |
463 | {"(RZ,E8.1,';')" , " 0.1E+01;" }, |
464 | {"(RZ,F3.0,';')" , " 1.;" }, |
465 | {"(RZ,G7.0,';')" , " 0.E+01;" }, |
466 | {"(RZ,G7.1,';')" , " 1. ;" }, |
467 | {"(RC,E8.1,';')" , " 0.2E+01;" }, |
468 | {"(RC,F3.0,';')" , " 2.;" }, |
469 | {"(RC,G7.0,';')" , " 0.E+01;" }, |
470 | {"(RC,G7.1,';')" , " 2. ;" }, |
471 | }}, |
472 | {// -1.5 |
473 | 0xbff8000000000000, |
474 | { |
475 | {"(E9.2,';')" , "-0.15E+01;" }, |
476 | {"(RN,E8.1,';')" , "-0.2E+01;" }, |
477 | {"(RD,E8.1,';')" , "-0.2E+01;" }, |
478 | {"(RU,E8.1,';')" , "-0.1E+01;" }, |
479 | {"(RZ,E8.1,';')" , "-0.1E+01;" }, |
480 | {"(RC,E8.1,';')" , "-0.2E+01;" }, |
481 | {"(EX9.1,';')" , "-0XC.0P-3;" }, |
482 | }}, |
483 | {// 2.5 |
484 | 0x4004000000000000, |
485 | { |
486 | {"(E9.2,';')" , " 0.25E+01;" }, |
487 | {"(RN,E8.1,';')" , " 0.2E+01;" }, |
488 | {"(RD,E8.1,';')" , " 0.2E+01;" }, |
489 | {"(RU,E8.1,';')" , " 0.3E+01;" }, |
490 | {"(RZ,E8.1,';')" , " 0.2E+01;" }, |
491 | {"(RC,E8.1,';')" , " 0.3E+01;" }, |
492 | {"(EX9.1,';')" , " 0XA.0P-2;" }, |
493 | }}, |
494 | {// -2.5 |
495 | 0xc004000000000000, |
496 | { |
497 | {"(E9.2,';')" , "-0.25E+01;" }, |
498 | {"(RN,E8.1,';')" , "-0.2E+01;" }, |
499 | {"(RD,E8.1,';')" , "-0.3E+01;" }, |
500 | {"(RU,E8.1,';')" , "-0.2E+01;" }, |
501 | {"(RZ,E8.1,';')" , "-0.2E+01;" }, |
502 | {"(RC,E8.1,';')" , "-0.3E+01;" }, |
503 | {"(EX9.1,';')" , "-0XA.0P-2;" }, |
504 | }}, |
505 | {// least positive nonzero subnormal |
506 | 1, |
507 | { |
508 | {"(E32.17,';')" , " 0.49406564584124654-323;" }, |
509 | {"(ES32.17,';')" , " 4.94065645841246544-324;" }, |
510 | {"(EN32.17,';')" , " 4.94065645841246544-324;" }, |
511 | {"(E759.752,';')" , |
512 | " 0." |
513 | "494065645841246544176568792868221372365059802614324764425585" |
514 | "682500675507270208751865299836361635992379796564695445717730" |
515 | "926656710355939796398774796010781878126300713190311404527845" |
516 | "817167848982103688718636056998730723050006387409153564984387" |
517 | "312473397273169615140031715385398074126238565591171026658556" |
518 | "686768187039560310624931945271591492455329305456544401127480" |
519 | "129709999541931989409080416563324524757147869014726780159355" |
520 | "238611550134803526493472019379026810710749170333222684475333" |
521 | "572083243193609238289345836806010601150616980975307834227731" |
522 | "832924790498252473077637592724787465608477820373446969953364" |
523 | "701797267771758512566055119913150489110145103786273816725095" |
524 | "583738973359899366480994116420570263709027924276754456522908" |
525 | "75386825064197182655334472656250-323;" }, |
526 | {"(G0,';')" , ".5E-323;" }, |
527 | {"(E757.750,';')" , |
528 | " 0." |
529 | "494065645841246544176568792868221372365059802614324764425585" |
530 | "682500675507270208751865299836361635992379796564695445717730" |
531 | "926656710355939796398774796010781878126300713190311404527845" |
532 | "817167848982103688718636056998730723050006387409153564984387" |
533 | "312473397273169615140031715385398074126238565591171026658556" |
534 | "686768187039560310624931945271591492455329305456544401127480" |
535 | "129709999541931989409080416563324524757147869014726780159355" |
536 | "238611550134803526493472019379026810710749170333222684475333" |
537 | "572083243193609238289345836806010601150616980975307834227731" |
538 | "832924790498252473077637592724787465608477820373446969953364" |
539 | "701797267771758512566055119913150489110145103786273816725095" |
540 | "583738973359899366480994116420570263709027924276754456522908" |
541 | "753868250641971826553344726562-323;" }, |
542 | {"(RN,E757.750,';')" , |
543 | " 0." |
544 | "494065645841246544176568792868221372365059802614324764425585" |
545 | "682500675507270208751865299836361635992379796564695445717730" |
546 | "926656710355939796398774796010781878126300713190311404527845" |
547 | "817167848982103688718636056998730723050006387409153564984387" |
548 | "312473397273169615140031715385398074126238565591171026658556" |
549 | "686768187039560310624931945271591492455329305456544401127480" |
550 | "129709999541931989409080416563324524757147869014726780159355" |
551 | "238611550134803526493472019379026810710749170333222684475333" |
552 | "572083243193609238289345836806010601150616980975307834227731" |
553 | "832924790498252473077637592724787465608477820373446969953364" |
554 | "701797267771758512566055119913150489110145103786273816725095" |
555 | "583738973359899366480994116420570263709027924276754456522908" |
556 | "753868250641971826553344726562-323;" }, |
557 | {"(RD,E757.750,';')" , |
558 | " 0." |
559 | "494065645841246544176568792868221372365059802614324764425585" |
560 | "682500675507270208751865299836361635992379796564695445717730" |
561 | "926656710355939796398774796010781878126300713190311404527845" |
562 | "817167848982103688718636056998730723050006387409153564984387" |
563 | "312473397273169615140031715385398074126238565591171026658556" |
564 | "686768187039560310624931945271591492455329305456544401127480" |
565 | "129709999541931989409080416563324524757147869014726780159355" |
566 | "238611550134803526493472019379026810710749170333222684475333" |
567 | "572083243193609238289345836806010601150616980975307834227731" |
568 | "832924790498252473077637592724787465608477820373446969953364" |
569 | "701797267771758512566055119913150489110145103786273816725095" |
570 | "583738973359899366480994116420570263709027924276754456522908" |
571 | "753868250641971826553344726562-323;" }, |
572 | {"(RU,E757.750,';')" , |
573 | " 0." |
574 | "494065645841246544176568792868221372365059802614324764425585" |
575 | "682500675507270208751865299836361635992379796564695445717730" |
576 | "926656710355939796398774796010781878126300713190311404527845" |
577 | "817167848982103688718636056998730723050006387409153564984387" |
578 | "312473397273169615140031715385398074126238565591171026658556" |
579 | "686768187039560310624931945271591492455329305456544401127480" |
580 | "129709999541931989409080416563324524757147869014726780159355" |
581 | "238611550134803526493472019379026810710749170333222684475333" |
582 | "572083243193609238289345836806010601150616980975307834227731" |
583 | "832924790498252473077637592724787465608477820373446969953364" |
584 | "701797267771758512566055119913150489110145103786273816725095" |
585 | "583738973359899366480994116420570263709027924276754456522908" |
586 | "753868250641971826553344726563-323;" }, |
587 | {"(RC,E757.750,';')" , |
588 | " 0." |
589 | "494065645841246544176568792868221372365059802614324764425585" |
590 | "682500675507270208751865299836361635992379796564695445717730" |
591 | "926656710355939796398774796010781878126300713190311404527845" |
592 | "817167848982103688718636056998730723050006387409153564984387" |
593 | "312473397273169615140031715385398074126238565591171026658556" |
594 | "686768187039560310624931945271591492455329305456544401127480" |
595 | "129709999541931989409080416563324524757147869014726780159355" |
596 | "238611550134803526493472019379026810710749170333222684475333" |
597 | "572083243193609238289345836806010601150616980975307834227731" |
598 | "832924790498252473077637592724787465608477820373446969953364" |
599 | "701797267771758512566055119913150489110145103786273816725095" |
600 | "583738973359899366480994116420570263709027924276754456522908" |
601 | "753868250641971826553344726563-323;" }, |
602 | {"(EX24.13,';')" , " 0X8.0000000000000P-1077;" }, |
603 | }}, |
604 | {// least positive nonzero normal |
605 | 0x10000000000000, |
606 | { |
607 | {"(E723.716,';')" , |
608 | " 0." |
609 | "222507385850720138309023271733240406421921598046233183055332" |
610 | "741688720443481391819585428315901251102056406733973103581100" |
611 | "515243416155346010885601238537771882113077799353200233047961" |
612 | "014744258363607192156504694250373420837525080665061665815894" |
613 | "872049117996859163964850063590877011830487479978088775374994" |
614 | "945158045160505091539985658247081864511353793580499211598108" |
615 | "576605199243335211435239014879569960959128889160299264151106" |
616 | "346631339366347758651302937176204732563178148566435087212282" |
617 | "863764204484681140761391147706280168985324411002416144742161" |
618 | "856716615054015428508471675290190316132277889672970737312333" |
619 | "408698898317506783884692609277397797285865965494109136909540" |
620 | "61364675687023986783152906809846172109246253967285156250-" |
621 | "307;" }, |
622 | {"(G0,';')" , ".22250738585072014E-307;" }, |
623 | {"(EX24.13,';')" , " 0X8.0000000000000P-1025;" }, |
624 | }}, |
625 | {// greatest finite |
626 | 0x7fefffffffffffffuLL, |
627 | { |
628 | {"(E32.17,';')" , " 0.17976931348623157+309;" }, |
629 | {"(E317.310,';')" , |
630 | " 0." |
631 | "179769313486231570814527423731704356798070567525844996598917" |
632 | "476803157260780028538760589558632766878171540458953514382464" |
633 | "234321326889464182768467546703537516986049910576551282076245" |
634 | "490090389328944075868508455133942304583236903222948165808559" |
635 | "332123348274797826204144723168738177180919299881250404026184" |
636 | "1248583680+309;" }, |
637 | {"(ES317.310,';')" , |
638 | " 1." |
639 | "797693134862315708145274237317043567980705675258449965989174" |
640 | "768031572607800285387605895586327668781715404589535143824642" |
641 | "343213268894641827684675467035375169860499105765512820762454" |
642 | "900903893289440758685084551339423045832369032229481658085593" |
643 | "321233482747978262041447231687381771809192998812504040261841" |
644 | "2485836800+308;" }, |
645 | {"(EN319.310,';')" , |
646 | " 179." |
647 | "769313486231570814527423731704356798070567525844996598917476" |
648 | "803157260780028538760589558632766878171540458953514382464234" |
649 | "321326889464182768467546703537516986049910576551282076245490" |
650 | "090389328944075868508455133942304583236903222948165808559332" |
651 | "123348274797826204144723168738177180919299881250404026184124" |
652 | "8583680000+306;" }, |
653 | {"(G0,';')" , ".17976931348623157E+309;" }, |
654 | {"(EX24.13,';')" , " 0XF.FFFFFFFFFFFF8P+1020;" }, |
655 | }}, |
656 | {// EX rounding |
657 | 0x3ff0100000000000uLL, |
658 | { |
659 | {"(F11.8,';')" , " 1.00390625;" }, |
660 | {"(EX10.2,';')" , " 0X8.08P-3;" }, |
661 | {"(EX10.1,';')" , " 0X8.0P-3;" }, |
662 | {"(EX10.0,';')" , " 0X8.08P-3;" }, |
663 | {"(EX0.0,';')" , "0X8.08P-3;" }, |
664 | {"(EX0,';')" , "0X8.08P-3;" }, |
665 | {"(RN,EX10.1,';')" , " 0X8.0P-3;" }, |
666 | {"(RU,EX10.1,';')" , " 0X8.1P-3;" }, |
667 | {"(RD,EX10.1,';')" , " 0X8.0P-3;" }, |
668 | {"(RZ,EX10.1,';')" , " 0X8.0P-3;" }, |
669 | {"(RC,EX10.1,';')" , " 0X8.1P-3;" }, |
670 | {"(RN,EX10.0,';')" , " 0X8.08P-3;" }, |
671 | {"(RU,EX10.0,';')" , " 0X8.08P-3;" }, |
672 | {"(RD,EX10.0,';')" , " 0X8.08P-3;" }, |
673 | {"(RZ,EX10.0,';')" , " 0X8.08P-3;" }, |
674 | {"(RC,EX10.0,';')" , " 0X8.08P-3;" }, |
675 | }}, |
676 | {// EX rounding |
677 | 0xbff0100000000000uLL, |
678 | { |
679 | {"(F11.8,';')" , "-1.00390625;" }, |
680 | {"(EX10.2,';')" , "-0X8.08P-3;" }, |
681 | {"(EX10.1,';')" , " -0X8.0P-3;" }, |
682 | {"(EX10.0,';')" , "-0X8.08P-3;" }, |
683 | {"(EX0.0,';')" , "-0X8.08P-3;" }, |
684 | {"(EX0,';')" , "-0X8.08P-3;" }, |
685 | {"(RN,EX10.1,';')" , " -0X8.0P-3;" }, |
686 | {"(RU,EX10.1,';')" , " -0X8.0P-3;" }, |
687 | {"(RD,EX10.1,';')" , " -0X8.1P-3;" }, |
688 | {"(RZ,EX10.1,';')" , " -0X8.0P-3;" }, |
689 | {"(RC,EX10.1,';')" , " -0X8.1P-3;" }, |
690 | {"(RN,EX10.0,';')" , "-0X8.08P-3;" }, |
691 | {"(RU,EX10.0,';')" , "-0X8.08P-3;" }, |
692 | {"(RD,EX10.0,';')" , "-0X8.08P-3;" }, |
693 | {"(RZ,EX10.0,';')" , "-0X8.08P-3;" }, |
694 | {"(RC,EX10.0,';')" , "-0X8.08P-3;" }, |
695 | }}, |
696 | }; |
697 | |
698 | for (auto const &[value, cases] : testCases) { |
699 | for (auto const &[format, expect] : cases) { |
700 | std::string got; |
701 | ASSERT_TRUE(CompareFormatReal(format, value, expect, got)) |
702 | << "Failed to format " << format << ", expected '" << expect |
703 | << "', got '" << got << "'" ; |
704 | } |
705 | } |
706 | |
707 | using IndividualTestCaseTy = std::tuple<const char *, double, const char *>; |
708 | static const std::vector<IndividualTestCaseTy> individualTestCases{ |
709 | {"(F5.3,';')" , 25., "*****;" }, |
710 | {"(F5.3,';')" , 2.5, "2.500;" }, |
711 | {"(F5.3,';')" , 0.25, "0.250;" }, |
712 | {"(F5.3,';')" , 0.025, "0.025;" }, |
713 | {"(F5.3,';')" , 0.0025, "0.003;" }, |
714 | {"(F5.3,';')" , 0.00025, "0.000;" }, |
715 | {"(F5.3,';')" , 0.000025, "0.000;" }, |
716 | {"(F5.3,';')" , -25., "*****;" }, |
717 | {"(F5.3,';')" , -2.5, "*****;" }, |
718 | {"(F5.3,';')" , -0.25, "-.250;" }, |
719 | {"(F5.3,';')" , -0.025, "-.025;" }, |
720 | {"(F5.3,';')" , -0.0025, "-.003;" }, |
721 | {"(F5.3,';')" , -0.00025, "-.000;" }, |
722 | {"(F5.3,';')" , -0.000025, "-.000;" }, |
723 | {"(F5.3,';')" , 99.999, "*****;" }, |
724 | {"(F5.3,';')" , 9.9999, "*****;" }, |
725 | {"(F5.3,';')" , 0.99999, "1.000;" }, |
726 | {"(F5.3,';')" , 0.099999, "0.100;" }, |
727 | {"(F5.3,';')" , 0.0099999, "0.010;" }, |
728 | {"(F5.3,';')" , 0.00099999, "0.001;" }, |
729 | {"(F5.3,';')" , |
730 | 0.0005000000000000000104083408558608425664715468883514404296875, |
731 | "0.001;" }, |
732 | {"(F5.3,';')" , |
733 | 0.000499999999999999901988123607310399165726266801357269287109375, |
734 | "0.000;" }, |
735 | {"(F5.3,';')" , 0.000099999, "0.000;" }, |
736 | {"(F5.3,';')" , -99.999, "*****;" }, |
737 | {"(F5.3,';')" , -9.9999, "*****;" }, |
738 | {"(F5.3,';')" , -0.99999, "*****;" }, |
739 | {"(F5.3,';')" , -0.099999, "-.100;" }, |
740 | {"(F5.3,';')" , -0.0099999, "-.010;" }, |
741 | {"(F5.3,';')" , -0.00099999, "-.001;" }, |
742 | {"(F5.3,';')" , |
743 | -0.0005000000000000000104083408558608425664715468883514404296875, |
744 | "-.001;" }, |
745 | {"(F5.3,';')" , |
746 | -0.000499999999999999901988123607310399165726266801357269287109375, |
747 | "-.000;" }, |
748 | {"(F5.3,';')" , -0.000099999, "-.000;" }, |
749 | {"(F0.1,';')" , 0.0, ".0;" }, |
750 | {"(F5.0,';')" , -0.5000000000000001, " -1.;" }, |
751 | {"(F5.0,';')" , -0.5, " -0.;" }, |
752 | {"(F5.0,';')" , -0.49999999999999994, " -0.;" }, |
753 | {"(F5.0,';')" , 0.49999999999999994, " 0.;" }, |
754 | {"(F5.0,';')" , 0.5, " 0.;" }, |
755 | {"(F5.0,';')" , 0.5000000000000001, " 1.;" }, |
756 | }; |
757 | |
758 | for (auto const &[format, value, expect] : individualTestCases) { |
759 | std::string got; |
760 | char hex[17]; |
761 | std::snprintf(s: hex, maxlen: sizeof hex, format: "%016llx" , |
762 | *reinterpret_cast<const unsigned long long *>(&value)); |
763 | ASSERT_TRUE(CompareFormatReal(format, value, expect, got)) |
764 | << "Failed to format " << value << " 0x" << hex << " with format " |
765 | << format << ", expected '" << expect << "', got '" << got << "'" ; |
766 | } |
767 | |
768 | // Problematic EN formatting edge cases with rounding |
769 | using IndividualENTestCaseTy = std::tuple<std::uint64_t, const char *>; |
770 | static const std::vector<IndividualENTestCaseTy> individualENTestCases{ |
771 | {0x3E11183197785F8C, " 995.0E-12" }, // 0.9950312500000000115852E-09 |
772 | {0x3E11180E68455D30, " 995.0E-12" }, // 0.9949999999999999761502E-09 |
773 | {0x3E112BD8F4F6B0D7, " 999.5E-12" }, // 0.9994999999999999089118E-09 |
774 | {0x3E45794883CA8782, " 10.0E-09" }, // 0.9999499999999999642266E-08 |
775 | {0x3F506218230C7482, " 999.9E-06" }, // 0.9999499999999998840761E-03 |
776 | {0x3FB99652BD3C3612, " 100.0E-03" }, // 0.9999500000000000055067E+00 |
777 | {0x4023E66666666667, " 10.0E+00" }, // 0.9950000000000001065814E+01 |
778 | }; |
779 | |
780 | for (auto const &[value, expect] : individualENTestCases) { |
781 | std::string got; |
782 | ASSERT_TRUE(CompareFormatReal("(EN10.1)" , value, expect, got)) |
783 | << "Failed to format EN10.1, expected '" << expect << "', got '" << got |
784 | << "'" ; |
785 | } |
786 | } |
787 | |
788 | TEST(IOApiTests, FormatIntegerValues) { |
789 | using IntTestCaseTy = std::tuple<const char *, std::int64_t, const char *>; |
790 | static const std::vector<IntTestCaseTy> intTestCases{ |
791 | {"(I4)" , 0, " 0" }, |
792 | {"(I4)" , 1, " 1" }, |
793 | {"(I4)" , 9999, "9999" }, |
794 | {"(SP,I4)" , 1, " +1" }, |
795 | {"(SP,I4)" , 9999, "****" }, |
796 | {"(SP,I4)" , 999, "+999" }, |
797 | {"(I4)" , -1, " -1" }, |
798 | {"(I4)" , -9999, "****" }, |
799 | {"(I4)" , -999, "-999" }, |
800 | {"(I4.2)" , 1, " 01" }, |
801 | {"(I4.2)" , -1, " -01" }, |
802 | {"(I4.2)" , 999, " 999" }, |
803 | {"(I4.4)" , 999, "0999" }, |
804 | {"(I0)" , 0, "0" }, |
805 | {"(I0)" , 1, "1" }, |
806 | {"(I0)" , 9999, "9999" }, |
807 | {"(SP,I0)" , 1, "+1" }, |
808 | {"(SP,I0)" , 9999, "+9999" }, |
809 | {"(SP,I0)" , 999, "+999" }, |
810 | {"(I0)" , -1, "-1" }, |
811 | {"(I0)" , -9999, "-9999" }, |
812 | {"(I0)" , -999, "-999" }, |
813 | {"(I0.2)" , 1, "01" }, |
814 | {"(I0.2)" , -1, "-01" }, |
815 | {"(I0.2)" , 999, "999" }, |
816 | {"(I0.4)" , 999, "0999" }, |
817 | {"(G4)" , 0, " 0" }, |
818 | {"(G4)" , 1, " 1" }, |
819 | {"(G4)" , 9999, "9999" }, |
820 | {"(SP,G4)" , 1, " +1" }, |
821 | {"(SP,G4)" , 9999, "****" }, |
822 | {"(SP,G4)" , 999, "+999" }, |
823 | {"(G4)" , -1, " -1" }, |
824 | {"(G4)" , -9999, "****" }, |
825 | {"(G4)" , -999, "-999" }, |
826 | {"(G4.2)" , 1, " 1" }, |
827 | {"(G4.2)" , -1, " -1" }, |
828 | {"(G4.2)" , 999, " 999" }, |
829 | {"(G4.4)" , 999, " 999" }, |
830 | {"(G0)" , 0, "0" }, |
831 | {"(G0)" , 1, "1" }, |
832 | {"(G0)" , 9999, "9999" }, |
833 | {"(SP,G0)" , 1, "+1" }, |
834 | {"(SP,G0)" , 9999, "+9999" }, |
835 | {"(SP,G0)" , 999, "+999" }, |
836 | {"(G0)" , -1, "-1" }, |
837 | {"(G0)" , -9999, "-9999" }, |
838 | {"(G0)" , -999, "-999" }, |
839 | {"(G0.2)" , 1, "1" }, |
840 | {"(G0.2)" , -1, "-1" }, |
841 | {"(G0.2)" , 999, "999" }, |
842 | {"(G0.4)" , 999, "999" }, |
843 | }; |
844 | |
845 | for (auto const &[fmt, value, expect] : intTestCases) { |
846 | std::string got; |
847 | ASSERT_TRUE(CompareFormatInteger(fmt, value, expect, got)) |
848 | << "Failed to format " << fmt << ", expected '" << expect << "', got '" |
849 | << got << "'" ; |
850 | } |
851 | } |
852 | |
853 | //------------------------------------------------------------------------------ |
854 | /// Tests for input editing real values |
855 | //------------------------------------------------------------------------------ |
856 | |
857 | // Ensure double input values correctly map to raw uint64 values |
858 | TEST(IOApiTests, EditDoubleInputValues) { |
859 | using TestCaseTy = std::tuple<const char *, const char *, std::uint64_t, int>; |
860 | int ovf{IostatRealInputOverflow}; |
861 | static const std::vector<TestCaseTy> testCases{ |
862 | {"(F18.0)" , " 0" , 0x0, 0}, |
863 | {"(F18.0)" , " " , 0x0, 0}, |
864 | {"(F18.0)" , " -0" , 0x8000000000000000, 0}, |
865 | {"(F18.0)" , " 01" , 0x3ff0000000000000, 0}, |
866 | {"(F18.0)" , " 1" , 0x3ff0000000000000, 0}, |
867 | {"(F18.0)" , " 125." , 0x405f400000000000, 0}, |
868 | {"(F18.0)" , " 12.5" , 0x4029000000000000, 0}, |
869 | {"(F18.0)" , " 1.25" , 0x3ff4000000000000, 0}, |
870 | {"(F18.0)" , " 01.25" , 0x3ff4000000000000, 0}, |
871 | {"(F18.0)" , " .125" , 0x3fc0000000000000, 0}, |
872 | {"(F18.0)" , " 0.125" , 0x3fc0000000000000, 0}, |
873 | {"(F18.0)" , " .0625" , 0x3fb0000000000000, 0}, |
874 | {"(F18.0)" , " 0.0625" , 0x3fb0000000000000, 0}, |
875 | {"(F18.0)" , " 125" , 0x405f400000000000, 0}, |
876 | {"(F18.1)" , " 125" , 0x4029000000000000, 0}, |
877 | {"(F18.2)" , " 125" , 0x3ff4000000000000, 0}, |
878 | {"(F18.3)" , " 125" , 0x3fc0000000000000, 0}, |
879 | {"(-1P,F18.0)" , " 125" , 0x4093880000000000, 0}, // 1250 |
880 | {"(1P,F18.0)" , " 125" , 0x4029000000000000, 0}, // 12.5 |
881 | {"(BZ,F18.0)" , " 125 " , 0x4093880000000000, 0}, // 1250 |
882 | {"(BZ,F18.0)" , " 125 . e +1 " , 0x42a6bcc41e900000, 0}, // 1.25e13 |
883 | {"(BZ,F18.0)" , " . " , 0x0, 0}, |
884 | {"(BZ,F18.0)" , " . e +1 " , 0x0, 0}, |
885 | {"(DC,F18.0)" , " 12,5" , 0x4029000000000000, 0}, |
886 | {"(EX22.0)" , "0X0P0 " , 0x0, 0}, // +0. |
887 | {"(EX22.0)" , "-0X0P0 " , 0x8000000000000000, 0}, // -0. |
888 | {"(EX22.0)" , "0X.8P1 " , 0x3ff0000000000000, 0}, // 1.0 |
889 | {"(EX22.0)" , "0X8.P-3 " , 0x3ff0000000000000, 0}, // 1.0 |
890 | {"(EX22.0)" , "0X.1P4 " , 0x3ff0000000000000, 0}, // 1.0 |
891 | {"(EX22.0)" , "0X10.P-4 " , 0x3ff0000000000000, 0}, // 1.0 |
892 | {"(EX22.0)" , "0X8.00P-3 " , 0x3ff0000000000000, 0}, // 1.0 |
893 | {"(EX22.0)" , "0X80.0P-6 " , 0x4000000000000000, 0}, // 2.0 |
894 | {"(EX22.0)" , "0XC.CCCCCCCCCCCDP-7 " , 0x3fb999999999999a, 0}, // 0.1 |
895 | {"(EX22.0)" , "0X.8P-1021 " , 0x0010000000000000, |
896 | 0}, // min normal |
897 | {"(EX22.0)" , "0X.8P-1022 " , 0x0008000000000000, |
898 | 0}, // subnormal |
899 | {"(EX22.0)" , "0X.8P-1073 " , 0x0000000000000001, |
900 | 0}, // min subn. |
901 | {"(EX22.0)" , "0X.FFFFFFFFFFFFF8P1024" , 0x7fefffffffffffff, |
902 | 0}, // max finite |
903 | {"(EX22.0)" , "0X.8P1025 " , 0x7ff0000000000000, ovf}, // +Inf |
904 | {"(EX22.0)" , "-0X.8P1025 " , 0xfff0000000000000, ovf}, // -Inf |
905 | {"(RC,EX22.0)" , "0X1.0000000000000P0 " , 0x3ff0000000000000, 0}, |
906 | {"(RC,EX22.0)" , "0X1.00000000000008P0 " , 0x3ff0000000000001, 0}, |
907 | {"(RC,EX22.0)" , "0X1.000000000000008P0 " , 0x3ff0000000000000, 0}, |
908 | {"(RC,EX22.0)" , "0X1.00000000000004P0 " , 0x3ff0000000000000, 0}, |
909 | {"(RC,EX22.0)" , "0X.80000000000000P1 " , 0x3ff0000000000000, 0}, |
910 | {"(RC,EX22.0)" , "0X.80000000000004P1 " , 0x3ff0000000000001, 0}, |
911 | {"(RC,EX22.0)" , "0X.800000000000004P1 " , 0x3ff0000000000000, 0}, |
912 | {"(RC,EX22.0)" , "0X.80000000000002P1 " , 0x3ff0000000000000, 0}, |
913 | {"(RZ,F7.0)" , " 2.e308" , 0x7fefffffffffffff, 0}, // +HUGE() |
914 | {"(RD,F7.0)" , " 2.e308" , 0x7fefffffffffffff, 0}, // +HUGE() |
915 | {"(RU,F7.0)" , " 2.e308" , 0x7ff0000000000000, ovf}, // +Inf |
916 | {"(RZ,F7.0)" , "-2.e308" , 0xffefffffffffffff, 0}, // -HUGE() |
917 | {"(RD,F7.0)" , "-2.e308" , 0xfff0000000000000, ovf}, // -Inf |
918 | {"(RU,F7.0)" , "-2.e308" , 0xffefffffffffffff, 0}, // -HUGE() |
919 | {"(RZ,F7.0)" , " 1.e999" , 0x7fefffffffffffff, 0}, // +HUGE() |
920 | {"(RD,F7.0)" , " 1.e999" , 0x7fefffffffffffff, 0}, // +HUGE() |
921 | {"(RU,F7.0)" , " 1.e999" , 0x7ff0000000000000, ovf}, // +Inf |
922 | {"(RZ,F7.0)" , "-1.e999" , 0xffefffffffffffff, 0}, // -HUGE() |
923 | {"(RD,F7.0)" , "-1.e999" , 0xfff0000000000000, ovf}, // -Inf |
924 | {"(RU,F7.0)" , "-1.e999" , 0xffefffffffffffff, 0}, // -HUGE() |
925 | {"(E9.1)" , " 1.0E-325" , 0x0, 0}, |
926 | {"(RU,E9.1)" , " 1.0E-325" , 0x1, 0}, |
927 | {"(E9.1)" , "-1.0E-325" , 0x8000000000000000, 0}, |
928 | {"(RD,E9.1)" , "-1.0E-325" , 0x8000000000000001, 0}, |
929 | }; |
930 | for (auto const &[format, data, want, iostat] : testCases) { |
931 | auto cookie{IONAME(BeginInternalFormattedInput)( |
932 | data, std::strlen(data), format, std::strlen(format))}; |
933 | union { |
934 | double x; |
935 | std::uint64_t raw; |
936 | } u; |
937 | u.raw = 0; |
938 | |
939 | // Read buffer into union value |
940 | IONAME(EnableHandlers)(cookie, true, true, true, true, true); |
941 | IONAME(InputReal64)(cookie, u.x); |
942 | |
943 | static constexpr int bufferSize{65}; |
944 | char iomsg[bufferSize]; |
945 | std::memset(s: iomsg, c: '\0', n: bufferSize - 1); |
946 | |
947 | // Ensure no unexpected errors were encountered reading input buffer into |
948 | // union value |
949 | IONAME(GetIoMsg)(cookie, iomsg, bufferSize - 1); |
950 | auto status{IONAME(EndIoStatement)(cookie)}; |
951 | ASSERT_EQ(status, iostat) |
952 | << '\'' << format << "' failed reading '" << data << "', status " |
953 | << static_cast<int>(status) << " != expected " << iostat << " iomsg '" |
954 | << iomsg << "'" ; |
955 | |
956 | // Ensure raw uint64 value matches expected conversion from double |
957 | ASSERT_EQ(u.raw, want) << '\'' << format << "' failed reading '" << data |
958 | << "', want " << want << ", got " << u.raw; |
959 | } |
960 | } |
961 | |