xref: /aosp_15_r20/external/pigweed/pw_kvs/flash_partition_stream_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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