1 //===-- flang/unittests/Runtime/BufferTest.cpp ------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "../../runtime/buffer.h"
10 #include "CrashHandlerFixture.h"
11 #include "gtest/gtest.h"
17 static constexpr std::size_t tinyBufferSize
{32};
18 using FileOffset
= std::int64_t;
19 using namespace Fortran::runtime
;
20 using namespace Fortran::runtime::io
;
22 class Store
: public FileFrame
<Store
, tinyBufferSize
> {
24 explicit Store(std::size_t bytes
= 65536) : bytes_
{bytes
} {
25 data_
.reset(new char[bytes
]);
26 std::memset(&data_
[0], 0, bytes
);
28 std::size_t bytes() const { return bytes_
; }
29 void set_enforceSequence(bool yes
= true) { enforceSequence_
= yes
; }
30 void set_expect(FileOffset to
) { expect_
= to
; }
32 std::size_t Read(FileOffset at
, char *to
, std::size_t minBytes
,
33 std::size_t maxBytes
, IoErrorHandler
&handler
) {
34 if (enforceSequence_
&& at
!= expect_
) {
35 handler
.SignalError("Read(%d,%d,%d) not at expected %d",
36 static_cast<int>(at
), static_cast<int>(minBytes
),
37 static_cast<int>(maxBytes
), static_cast<int>(expect_
));
38 } else if (at
< 0 || at
+ minBytes
> bytes_
) {
39 handler
.SignalError("Read(%d,%d,%d) is out of bounds",
40 static_cast<int>(at
), static_cast<int>(minBytes
),
41 static_cast<int>(maxBytes
));
43 auto result
{std::min
<std::size_t>(maxBytes
, bytes_
- at
)};
44 std::memcpy(to
, &data_
[at
], result
);
45 expect_
= at
+ result
;
48 std::size_t Write(FileOffset at
, const char *from
, std::size_t bytes
,
49 IoErrorHandler
&handler
) {
50 if (enforceSequence_
&& at
!= expect_
) {
51 handler
.SignalError("Write(%d,%d) not at expected %d",
52 static_cast<int>(at
), static_cast<int>(bytes
),
53 static_cast<int>(expect_
));
54 } else if (at
< 0 || at
+ bytes
> bytes_
) {
55 handler
.SignalError("Write(%d,%d) is out of bounds", static_cast<int>(at
),
56 static_cast<int>(bytes
));
58 std::memcpy(&data_
[at
], from
, bytes
);
65 std::unique_ptr
<char[]> data_
;
66 bool enforceSequence_
{false};
67 FileOffset expect_
{0};
70 inline int ChunkSize(int j
, int most
) {
71 // 31, 1, 29, 3, 27, ...
73 auto chunk
{static_cast<int>(
74 ((j
% 2) ? j
: (tinyBufferSize
- 1 - j
)) % tinyBufferSize
)};
75 return std::min(chunk
, most
);
78 inline int ValueFor(int at
) { return (at
^ (at
>> 8)) & 0xff; }
80 struct BufferTests
: CrashHandlerFixture
{};
82 TEST(BufferTests
, TestFrameBufferReadAndWrite
) {
83 Terminator terminator
{__FILE__
, __LINE__
};
84 IoErrorHandler handler
{terminator
};
86 store
.set_enforceSequence(true);
87 const auto bytes
{static_cast<FileOffset
>(store
.bytes())};
88 // Fill with an assortment of chunks
91 auto chunk
{ChunkSize(j
, static_cast<int>(bytes
- at
))};
92 store
.WriteFrame(at
, chunk
, handler
);
93 char *to
{store
.Frame()};
94 for (int k
{0}; k
< chunk
; ++k
) {
95 to
[k
] = ValueFor(at
+ k
);
100 store
.Flush(handler
);
105 auto chunk
{ChunkSize(j
, static_cast<int>(bytes
- at
))};
106 std::size_t frame
{store
.ReadFrame(at
, chunk
, handler
)};
107 ASSERT_GE(frame
, static_cast<std::size_t>(chunk
))
108 << "Badly-sized ReadFrame at " << at
<< ", chunk=" << chunk
<< ", got "
111 const char *from
{store
.Frame()};
112 for (int k
{0}; k
< chunk
; ++k
) {
113 auto expect
{static_cast<char>(ValueFor(at
+ k
))};
114 ASSERT_EQ(from
[k
], expect
)
115 << "At " << at
<< '+' << k
<< '(' << (at
+ k
) << "), read "
116 << (from
[k
] & 0xff) << ", expected " << static_cast<int>(expect
)