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