• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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