1 // Copyright 2020 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 "pw_kvs/checksum.h"
16
17 #include "pw_kvs/crc16_checksum.h"
18 #include "pw_unit_test/framework.h"
19
20 namespace pw::kvs {
21 namespace {
22
23 using std::byte;
24
25 constexpr std::string_view kString =
26 "In the beginning the Universe was created. This has made a lot of "
27 "people very angry and been widely regarded as a bad move.";
28 constexpr uint16_t kStringCrc = 0xC184;
29
TEST(Checksum,UpdateAndVerify)30 TEST(Checksum, UpdateAndVerify) {
31 ChecksumCrc16 crc16_algo;
32 ChecksumAlgorithm& algo = crc16_algo;
33
34 algo.Update(kString.data(), kString.size());
35 EXPECT_EQ(OkStatus(), algo.Verify(as_bytes(span(&kStringCrc, 1))));
36 }
37
TEST(Checksum,Verify_Failure)38 TEST(Checksum, Verify_Failure) {
39 ChecksumCrc16 algo;
40 EXPECT_EQ(Status::DataLoss(), algo.Verify(as_bytes(span(kString.data(), 2))));
41 }
42
TEST(Checksum,Verify_InvalidSize)43 TEST(Checksum, Verify_InvalidSize) {
44 ChecksumCrc16 algo;
45 EXPECT_EQ(Status::InvalidArgument(), algo.Verify({}));
46 EXPECT_EQ(Status::InvalidArgument(),
47 algo.Verify(as_bytes(span(kString.substr(0, 1)))));
48 }
49
TEST(Checksum,Verify_LargerState_ComparesToTruncatedData)50 TEST(Checksum, Verify_LargerState_ComparesToTruncatedData) {
51 byte crc[3] = {byte{0x84}, byte{0xC1}, byte{0x33}};
52 ChecksumCrc16 algo;
53 ASSERT_GT(sizeof(crc), algo.size_bytes());
54
55 algo.Update(as_bytes(span(kString)));
56
57 EXPECT_EQ(OkStatus(), algo.Verify(crc));
58 }
59
TEST(Checksum,Reset)60 TEST(Checksum, Reset) {
61 ChecksumCrc16 crc_algo;
62 crc_algo.Update(as_bytes(span(kString)));
63 crc_algo.Reset();
64
65 span state = crc_algo.Finish();
66 EXPECT_EQ(state[0], byte{0xFF});
67 EXPECT_EQ(state[1], byte{0xFF});
68 }
69
TEST(IgnoreChecksum,NeverUpdate_VerifyWithoutData)70 TEST(IgnoreChecksum, NeverUpdate_VerifyWithoutData) {
71 IgnoreChecksum checksum;
72
73 EXPECT_EQ(OkStatus(), checksum.Verify({}));
74 }
75
TEST(IgnoreChecksum,NeverUpdate_VerifyWithData)76 TEST(IgnoreChecksum, NeverUpdate_VerifyWithData) {
77 IgnoreChecksum checksum;
78
79 EXPECT_EQ(OkStatus(), checksum.Verify(as_bytes(span(kString))));
80 }
81
TEST(IgnoreChecksum,AfterUpdate_Verify)82 TEST(IgnoreChecksum, AfterUpdate_Verify) {
83 IgnoreChecksum checksum;
84
85 checksum.Update(as_bytes(span(kString)));
86 EXPECT_EQ(OkStatus(), checksum.Verify({}));
87 }
88
89 constexpr size_t kAlignment = 10;
90
91 constexpr std::string_view kData =
92 "123456789_123456789_123456789_123456789_123456789_" // 50
93 "123456789_123456789_123456789_123456789_123456789_"; // 100
94 const span<const byte> kBytes = as_bytes(span(kData));
95
96 class PickyChecksum final : public AlignedChecksum<kAlignment, 32> {
97 public:
PickyChecksum()98 PickyChecksum() : AlignedChecksum(data_), data_{}, size_(0) {}
99
Reset()100 void Reset() override {}
101
FinalizeAligned()102 void FinalizeAligned() override { EXPECT_EQ(kData.size(), size_); }
103
UpdateAligned(span<const std::byte> data)104 void UpdateAligned(span<const std::byte> data) override {
105 ASSERT_EQ(data.size() % kAlignment, 0u);
106 EXPECT_EQ(kData.substr(0, data.size()),
107 std::string_view(reinterpret_cast<const char*>(data.data()),
108 data.size()));
109
110 std::memcpy(&data_[size_], data.data(), data.size());
111 size_ += data.size();
112 }
113
114 private:
115 std::byte data_[kData.size()];
116 size_t size_;
117 };
118
TEST(AlignedChecksum,MaintainsAlignment)119 TEST(AlignedChecksum, MaintainsAlignment) {
120 PickyChecksum checksum;
121
122 // Write values smaller than the alignment.
123 checksum.Update(kBytes.subspan(0, 1));
124 checksum.Update(kBytes.subspan(1, 9));
125
126 // Write values larger than the alignment but smaller than the buffer.
127 checksum.Update(kBytes.subspan(10, 11));
128
129 // Exactly fill the remainder of the buffer.
130 checksum.Update(kBytes.subspan(21, 11));
131
132 // Fill the buffer more than once.
133 checksum.Update(kBytes.subspan(32, 66));
134
135 // Write nothing.
136 checksum.Update(kBytes.subspan(98, 0));
137
138 // Write the remaining data.
139 checksum.Update(kBytes.subspan(98, 2));
140
141 auto state = checksum.Finish();
142 EXPECT_EQ(std::string_view(reinterpret_cast<const char*>(state.data()),
143 state.size()),
144 kData);
145 EXPECT_EQ(OkStatus(), checksum.Verify(kBytes));
146 }
147
148 } // namespace
149 } // namespace pw::kvs
150