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 #include "pw_checksum/crc32.h"
15
16 #include <string_view>
17
18 #include "public/pw_checksum/crc32.h"
19 #include "pw_bytes/array.h"
20 #include "pw_span/span.h"
21 #include "pw_unit_test/framework.h"
22
23 namespace pw::checksum {
24 namespace {
25
26 // The expected CRC32 values were calculated using
27 //
28 // http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
29 //
30 // with polynomial 0x4C11DB7, initial value 0xFFFFFFFF.
31
32 constexpr auto kBytes = bytes::Array<1, 2, 3, 4, 5, 6, 7, 8, 9>();
33 constexpr auto kBytesPart0 = bytes::Array<1, 2, 3, 4, 5>();
34 constexpr auto kBytesPart1 = bytes::Array<6, 7, 8, 9>();
35 constexpr uint32_t kBufferCrc = 0x40EFAB9E;
36
37 constexpr std::string_view kString =
38 "In the beginning the Universe was created. This has made a lot of "
39 "people very angry and been widely regarded as a bad move.";
40 constexpr uint32_t kStringCrc = 0x9EC87F88;
41
TEST(Crc32,Empty)42 TEST(Crc32, Empty) {
43 EXPECT_EQ(Crc32::Calculate(span<std::byte>()), PW_CHECKSUM_EMPTY_CRC32);
44 EXPECT_EQ(Crc32EightBit::Calculate(span<std::byte>()),
45 PW_CHECKSUM_EMPTY_CRC32);
46 EXPECT_EQ(Crc32FourBit::Calculate(span<std::byte>()),
47 PW_CHECKSUM_EMPTY_CRC32);
48 EXPECT_EQ(Crc32OneBit::Calculate(span<std::byte>()), PW_CHECKSUM_EMPTY_CRC32);
49 }
50
TEST(Crc32,Buffer)51 TEST(Crc32, Buffer) {
52 EXPECT_EQ(Crc32::Calculate(as_bytes(span(kBytes))), kBufferCrc);
53 EXPECT_EQ(Crc32EightBit::Calculate(as_bytes(span(kBytes))), kBufferCrc);
54 EXPECT_EQ(Crc32FourBit::Calculate(as_bytes(span(kBytes))), kBufferCrc);
55 EXPECT_EQ(Crc32OneBit::Calculate(as_bytes(span(kBytes))), kBufferCrc);
56 }
57
TEST(Crc32,String)58 TEST(Crc32, String) {
59 EXPECT_EQ(Crc32::Calculate(as_bytes(span(kString))), kStringCrc);
60 EXPECT_EQ(Crc32EightBit::Calculate(as_bytes(span(kString))), kStringCrc);
61 EXPECT_EQ(Crc32FourBit::Calculate(as_bytes(span(kString))), kStringCrc);
62 EXPECT_EQ(Crc32OneBit::Calculate(as_bytes(span(kString))), kStringCrc);
63 }
64
65 template <typename CrcVariant>
TestByByte()66 void TestByByte() {
67 CrcVariant crc;
68 for (std::byte b : kBytes) {
69 crc.Update(b);
70 }
71 EXPECT_EQ(crc.value(), kBufferCrc);
72 }
73
TEST(Crc32Class,ByteByByte)74 TEST(Crc32Class, ByteByByte) {
75 TestByByte<Crc32>();
76 TestByByte<Crc32EightBit>();
77 TestByByte<Crc32FourBit>();
78 TestByByte<Crc32OneBit>();
79 }
80
81 template <typename CrcVariant>
TestBuffer()82 void TestBuffer() {
83 CrcVariant crc32;
84 crc32.Update(as_bytes(span(kBytes)));
85 EXPECT_EQ(crc32.value(), kBufferCrc);
86 }
87
TEST(Crc32Class,Buffer)88 TEST(Crc32Class, Buffer) {
89 TestBuffer<Crc32>();
90 TestBuffer<Crc32EightBit>();
91 TestBuffer<Crc32FourBit>();
92 TestBuffer<Crc32OneBit>();
93 }
94
95 template <typename CrcVariant>
TestBufferAppend()96 void TestBufferAppend() {
97 CrcVariant crc32;
98 crc32.Update(kBytesPart0);
99 crc32.Update(kBytesPart1);
100 EXPECT_EQ(crc32.value(), kBufferCrc);
101 }
102
TEST(Crc32Class,BufferAppend)103 TEST(Crc32Class, BufferAppend) {
104 TestBufferAppend<Crc32>();
105 TestBufferAppend<Crc32EightBit>();
106 TestBufferAppend<Crc32FourBit>();
107 TestBufferAppend<Crc32OneBit>();
108 }
109
110 template <typename CrcVariant>
TestString()111 void TestString() {
112 CrcVariant crc32;
113 crc32.Update(as_bytes(span(kString)));
114 EXPECT_EQ(crc32.value(), kStringCrc);
115 }
116
TEST(Crc32Class,String)117 TEST(Crc32Class, String) {
118 TestString<Crc32>();
119 TestString<Crc32EightBit>();
120 TestString<Crc32FourBit>();
121 TestString<Crc32OneBit>();
122 }
123
124 extern "C" uint32_t CallChecksumCrc32(const void* data, size_t size_bytes);
125 extern "C" uint32_t CallChecksumCrc32Append(const void* data,
126 size_t size_bytes,
127 uint32_t value);
128
TEST(Crc32FromC,Buffer)129 TEST(Crc32FromC, Buffer) {
130 EXPECT_EQ(CallChecksumCrc32(kBytes.data(), kBytes.size()), kBufferCrc);
131 }
132
TEST(Crc32FromC,String)133 TEST(Crc32FromC, String) {
134 EXPECT_EQ(CallChecksumCrc32(kString.data(), kString.size()), kStringCrc);
135 }
136
TEST(Crc32AppendFromC,Buffer)137 TEST(Crc32AppendFromC, Buffer) {
138 uint32_t crc = PW_CHECKSUM_EMPTY_CRC32;
139 for (std::byte b : kBytes) {
140 crc = CallChecksumCrc32Append(&b, 1, crc);
141 }
142
143 EXPECT_EQ(crc, kBufferCrc);
144 }
145
TEST(Crc32AppendFromC,String)146 TEST(Crc32AppendFromC, String) {
147 EXPECT_EQ(CallChecksumCrc32Append(
148 kString.data(), kString.size(), PW_CHECKSUM_EMPTY_CRC32),
149 kStringCrc);
150 }
151
152 } // namespace
153 } // namespace pw::checksum
154