pw_kvs: Check that the flash partition has minimum needed sectors

Verify that the KVS's flash partition has enough sectors to actually
function. That is 1 working sector + 1 free sector, for a minimum
required of 2 sectors.

Change-Id: Ic850bf2c19aa66fa1cc143a433c3f624f292387b
diff --git a/pw_kvs/key_value_store.cc b/pw_kvs/key_value_store.cc
index 84cc4cf..68a8412 100644
--- a/pw_kvs/key_value_store.cc
+++ b/pw_kvs/key_value_store.cc
@@ -70,6 +70,13 @@
     return Status::FAILED_PRECONDITION;
   }
 
+  if (partition_.sector_count() < 2) {
+    ERR("KVS init failed: FlashParition sector count (=%u) must be at 2. KVS "
+        "requires at least 1 working sector + 1 free/reserved sector",
+        unsigned(partition_.sector_count()));
+    return Status::FAILED_PRECONDITION;
+  }
+
   const size_t sector_size_bytes = partition_.sector_size_bytes();
 
   // TODO: investigate doing this as a static assert/compile-time check.
diff --git a/pw_kvs/key_value_store_binary_format_test.cc b/pw_kvs/key_value_store_binary_format_test.cc
index 4c48e55..079396d 100644
--- a/pw_kvs/key_value_store_binary_format_test.cc
+++ b/pw_kvs/key_value_store_binary_format_test.cc
@@ -157,14 +157,14 @@
 constexpr auto kEmpty32Bytes = InitializedBytes<32>(0xff);
 static_assert(sizeof(kEmpty32Bytes) == 32);
 
+EntryFormat default_format = {.magic = kMagic, .checksum = &default_checksum};
+
 class KvsErrorHandling : public ::testing::Test {
  protected:
   KvsErrorHandling()
       : flash_(internal::Entry::kMinAlignmentBytes),
         partition_(&flash_),
-        kvs_(&partition_,
-             {.magic = kMagic, .checksum = &default_checksum},
-             kNoGcOptions) {}
+        kvs_(&partition_, default_format, kNoGcOptions) {}
 
   void InitFlashTo(span<const byte> contents) {
     partition_.Erase();
diff --git a/pw_kvs/key_value_store_test.cc b/pw_kvs/key_value_store_test.cc
index 81238a6..1333364 100644
--- a/pw_kvs/key_value_store_test.cc
+++ b/pw_kvs/key_value_store_test.cc
@@ -630,6 +630,45 @@
   EXPECT_EQ(kvs_.size(), 0u);
 }
 
+TEST(InitCheck, TooFewSectors) {
+  // Use test flash with 1 x 4k sectors, 16 byte alignment
+  FakeFlashMemoryBuffer<4 * 1024, 1> test_flash(16);
+  FlashPartition test_partition(&test_flash, 0, test_flash.sector_count());
+
+  constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr};
+  KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&test_partition,
+                                                          format);
+
+  EXPECT_EQ(kvs.Init(), Status::FAILED_PRECONDITION);
+}
+
+TEST(InitCheck, ZeroSectors) {
+  // Use test flash with 1 x 4k sectors, 16 byte alignment
+  FakeFlashMemoryBuffer<4 * 1024, 1> test_flash(16);
+
+  // Set FlashPartition to have 0 sectors.
+  FlashPartition test_partition(&test_flash, 0, 0);
+
+  constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr};
+  KeyValueStoreBuffer<kMaxEntries, kMaxUsableSectors> kvs(&test_partition,
+                                                          format);
+
+  EXPECT_EQ(kvs.Init(), Status::FAILED_PRECONDITION);
+}
+
+TEST(InitCheck, TooManySectors) {
+  // Use test flash with 1 x 4k sectors, 16 byte alignment
+  FakeFlashMemoryBuffer<4 * 1024, 5> test_flash(16);
+
+  // Set FlashPartition to have 0 sectors.
+  FlashPartition test_partition(&test_flash, 0, test_flash.sector_count());
+
+  constexpr EntryFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr};
+  KeyValueStoreBuffer<kMaxEntries, 2> kvs(&test_partition, format);
+
+  EXPECT_EQ(kvs.Init(), Status::FAILED_PRECONDITION);
+}
+
 #define ASSERT_OK(expr) ASSERT_EQ(Status::OK, expr)
 #define EXPECT_OK(expr) EXPECT_EQ(Status::OK, expr)