• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 #include "pw_persistent_ram/persistent_buffer.h"
15 
16 #include <cstddef>
17 #include <span>
18 #include <type_traits>
19 
20 #include "gtest/gtest.h"
21 #include "pw_bytes/span.h"
22 #include "pw_random/xor_shift.h"
23 
24 namespace pw::persistent_ram {
25 namespace {
26 
27 class PersistentTest : public ::testing::Test {
28  protected:
29   static constexpr size_t kBufferSize = 256;
PersistentTest()30   PersistentTest() { ZeroPersistentMemory(); }
31 
32   // Emulate invalidation of persistent section(s).
ZeroPersistentMemory()33   void ZeroPersistentMemory() { memset(buffer_, 0, sizeof(buffer_)); }
RandomFillMemory()34   void RandomFillMemory() {
35     random::XorShiftStarRng64 rng(0x9ad75);
36     StatusWithSize sws = rng.Get(buffer_);
37     ASSERT_TRUE(sws.ok());
38     ASSERT_EQ(sws.size(), sizeof(buffer_));
39   }
40 
GetPersistentBuffer()41   PersistentBuffer<kBufferSize>& GetPersistentBuffer() {
42     return *(new (buffer_) PersistentBuffer<kBufferSize>());
43   }
44 
45   // Allocate a chunk of aligned storage that can be independently controlled.
46   alignas(PersistentBuffer<kBufferSize>)
47       std::byte buffer_[sizeof(PersistentBuffer<kBufferSize>)];
48 };
49 
TEST_F(PersistentTest,DefaultConstructionAndDestruction)50 TEST_F(PersistentTest, DefaultConstructionAndDestruction) {
51   constexpr uint32_t kExpectedNumber = 0x6C2C6582;
52   {
53     // Emulate a boot where the persistent sections were invalidated.
54     // Although the fixture always does this, we do this an extra time to be
55     // 100% confident that an integrity check cannot be accidentally selected
56     // which results in reporting there is valid data when zero'd.
57     ZeroPersistentMemory();
58     auto& persistent = GetPersistentBuffer();
59     auto writer = persistent.GetWriter();
60     EXPECT_EQ(persistent.size(), 0u);
61 
62     writer.Write(std::as_bytes(std::span(&kExpectedNumber, 1)));
63     ASSERT_TRUE(persistent.has_value());
64 
65     persistent.~PersistentBuffer();  // Emulate shutdown / global destructors.
66   }
67 
68   {  // Emulate a boot where persistent memory was kept as is.
69     auto& persistent = GetPersistentBuffer();
70     ASSERT_TRUE(persistent.has_value());
71     EXPECT_EQ(persistent.size(), sizeof(kExpectedNumber));
72 
73     uint32_t temp = 0;
74     memcpy(&temp, persistent.data(), sizeof(temp));
75     EXPECT_EQ(temp, kExpectedNumber);
76   }
77 }
78 
TEST_F(PersistentTest,LongData)79 TEST_F(PersistentTest, LongData) {
80   constexpr std::string_view kTestString(
81       "A nice string should remain valid even if written incrementally!");
82   constexpr size_t kWriteSize = 5;
83 
84   {  // Initialize the buffer.
85     RandomFillMemory();
86     auto& persistent = GetPersistentBuffer();
87     ASSERT_FALSE(persistent.has_value());
88 
89     auto writer = persistent.GetWriter();
90     for (size_t i = 0; i < kTestString.length(); i += kWriteSize) {
91       writer.Write(kTestString.data() + i,
92                    std::min(kWriteSize, kTestString.length() - i));
93     }
94     // Need to manually write a null terminator since std::string_view doesn't
95     // include one in the string length.
96     writer.Write(std::byte(0));
97 
98     persistent.~PersistentBuffer();  // Emulate shutdown / global destructors.
99   }
100 
101   {  // Ensure data is valid.
102     auto& persistent = GetPersistentBuffer();
103     ASSERT_TRUE(persistent.has_value());
104     ASSERT_STREQ(kTestString.data(),
105                  reinterpret_cast<const char*>(persistent.data()));
106   }
107 }
108 
TEST_F(PersistentTest,ZeroDataIsNoValue)109 TEST_F(PersistentTest, ZeroDataIsNoValue) {
110   ZeroPersistentMemory();
111   auto& persistent = GetPersistentBuffer();
112   EXPECT_FALSE(persistent.has_value());
113 }
114 
TEST_F(PersistentTest,RandomDataIsInvalid)115 TEST_F(PersistentTest, RandomDataIsInvalid) {
116   RandomFillMemory();
117   auto& persistent = GetPersistentBuffer();
118   ASSERT_FALSE(persistent.has_value());
119 }
120 
TEST_F(PersistentTest,AppendingData)121 TEST_F(PersistentTest, AppendingData) {
122   constexpr std::string_view kTestString("Test string one!");
123   constexpr uint32_t kTestNumber = 42;
124 
125   {  // Initialize the buffer.
126     RandomFillMemory();
127     auto& persistent = GetPersistentBuffer();
128     auto writer = persistent.GetWriter();
129     EXPECT_EQ(persistent.size(), 0u);
130 
131     // Write an integer.
132     writer.Write(std::as_bytes(std::span(&kTestNumber, 1)));
133     ASSERT_TRUE(persistent.has_value());
134 
135     persistent.~PersistentBuffer();  // Emulate shutdown / global destructors.
136   }
137 
138   {  // Get a pointer to the buffer and validate the contents.
139     auto& persistent = GetPersistentBuffer();
140     ASSERT_TRUE(persistent.has_value());
141     EXPECT_EQ(persistent.size(), sizeof(kTestNumber));
142 
143     // Write more data.
144     auto writer = persistent.GetWriter();
145     EXPECT_EQ(persistent.size(), sizeof(kTestNumber));
146     writer.Write(std::as_bytes(std::span<const char>(kTestString)));
147 
148     persistent.~PersistentBuffer();  // Emulate shutdown / global destructors.
149   }
150   {  // Ensure data was appended.
151     auto& persistent = GetPersistentBuffer();
152     ASSERT_TRUE(persistent.has_value());
153     EXPECT_EQ(persistent.size(), sizeof(kTestNumber) + kTestString.length());
154   }
155 }
156 
157 }  // namespace
158 }  // namespace pw::persistent_ram
159