pw_kvs: Add test_key_value_store

Add test_key_value_store that uses TestKvs() to provide an initialized
KVS for easy use in other modules that depend on KVS.
Add a FakeFlashMemory version of the test_key_value_store.

Change-Id: I06e28bb736b1a85fbb0291aaf8b43a7609c6744c
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/15641
Reviewed-by: Janusz Sobczak <jsobczak@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
Commit-Queue: David Rogers <davidrogers@google.com>
diff --git a/pw_kvs/BUILD b/pw_kvs/BUILD
index ac6038e..4d3005c 100644
--- a/pw_kvs/BUILD
+++ b/pw_kvs/BUILD
@@ -138,6 +138,21 @@
 )
 
 pw_cc_library(
+    name = "fake_flash_test_key_value_store",
+    srcs = [
+        "fake_flash_test_key_value_store.cc",
+    ],
+    hdrs = [
+        "public/pw_kvs/test_key_value_store.h",
+    ],
+    deps = [
+        ":crc16",
+        ":pw_kvs",
+        ":fake_flash",
+    ],
+)
+
+pw_cc_library(
     name = "test_utils",
     hdrs = [
         "pw_kvs_private/byte_utils.h",
@@ -322,6 +337,19 @@
 )
 
 pw_cc_test(
+    name = "fake_flash_test_key_value_store_test",
+    srcs = ["test_key_value_store_test.cc"],
+    deps = [
+        ":crc16",
+        ":fake_flash_test_key_value_store",
+        ":pw_kvs",
+        "//pw_log:backend",
+        "//pw_status",
+        "//pw_unit_test",
+    ],
+)
+
+pw_cc_test(
     name = "key_value_store_binary_format_test",
     srcs = [
         "key_value_store_binary_format_test.cc",
diff --git a/pw_kvs/BUILD.gn b/pw_kvs/BUILD.gn
index 9a00f02..0f74e16 100644
--- a/pw_kvs/BUILD.gn
+++ b/pw_kvs/BUILD.gn
@@ -117,6 +117,17 @@
   defines = [ "PW_FLASH_TEST_ALIGNMENT=256" ]
 }
 
+pw_source_set("fake_flash_test_key_value_store") {
+  public_configs = [ ":default_config" ]
+  public = [ "public/pw_kvs/test_key_value_store.h" ]
+  sources = [ "fake_flash_test_key_value_store.cc" ]
+  deps = [
+    ":crc16",
+    ":fake_flash",
+    dir_pw_kvs,
+  ]
+}
+
 pw_source_set("flash_partition_test_100_iterations") {
   deps = [
     dir_pw_kvs,
@@ -183,6 +194,7 @@
     ":key_value_store_binary_format_test",
     ":key_value_store_fuzz_test",
     ":key_value_store_map_test",
+    ":fake_flash_test_key_value_store_test",
     ":sectors_test",
     ":key_value_store_wear_test",
   ]
@@ -302,6 +314,14 @@
   sources = [ "key_value_store_fuzz_test.cc" ]
 }
 
+pw_test("fake_flash_test_key_value_store_test") {
+  deps = [
+    ":fake_flash_test_key_value_store",
+    ":pw_kvs",
+  ]
+  sources = [ "test_key_value_store_test.cc" ]
+}
+
 pw_test("key_value_store_map_test") {
   deps = [
     ":crc16",
diff --git a/pw_kvs/fake_flash_test_key_value_store.cc b/pw_kvs/fake_flash_test_key_value_store.cc
new file mode 100644
index 0000000..52b52f8
--- /dev/null
+++ b/pw_kvs/fake_flash_test_key_value_store.cc
@@ -0,0 +1,74 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "pw_kvs/crc16_checksum.h"
+#include "pw_kvs/fake_flash_memory.h"
+#include "pw_kvs/flash_memory.h"
+#include "pw_kvs/key_value_store.h"
+#include "pw_kvs/test_key_value_store.h"
+
+namespace pw::kvs {
+
+namespace {
+
+#ifndef PW_FLASH_TEST_SECTORS
+#define PW_FLASH_TEST_SECTORS 8U
+#endif  // PW_FLASH_TEST_SECTORS
+
+#ifndef PW_FLASH_TEST_SECTOR_SIZE
+#define PW_FLASH_TEST_SECTOR_SIZE (4 * 1024U)
+#endif  // PW_FLASH_TEST_SECTOR_SIZE
+
+#ifndef PW_FLASH_TEST_ALIGNMENT
+#define PW_FLASH_TEST_ALIGNMENT 16U
+#endif  // PW_FLASH_TEST_ALIGNMENT
+
+#ifndef PW_KVS_TEST_MAX_ENTIRES
+#define PW_KVS_TEST_MAX_ENTIRES 32U
+#endif  // PW_KVS_TEST_MAX_ENTIRES
+
+#ifndef PW_KVS_TEST_REDUNDANCY
+#define PW_KVS_TEST_REDUNDANCY 1U
+#endif  // PW_KVS_TEST_REDUNDANCY
+
+constexpr size_t kFlashTestSectors = PW_FLASH_TEST_SECTORS;
+constexpr size_t kFlashTestSectorSize = PW_FLASH_TEST_SECTOR_SIZE;
+constexpr size_t kFlashTestAlignment = PW_FLASH_TEST_ALIGNMENT;
+
+constexpr size_t kKvsTestMaxEntries = PW_KVS_TEST_MAX_ENTIRES;
+constexpr size_t kKvsTestRedundancy = PW_KVS_TEST_REDUNDANCY;
+
+// Default to 8 x 4k sectors, 16 byte alignment.
+FakeFlashMemoryBuffer<kFlashTestSectorSize, kFlashTestSectors> test_flash(
+    kFlashTestAlignment);
+FlashPartition test_partition(&test_flash);
+
+ChecksumCrc16 kvs_checksum;
+
+// For KVS magic value always use a random 32 bit integer rather than a human
+// readable 4 bytes. See pw_kvs/format.h for more information.
+constexpr EntryFormat kvs_format = {.magic = 0xc40fd8a8,
+                                    .checksum = &kvs_checksum};
+
+KeyValueStoreBuffer<kKvsTestMaxEntries, kFlashTestSectors, kKvsTestRedundancy>
+    test_kvs(&test_partition, kvs_format);
+
+}  // namespace
+
+KeyValueStore& TestKvs() {
+  test_partition.Erase();
+  test_kvs.Init();
+  return test_kvs;
+}
+}  // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/test_key_value_store.h b/pw_kvs/public/pw_kvs/test_key_value_store.h
new file mode 100644
index 0000000..73aa609
--- /dev/null
+++ b/pw_kvs/public/pw_kvs/test_key_value_store.h
@@ -0,0 +1,22 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+#include "pw_kvs/key_value_store.h"
+
+namespace pw::kvs {
+
+KeyValueStore& TestKvs();
+
+}  // namespace pw::kvs
diff --git a/pw_kvs/test_key_value_store_test.cc b/pw_kvs/test_key_value_store_test.cc
new file mode 100644
index 0000000..5219925
--- /dev/null
+++ b/pw_kvs/test_key_value_store_test.cc
@@ -0,0 +1,35 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "pw_kvs/test_key_value_store.h"
+
+#include "gtest/gtest.h"
+#include "pw_kvs/key_value_store.h"
+#include "pw_status/status.h"
+
+namespace pw::kvs {
+namespace {
+
+// Simple test to verify that the TestKvs() does basic function.
+TEST(TestKvs, PutGetValue) {
+  KeyValueStore& kvs = TestKvs();
+  ASSERT_EQ(Status::OK, kvs.Put("key", uint32_t(0xfeedbeef)));
+
+  uint32_t value = 0;
+  EXPECT_EQ(Status::OK, kvs.Get("key", &value));
+  EXPECT_EQ(uint32_t(0xfeedbeef), value);
+}
+
+}  // namespace
+}  // namespace pw::kvs