1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include <algorithm>
16 #include <array>
17 #include <cstddef>
18 #include <cstring>
19
20 #include "public/pw_kvs/flash_memory.h"
21 #include "pw_kvs/fake_flash_memory.h"
22 #include "pw_kvs/flash_memory.h"
23 #include "pw_kvs_private/config.h"
24 #include "pw_log/log.h"
25 #include "pw_random/xor_shift.h"
26 #include "pw_span/span.h"
27 #include "pw_unit_test/framework.h"
28
29 #if PW_CXX_STANDARD_IS_SUPPORTED(17)
30
31 #ifndef PW_FLASH_TEST_ALIGNMENT
32 #define PW_FLASH_TEST_ALIGNMENT 1
33 #endif
34
35 namespace pw::kvs {
36 namespace {
37
38 class FlashStreamTest : public ::testing::Test {
39 protected:
FlashStreamTest()40 FlashStreamTest() : flash_(kFlashAlignment), partition_(&flash_) {}
41
InitBufferToFill(ByteSpan buffer_span,char fill)42 void InitBufferToFill(ByteSpan buffer_span, char fill) {
43 std::memset(buffer_span.data(), fill, buffer_span.size_bytes());
44 }
45
InitBufferToRandom(ByteSpan buffer_span,uint64_t seed)46 void InitBufferToRandom(ByteSpan buffer_span, uint64_t seed) {
47 random::XorShiftStarRng64 rng(seed);
48
49 std::memset(buffer_span.data(),
50 static_cast<int>(flash_.erased_memory_content()),
51 buffer_span.size());
52 rng.Get(buffer_span);
53 }
54
VerifyFlash(ConstByteSpan verify_bytes,size_t offset=0)55 void VerifyFlash(ConstByteSpan verify_bytes, size_t offset = 0) {
56 // Should be defined as same size.
57 EXPECT_EQ(source_buffer_.size(), flash_.buffer().size_bytes());
58
59 // Can't allow it to march off the end of source_buffer_.
60 ASSERT_LE((verify_bytes.size_bytes() + offset), source_buffer_.size());
61
62 for (size_t i = 0; i < verify_bytes.size_bytes(); i++) {
63 ASSERT_EQ(source_buffer_[i + offset], verify_bytes[i]);
64 }
65 }
66
VerifyFlashContent(ConstByteSpan verify_bytes,size_t offset=0)67 void VerifyFlashContent(ConstByteSpan verify_bytes, size_t offset = 0) {
68 // Can't allow it to march off the end of source_buffer_.
69 ASSERT_LE((verify_bytes.size_bytes() + offset),
70 flash_.buffer().size_bytes());
71
72 for (size_t i = 0; i < verify_bytes.size_bytes(); i++) {
73 ASSERT_EQ(flash_.buffer()[i + offset], verify_bytes[i]);
74 }
75 }
76
DoWriteInChunks(size_t chunk_write_size_bytes,uint64_t seed)77 void DoWriteInChunks(size_t chunk_write_size_bytes, uint64_t seed) {
78 InitBufferToRandom(span(source_buffer_), seed);
79 ConstByteSpan write_data = span(source_buffer_);
80
81 ASSERT_EQ(OkStatus(), partition_.Erase());
82
83 FlashPartition::Writer writer(partition_);
84
85 while (write_data.size_bytes() > 0) {
86 size_t offset_before_write = writer.Tell();
87 size_t write_chunk_size =
88 std::min(chunk_write_size_bytes, write_data.size_bytes());
89
90 ConstByteSpan write_chunk = write_data.first(write_chunk_size);
91 ASSERT_EQ(OkStatus(), writer.Write(write_chunk));
92 VerifyFlashContent(write_chunk, offset_before_write);
93
94 write_data = write_data.subspan(write_chunk_size);
95
96 ASSERT_EQ(writer.ConservativeWriteLimit(), write_data.size_bytes());
97 }
98
99 VerifyFlashContent(span(source_buffer_));
100 }
101
DoReadInChunks(size_t chunk_read_size_bytes,uint64_t seed,size_t start_offset,size_t bytes_to_read)102 void DoReadInChunks(size_t chunk_read_size_bytes,
103 uint64_t seed,
104 size_t start_offset,
105 size_t bytes_to_read) {
106 InitBufferToRandom(flash_.buffer(), seed);
107
108 ASSERT_LE((start_offset + bytes_to_read), flash_.buffer().size_bytes());
109
110 FlashPartition::Reader reader(partition_);
111 ASSERT_EQ(reader.ConservativeReadLimit(), flash_.buffer().size_bytes());
112
113 ASSERT_EQ(reader.Seek(start_offset), OkStatus());
114 ASSERT_EQ(reader.ConservativeReadLimit(),
115 flash_.buffer().size_bytes() - start_offset);
116
117 while (bytes_to_read > 0) {
118 ASSERT_EQ(start_offset, reader.Tell());
119
120 size_t chunk_size = std::min(chunk_read_size_bytes, bytes_to_read);
121
122 ByteSpan read_chunk = span(source_buffer_).first(chunk_size);
123 InitBufferToFill(read_chunk, 0);
124 ASSERT_EQ(read_chunk.size_bytes(), chunk_size);
125
126 auto result = reader.Read(read_chunk);
127 ASSERT_EQ(result.status(), OkStatus());
128 ASSERT_EQ(result.value().size_bytes(), chunk_size);
129 VerifyFlashContent(read_chunk, start_offset);
130
131 start_offset += chunk_size;
132 bytes_to_read -= chunk_size;
133
134 ASSERT_EQ(reader.ConservativeReadLimit(),
135 flash_.buffer().size_bytes() - start_offset);
136 }
137 }
138
139 static constexpr size_t kFlashAlignment = PW_FLASH_TEST_ALIGNMENT;
140 static constexpr size_t kSectorSize = 2048;
141 static constexpr size_t kSectorCount = 2;
142 static constexpr size_t kFPDataSize = (kSectorCount * kSectorSize);
143
144 FakeFlashMemoryBuffer<kSectorSize, kSectorCount> flash_;
145 FlashPartition partition_;
146 std::array<std::byte, kFPDataSize> source_buffer_;
147 size_t size_bytes_;
148 };
149
TEST_F(FlashStreamTest,Write_1_Byte_Chunks)150 TEST_F(FlashStreamTest, Write_1_Byte_Chunks) {
151 // Write in 1 byte chunks.
152 DoWriteInChunks(1, 0xab1234);
153 }
154
TEST_F(FlashStreamTest,Write_5_Byte_Chunks)155 TEST_F(FlashStreamTest, Write_5_Byte_Chunks) {
156 // Write in 5 byte chunks.
157 DoWriteInChunks(5, 0xdc2274);
158 }
159
TEST_F(FlashStreamTest,Write_16_Byte_Chunks)160 TEST_F(FlashStreamTest, Write_16_Byte_Chunks) {
161 // Write in 16 byte chunks.
162 DoWriteInChunks(16, 0xef8224);
163 }
164
TEST_F(FlashStreamTest,Write_255_Byte_Chunks)165 TEST_F(FlashStreamTest, Write_255_Byte_Chunks) {
166 // Write in 255 byte chunks.
167 DoWriteInChunks(255, 0xffe1348);
168 }
169
TEST_F(FlashStreamTest,Write_256_Byte_Chunks)170 TEST_F(FlashStreamTest, Write_256_Byte_Chunks) {
171 // Write in 256 byte chunks.
172 DoWriteInChunks(256, 0xe11234);
173 }
174
TEST_F(FlashStreamTest,Read_1_Byte_Chunks)175 TEST_F(FlashStreamTest, Read_1_Byte_Chunks) {
176 // Read in 1 byte chunks.
177 DoReadInChunks(1, 0x7643ff, 0, flash_.buffer().size_bytes());
178 }
179
TEST_F(FlashStreamTest,Read_16_Byte_Chunks)180 TEST_F(FlashStreamTest, Read_16_Byte_Chunks) {
181 // Read in 16 byte chunks.
182 DoReadInChunks(16, 0x61e234, 0, flash_.buffer().size_bytes());
183 }
184
TEST_F(FlashStreamTest,Read_255_Byte_Chunks)185 TEST_F(FlashStreamTest, Read_255_Byte_Chunks) {
186 // Read in 256 byte chunks.
187 DoReadInChunks(255, 0xe13514, 0, flash_.buffer().size_bytes());
188 }
189
TEST_F(FlashStreamTest,Read_256_Byte_Chunks)190 TEST_F(FlashStreamTest, Read_256_Byte_Chunks) {
191 // Read in 256 byte chunks.
192 DoReadInChunks(256, 0xe11234, 0, flash_.buffer().size_bytes());
193 }
194
TEST_F(FlashStreamTest,Read_256_Byte_Chunks_With_Offset)195 TEST_F(FlashStreamTest, Read_256_Byte_Chunks_With_Offset) {
196 // Read in 256 byte chunks.
197 DoReadInChunks(256, 0xfffe34, 1024, (flash_.buffer().size_bytes() - 1024));
198 }
199
TEST_F(FlashStreamTest,Read_Multiple_Seeks)200 TEST_F(FlashStreamTest, Read_Multiple_Seeks) {
201 static const size_t kSeekReadSizeBytes = 512;
202 static const size_t kSeekReadIterations = 4;
203 ASSERT_GE(flash_.buffer().size_bytes(),
204 (kSeekReadIterations * (2 * kSeekReadSizeBytes)));
205
206 InitBufferToRandom(flash_.buffer(), 0xffde176);
207 FlashPartition::Reader reader(partition_);
208
209 for (size_t i = 0; i < kSeekReadIterations; i++) {
210 size_t start_offset = kSeekReadSizeBytes + (i * 2 * kSeekReadSizeBytes);
211 ASSERT_EQ(reader.Seek(start_offset), OkStatus());
212 ASSERT_EQ(start_offset, reader.Tell());
213
214 ByteSpan read_chunk = span(source_buffer_).first(kSeekReadSizeBytes);
215 InitBufferToFill(read_chunk, 0);
216
217 auto result = reader.Read(read_chunk);
218 ASSERT_EQ(result.status(), OkStatus());
219 ASSERT_EQ(result.value().size_bytes(), kSeekReadSizeBytes);
220 VerifyFlashContent(read_chunk, start_offset);
221 ASSERT_EQ(start_offset + kSeekReadSizeBytes, reader.Tell());
222 }
223 }
224
TEST_F(FlashStreamTest,Read_Seeks_With_Limit)225 TEST_F(FlashStreamTest, Read_Seeks_With_Limit) {
226 static const size_t kSeekReadSizeBytes = 512;
227 const size_t kPartitionSize = flash_.buffer().size_bytes();
228 ASSERT_GE(flash_.buffer().size_bytes(), (2 * kSeekReadSizeBytes));
229
230 InitBufferToRandom(flash_.buffer(), 0xffde176);
231 FlashPartition::Reader reader(partition_, kSeekReadSizeBytes);
232
233 ASSERT_EQ(reader.ConservativeReadLimit(), kSeekReadSizeBytes);
234
235 reader.SetReadLimit(5u);
236 ASSERT_EQ(reader.ConservativeReadLimit(), 5u);
237 ASSERT_EQ(0u, reader.Tell());
238
239 reader.SetReadLimit(kPartitionSize + 5);
240 ASSERT_EQ(reader.ConservativeReadLimit(), kPartitionSize);
241 ASSERT_EQ(0u, reader.Tell());
242
243 reader.SetReadLimit(kSeekReadSizeBytes);
244 ASSERT_EQ(reader.ConservativeReadLimit(), kSeekReadSizeBytes);
245 ASSERT_EQ(0u, reader.Tell());
246
247 ASSERT_EQ(reader.Seek(1u), OkStatus());
248 ASSERT_EQ(reader.ConservativeReadLimit(), (kSeekReadSizeBytes - 1));
249 ASSERT_EQ(1u, reader.Tell());
250
251 ASSERT_EQ(reader.Seek(kSeekReadSizeBytes), OkStatus());
252 ASSERT_EQ(reader.ConservativeReadLimit(), 0u);
253 ASSERT_EQ(kSeekReadSizeBytes, reader.Tell());
254
255 ASSERT_EQ(reader.Seek(kSeekReadSizeBytes + 1), Status::OutOfRange());
256 ASSERT_EQ(reader.Seek(2 * kSeekReadSizeBytes), Status::OutOfRange());
257
258 reader.SetReadLimit(kPartitionSize + 5);
259 ASSERT_EQ(reader.ConservativeReadLimit(),
260 (kPartitionSize - kSeekReadSizeBytes));
261 ASSERT_EQ(kSeekReadSizeBytes, reader.Tell());
262
263 reader.SetReadLimit(5);
264 ASSERT_EQ(reader.ConservativeReadLimit(), 0u);
265 ASSERT_EQ(5u, reader.Tell());
266 }
267
TEST_F(FlashStreamTest,Read_Seek_Forward_and_Back)268 TEST_F(FlashStreamTest, Read_Seek_Forward_and_Back) {
269 static const size_t kSeekReadSizeBytes = 256;
270 static const size_t kTotalIterations = 3;
271 static const size_t kSeekReadIterations =
272 flash_.buffer().size_bytes() / (2 * kSeekReadSizeBytes);
273
274 InitBufferToRandom(flash_.buffer(), 0xffde176);
275 FlashPartition::Reader reader(partition_);
276
277 for (size_t outer_count = 0; outer_count < kTotalIterations; outer_count++) {
278 // Seek and read going forward.
279 for (size_t i = 0; i < kSeekReadIterations; i++) {
280 size_t start_offset = kSeekReadSizeBytes + (i * 2 * kSeekReadSizeBytes);
281 ASSERT_EQ(reader.Seek(start_offset), OkStatus());
282 ASSERT_EQ(start_offset, reader.Tell());
283
284 ByteSpan read_chunk = span(source_buffer_).first(kSeekReadSizeBytes);
285 InitBufferToFill(read_chunk, 0);
286
287 auto result = reader.Read(read_chunk);
288 ASSERT_EQ(result.status(), OkStatus());
289 ASSERT_EQ(result.value().size_bytes(), kSeekReadSizeBytes);
290 VerifyFlashContent(read_chunk, start_offset);
291 ASSERT_EQ(start_offset + kSeekReadSizeBytes, reader.Tell());
292 }
293
294 // Seek and read going backward.
295 for (size_t j = (kSeekReadIterations * 2); j > 0; j--) {
296 size_t start_offset = (j - 1) * kSeekReadSizeBytes;
297 ASSERT_EQ(reader.Seek(start_offset), OkStatus());
298 ASSERT_EQ(start_offset, reader.Tell());
299 ASSERT_GE(reader.ConservativeReadLimit(), kSeekReadSizeBytes);
300
301 ByteSpan read_chunk = span(source_buffer_).first(kSeekReadSizeBytes);
302 InitBufferToFill(read_chunk, 0);
303
304 auto result = reader.Read(read_chunk);
305 ASSERT_EQ(result.status(), OkStatus());
306 ASSERT_EQ(result.value().size_bytes(), kSeekReadSizeBytes);
307 VerifyFlashContent(read_chunk, start_offset);
308 ASSERT_EQ(start_offset + kSeekReadSizeBytes, reader.Tell());
309 }
310 }
311 }
312
TEST_F(FlashStreamTest,Read_Past_End)313 TEST_F(FlashStreamTest, Read_Past_End) {
314 InitBufferToRandom(flash_.buffer(), 0xcccde176);
315 FlashPartition::Reader reader(partition_);
316
317 static const size_t kBytesForFinalRead = 50;
318
319 ByteSpan read_chunk =
320 span(source_buffer_).first(source_buffer_.size() - kBytesForFinalRead);
321
322 auto result = reader.Read(read_chunk);
323 ASSERT_EQ(result.status(), OkStatus());
324 ASSERT_EQ(result.value().size_bytes(), read_chunk.size_bytes());
325 ASSERT_EQ(reader.Tell(), read_chunk.size_bytes());
326 ASSERT_EQ(reader.ConservativeReadLimit(), kBytesForFinalRead);
327 ASSERT_EQ(result.value().data(), read_chunk.data());
328 VerifyFlashContent(read_chunk);
329
330 result = reader.Read(read_chunk);
331 ASSERT_EQ(result.status(), OkStatus());
332 ASSERT_EQ(result.value().size_bytes(), kBytesForFinalRead);
333 ASSERT_EQ(reader.Tell(), flash_.buffer().size_bytes());
334 ASSERT_EQ(reader.ConservativeReadLimit(), 0U);
335 ASSERT_EQ(result.value().data(), read_chunk.data());
336 VerifyFlashContent(result.value(), read_chunk.size_bytes());
337 }
338
TEST_F(FlashStreamTest,Read_Past_End_of_Limit)339 TEST_F(FlashStreamTest, Read_Past_End_of_Limit) {
340 static const size_t kBytesForReadLimit = 128;
341 static const size_t kBytesForFinalRead = 50;
342
343 InitBufferToRandom(flash_.buffer(), 0xcccde176);
344 FlashPartition::Reader reader(partition_, kBytesForReadLimit);
345
346 ASSERT_GE(source_buffer_.size(), kBytesForReadLimit);
347 ASSERT_GT(kBytesForReadLimit, 2 * kBytesForFinalRead);
348
349 ByteSpan read_chunk =
350 span(source_buffer_).first(kBytesForReadLimit - kBytesForFinalRead);
351
352 auto result = reader.Read(read_chunk);
353 ASSERT_EQ(result.status(), OkStatus());
354 ASSERT_EQ(result.value().size_bytes(), read_chunk.size_bytes());
355 ASSERT_EQ(reader.Tell(), read_chunk.size_bytes());
356 ASSERT_EQ(reader.ConservativeReadLimit(), kBytesForFinalRead);
357 ASSERT_EQ(result.value().data(), read_chunk.data());
358 VerifyFlashContent(read_chunk);
359
360 result = reader.Read(read_chunk);
361 ASSERT_EQ(result.status(), OkStatus());
362 ASSERT_EQ(result.value().size_bytes(), kBytesForFinalRead);
363 ASSERT_EQ(reader.Tell(), kBytesForReadLimit);
364 ASSERT_EQ(reader.ConservativeReadLimit(), 0U);
365 ASSERT_EQ(result.value().data(), read_chunk.data());
366 VerifyFlashContent(result.value(), read_chunk.size_bytes());
367
368 ASSERT_EQ(reader.Read(read_chunk).status(), Status::OutOfRange());
369 }
370
TEST_F(FlashStreamTest,Read_With_Zero_Byte_Limit)371 TEST_F(FlashStreamTest, Read_With_Zero_Byte_Limit) {
372 static const size_t kBytesForReadLimit = 128;
373 static const size_t kBytesForFinalRead = 50;
374
375 InitBufferToRandom(flash_.buffer(), 0xcccde176);
376 FlashPartition::Reader reader(partition_, 0u);
377
378 ASSERT_GE(source_buffer_.size(), kBytesForReadLimit);
379 ASSERT_GT(kBytesForReadLimit, 2 * kBytesForFinalRead);
380
381 ByteSpan read_chunk = span(source_buffer_);
382
383 ASSERT_EQ(reader.ConservativeReadLimit(), 0u);
384 ASSERT_EQ(reader.Tell(), 0u);
385
386 auto result = reader.Read(read_chunk);
387 ASSERT_EQ(result.status(), Status::OutOfRange());
388 ASSERT_EQ(reader.Tell(), 0u);
389 ASSERT_EQ(reader.ConservativeReadLimit(), 0u);
390
391 ASSERT_EQ(reader.Seek(0), OkStatus());
392 ASSERT_EQ(reader.Tell(), 0u);
393 ASSERT_EQ(reader.ConservativeReadLimit(), 0u);
394
395 ASSERT_EQ(reader.Seek(1), Status::OutOfRange());
396 ASSERT_EQ(reader.Tell(), 0u);
397 ASSERT_EQ(reader.ConservativeReadLimit(), 0u);
398
399 ASSERT_EQ(reader.Seek(5), Status::OutOfRange());
400 ASSERT_EQ(reader.Tell(), 0u);
401 ASSERT_EQ(reader.ConservativeReadLimit(), 0u);
402
403 result = reader.Read(read_chunk);
404 ASSERT_EQ(result.status(), Status::OutOfRange());
405 ASSERT_EQ(reader.Tell(), 0u);
406 ASSERT_EQ(reader.ConservativeReadLimit(), 0u);
407 }
408
TEST_F(FlashStreamTest,Read_Past_End_After_Seek)409 TEST_F(FlashStreamTest, Read_Past_End_After_Seek) {
410 InitBufferToRandom(flash_.buffer(), 0xddcde176);
411 FlashPartition::Reader reader(partition_);
412
413 static const size_t kBytesForFinalRead = 50;
414 size_t start_offset = flash_.buffer().size_bytes() - kBytesForFinalRead;
415 ASSERT_EQ(reader.Seek(start_offset), OkStatus());
416
417 ASSERT_EQ(start_offset, reader.Tell());
418 ASSERT_EQ(reader.ConservativeReadLimit(), kBytesForFinalRead);
419
420 ByteSpan read_chunk = span(source_buffer_);
421 auto result = reader.Read(read_chunk);
422 ASSERT_EQ(result.status(), OkStatus());
423 ASSERT_EQ(result.value().size_bytes(), kBytesForFinalRead);
424 ASSERT_EQ(reader.Tell(), flash_.buffer().size_bytes());
425 ASSERT_EQ(reader.ConservativeReadLimit(), 0U);
426 ASSERT_EQ(result.value().data(), read_chunk.data());
427 VerifyFlashContent(result.value(), start_offset);
428 }
429
TEST_F(FlashStreamTest,Read_Out_Of_Range)430 TEST_F(FlashStreamTest, Read_Out_Of_Range) {
431 InitBufferToRandom(flash_.buffer(), 0x531de176);
432 FlashPartition::Reader reader(partition_);
433
434 ByteSpan read_chunk = span(source_buffer_);
435
436 auto result = reader.Read(read_chunk);
437 ASSERT_EQ(result.status(), OkStatus());
438 ASSERT_EQ(result.value().size_bytes(), read_chunk.size_bytes());
439 ASSERT_EQ(reader.Tell(), read_chunk.size_bytes());
440 ASSERT_EQ(reader.ConservativeReadLimit(), 0U);
441 ASSERT_EQ(result.value().data(), read_chunk.data());
442 VerifyFlashContent(read_chunk);
443
444 result = reader.Read(read_chunk);
445 ASSERT_EQ(result.status(), Status::OutOfRange());
446 ASSERT_EQ(reader.Tell(), flash_.buffer().size_bytes());
447 ASSERT_EQ(reader.ConservativeReadLimit(), 0U);
448 }
449
TEST_F(FlashStreamTest,Read_Out_Of_Range_After_Seek)450 TEST_F(FlashStreamTest, Read_Out_Of_Range_After_Seek) {
451 InitBufferToRandom(flash_.buffer(), 0x8c94566);
452 FlashPartition::Reader reader(partition_);
453
454 ByteSpan read_chunk = span(source_buffer_);
455
456 ASSERT_EQ(reader.Seek(flash_.buffer().size_bytes()), OkStatus());
457 ASSERT_EQ(reader.Tell(), flash_.buffer().size_bytes());
458 ASSERT_EQ(reader.ConservativeReadLimit(), 0U);
459
460 auto result = reader.Read(read_chunk);
461 ASSERT_EQ(result.status(), Status::OutOfRange());
462 ASSERT_EQ(reader.Tell(), flash_.buffer().size_bytes());
463 ASSERT_EQ(reader.ConservativeReadLimit(), 0U);
464 }
465
TEST_F(FlashStreamTest,Reader_Seek_Ops)466 TEST_F(FlashStreamTest, Reader_Seek_Ops) {
467 size_t kPartitionSizeBytes = flash_.buffer().size_bytes();
468 FlashPartition::Reader reader(partition_);
469
470 // Seek from 0 to past end.
471 ASSERT_EQ(reader.Seek(kPartitionSizeBytes + 5), Status::OutOfRange());
472 ASSERT_EQ(reader.Tell(), 0U);
473
474 // Seek to end then seek again going past end.
475 ASSERT_EQ(reader.Seek(0), OkStatus());
476 ASSERT_EQ(reader.Tell(), 0U);
477 ASSERT_EQ(reader.ConservativeReadLimit(), kPartitionSizeBytes);
478
479 ASSERT_EQ(reader.Seek(kPartitionSizeBytes,
480 FlashPartition::Reader::Whence::kCurrent),
481 OkStatus());
482 ASSERT_EQ(reader.Tell(), kPartitionSizeBytes);
483 ASSERT_EQ(reader.ConservativeReadLimit(), 0U);
484
485 ASSERT_EQ(reader.Seek(5, FlashPartition::Reader::Whence::kCurrent),
486 Status::OutOfRange());
487 ASSERT_EQ(reader.Tell(), kPartitionSizeBytes);
488 ASSERT_EQ(reader.ConservativeReadLimit(), 0U);
489
490 // Seek to beginning then seek backwards going past start.
491 ASSERT_EQ(reader.Seek(0), OkStatus());
492 ASSERT_EQ(reader.Seek(-5, FlashPartition::Reader::Whence::kCurrent),
493 Status::OutOfRange());
494 ASSERT_EQ(reader.Tell(), 0U);
495 ASSERT_EQ(reader.ConservativeReadLimit(), kPartitionSizeBytes);
496 }
497
TEST_F(FlashStreamTest,Invald_Ops)498 TEST_F(FlashStreamTest, Invald_Ops) {
499 FlashPartition::Reader reader(partition_);
500 ASSERT_EQ(reader.ConservativeWriteLimit(), 0U);
501
502 FlashPartition::Writer writer(partition_);
503 ASSERT_EQ(writer.ConservativeReadLimit(), 0U);
504 }
505
506 } // namespace
507 } // namespace pw::kvs
508
509 #endif // PW_CXX_STANDARD_IS_SUPPORTED(17)
510