Line data Source code
1 : // Copyright (c) 2019-2025 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/prinbee
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : // self
20 : //
21 : #include "catch_main.h"
22 :
23 :
24 : // prinbee
25 : //
26 : #include <prinbee/data/virtual_buffer.h>
27 :
28 :
29 : // advgetopt
30 : //
31 : #include <advgetopt/options.h>
32 :
33 :
34 : // last include
35 : //
36 : #include <snapdev/poison.h>
37 :
38 :
39 :
40 5 : CATCH_TEST_CASE("virtual_buffer", "[virtual-buffer]")
41 : {
42 7 : CATCH_START_SECTION("virtual_buffer: simple write + read")
43 : {
44 1 : prinbee::virtual_buffer::pointer_t v(std::make_shared<prinbee::virtual_buffer>());
45 1 : CATCH_REQUIRE(v->size() == 0);
46 1 : CATCH_REQUIRE(v->count_buffers() == 0);
47 :
48 1 : constexpr std::size_t const buf_size(1024);
49 1 : char buf[buf_size];
50 1025 : for(std::size_t i(0); i < sizeof(buf); ++i)
51 : {
52 1024 : buf[i] = rand();
53 : }
54 1 : CATCH_REQUIRE(v->pwrite(buf, sizeof(buf), 0, true) == sizeof(buf));
55 :
56 1 : CATCH_REQUIRE(v->size() == sizeof(buf));
57 1 : CATCH_REQUIRE(v->count_buffers() == 1); // one write means at most 1 buffer
58 :
59 1 : char saved[buf_size];
60 1 : CATCH_REQUIRE(v->pread(saved, sizeof(saved), 0, true) == sizeof(saved));
61 :
62 1 : CATCH_REQUIRE(sizeof(buf) == sizeof(saved));
63 1 : CATCH_REQUIRE(memcmp(buf, saved, sizeof(buf)) == 0);
64 1 : }
65 6 : CATCH_END_SECTION()
66 :
67 7 : CATCH_START_SECTION("virtual_buffer: write once + read many times")
68 : {
69 1 : prinbee::virtual_buffer::pointer_t v(std::make_shared<prinbee::virtual_buffer>());
70 1 : CATCH_REQUIRE(v->size() == 0);
71 1 : CATCH_REQUIRE(v->count_buffers() == 0);
72 :
73 1 : constexpr size_t const buf_size(1024);
74 1 : char buf[buf_size];
75 1025 : for(size_t i(0); i < sizeof(buf); ++i)
76 : {
77 1024 : buf[i] = rand();
78 : }
79 1 : CATCH_REQUIRE(v->pwrite(buf, sizeof(buf), 0, true) == sizeof(buf));
80 :
81 1 : CATCH_REQUIRE(v->size() == sizeof(buf));
82 1 : CATCH_REQUIRE(v->count_buffers() == 1); // one write means at most 1 buffer
83 :
84 1025 : for(size_t i(0); i < sizeof(buf); ++i)
85 : {
86 1024 : char c;
87 1024 : CATCH_REQUIRE(v->pread(&c, sizeof(c), i, true) == sizeof(c));
88 1024 : CATCH_REQUIRE(buf[i] == c);
89 : }
90 1 : }
91 6 : CATCH_END_SECTION()
92 :
93 7 : CATCH_START_SECTION("virtual_buffer: short write + read several times")
94 : {
95 1 : prinbee::virtual_buffer::pointer_t v(std::make_shared<prinbee::virtual_buffer>());
96 1 : CATCH_REQUIRE(v->size() == 0);
97 1 : CATCH_REQUIRE(v->count_buffers() == 0);
98 :
99 1 : constexpr size_t const buf_size(1024);
100 1 : char buf[buf_size];
101 1025 : for(size_t i(0); i < sizeof(buf); ++i)
102 : {
103 1024 : buf[i] = rand();
104 : }
105 1 : CATCH_REQUIRE(v->pwrite(buf, sizeof(buf), 0, true) == sizeof(buf));
106 :
107 1 : CATCH_REQUIRE(v->size() == sizeof(buf));
108 1 : CATCH_REQUIRE(v->count_buffers() == 1); // one write means at most 1 buffer
109 :
110 : // update the first 4 bytes
111 : //
112 1 : buf[0] = rand();
113 1 : buf[1] = rand();
114 1 : buf[2] = rand();
115 1 : buf[3] = rand();
116 1 : CATCH_REQUIRE(v->pwrite(buf, 4, 0, false) == 4);
117 :
118 1 : CATCH_REQUIRE(v->size() == sizeof(buf));
119 1 : CATCH_REQUIRE(v->count_buffers() == 1); // overwrite does not add more buffers
120 :
121 1025 : for(size_t i(0); i < sizeof(buf); ++i)
122 : {
123 1024 : char c;
124 1024 : CATCH_REQUIRE(v->pread(&c, sizeof(c), i, true) == sizeof(c));
125 1024 : CATCH_REQUIRE(buf[i] == c);
126 : }
127 1 : }
128 6 : CATCH_END_SECTION()
129 :
130 7 : CATCH_START_SECTION("virtual_buffer: simple write + read + erase + read")
131 : {
132 1 : prinbee::virtual_buffer::pointer_t v(std::make_shared<prinbee::virtual_buffer>());
133 1 : CATCH_REQUIRE(v->size() == 0);
134 1 : CATCH_REQUIRE(v->count_buffers() == 0);
135 :
136 1 : constexpr std::size_t const buf_size(1024 * 8);
137 1 : char buf[buf_size];
138 8193 : for(std::size_t i(0); i < sizeof(buf); ++i)
139 : {
140 8192 : buf[i] = rand();
141 : }
142 1 : CATCH_REQUIRE(v->pwrite(buf, sizeof(buf), 0, true) == sizeof(buf));
143 :
144 1 : CATCH_REQUIRE(v->size() == sizeof(buf));
145 1 : CATCH_REQUIRE(v->count_buffers() == 1); // one write means at most 1 buffer
146 :
147 1 : char saved[buf_size];
148 1 : CATCH_REQUIRE(v->pread(saved, sizeof(saved), 0, true) == sizeof(saved));
149 :
150 1 : CATCH_REQUIRE(sizeof(buf) == sizeof(saved));
151 1 : CATCH_REQUIRE(memcmp(buf, saved, sizeof(buf)) == 0);
152 :
153 : // erase 1024 bytes at offset 4096
154 : //
155 1 : CATCH_REQUIRE(v->perase(1024, 4096) == 1024);
156 1 : CATCH_REQUIRE(v->pread(saved, 4096, 0, true) == 4096);
157 1 : CATCH_REQUIRE(memcmp(buf, saved, 4096) == 0);
158 1 : CATCH_REQUIRE(v->pread(saved, 3072, 4096, true) == 3072);
159 1 : CATCH_REQUIRE(memcmp(buf + 4096 + 1024, saved, 3072) == 0);
160 1 : }
161 6 : CATCH_END_SECTION()
162 :
163 7 : CATCH_START_SECTION("virtual_buffer: many writes + read + (erase + read) * N")
164 : {
165 1 : prinbee::virtual_buffer::pointer_t v(std::make_shared<prinbee::virtual_buffer>());
166 1 : CATCH_REQUIRE(v->size() == 0);
167 1 : CATCH_REQUIRE(v->count_buffers() == 0);
168 :
169 : // create a buffer of many Kb (at least 150Kb up to 512Kb
170 : //
171 1 : std::uint64_t buf_size(0);
172 : for(;;)
173 : {
174 2 : SNAP_CATCH2_NAMESPACE::random(buf_size);
175 2 : buf_size %= 512 * 1024;
176 2 : ++buf_size;
177 2 : if(buf_size >= 150 * 1024)
178 : {
179 1 : break;
180 : }
181 : }
182 1 : prinbee::buffer_t buf;
183 1 : buf.reserve(buf_size);
184 206571 : for(std::uint64_t i(0); i < buf_size; ++i)
185 : {
186 206570 : buf.push_back(rand());
187 : }
188 :
189 : // write the buffer in small chunks so that way we get "many"
190 : // virtual buffers instead of one large one
191 : //
192 1 : std::uint64_t written(0);
193 414 : while(written < buf_size)
194 : {
195 413 : std::uint64_t sz(0);
196 413 : SNAP_CATCH2_NAMESPACE::random(sz);
197 413 : sz %= 1024;
198 413 : ++sz; // 1 to 1024
199 413 : sz = std::min(buf_size - written, sz);
200 413 : CATCH_REQUIRE(v->pwrite(buf.data() + written, sz, written, true) == static_cast<int>(sz));
201 413 : written += sz;
202 413 : CATCH_REQUIRE(v->size() == written);
203 : }
204 :
205 1 : CATCH_REQUIRE(v->size() == buf_size);
206 1 : CATCH_REQUIRE(v->count_buffers() > 1);
207 :
208 : // verify we can read the whole lot of data and it is equal to buffer
209 : //
210 3 : prinbee::buffer_t saved(buf_size);
211 1 : CATCH_REQUIRE(v->pread(saved.data(), buf_size, 0, true) == static_cast<int>(buf_size));
212 1 : CATCH_REQUIRE(buf == saved);
213 :
214 : // erase the whole buffer a little bit at a time and verify the
215 : // result each time
216 : //
217 833 : while(v->size() > 0)
218 : {
219 832 : std::uint64_t sz(0);
220 832 : SNAP_CATCH2_NAMESPACE::random(sz);
221 832 : sz %= 512;
222 832 : ++sz; // 1 to 512 bytes to delete
223 832 : sz = std::min(sz, v->size());
224 :
225 832 : std::uint64_t offset(0);
226 832 : if(v->size() > sz)
227 : {
228 831 : SNAP_CATCH2_NAMESPACE::random(offset);
229 831 : offset %= v->size() - sz;
230 : }
231 :
232 832 : if(sz + offset == v->size())
233 : {
234 : // a larger size at the end has no effect because we adjust
235 : // it to v->size() internally
236 : //
237 1 : std::uint64_t const extra(rand() % 4096 + 1);
238 2 : SNAP_LOG_WARNING << "--- perase(" << sz << " + " << extra << " [" << sz + extra << "], " << offset << "); ..." << SNAP_LOG_SEND;
239 1 : CATCH_REQUIRE(v->perase(sz + extra, offset) == static_cast<int>(sz));
240 : }
241 : else
242 : {
243 1662 : SNAP_LOG_WARNING << "--- perase(" << sz << ", " << offset << "); ..." << SNAP_LOG_SEND;
244 831 : CATCH_REQUIRE(v->perase(sz, offset) == static_cast<int>(sz));
245 : }
246 :
247 : // also apply the erase to our local buffer
248 : //
249 832 : buf.erase(buf.begin() + offset, buf.begin() + offset + sz);
250 :
251 : // get a copy of the full buffer and compare, it must be 100% equal
252 : //
253 2496 : prinbee::buffer_t latest(buf.size());
254 1664 : SNAP_LOG_WARNING << "--- read result (" << buf.size() << ") ..." << SNAP_LOG_SEND;
255 832 : CATCH_REQUIRE(v->pread(latest.data(), buf.size(), 0, true) == static_cast<int>(buf.size()));
256 : //CATCH_REQUIRE(buf == latest); -- output for this one is awful
257 832 : CATCH_REQUIRE_LARGE_BUFFER(buf.data(), buf.size(), latest.data(), latest.size());
258 832 : }
259 : //CATCH_REQUIRE(v->perase(1024, 4096) == 1024);
260 : //CATCH_REQUIRE(v->pread(saved, 4096, 0, true) == 4096);
261 : //CATCH_REQUIRE(memcmp(buf, saved, 4096) == 0);
262 : //CATCH_REQUIRE(v->pread(saved, 3072, 4096, true) == 3072);
263 : //CATCH_REQUIRE(memcmp(buf + 4096 + 1024, saved, 3072) == 0);
264 1 : }
265 6 : CATCH_END_SECTION()
266 5 : }
267 :
268 :
269 : // vim: ts=4 sw=4 et
|