1 // Copyright 2022 The Abseil Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of 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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/crc/crc32c.h"
16
17 #include <algorithm>
18 #include <cstddef>
19 #include <cstdint>
20 #include <cstring>
21 #include <string>
22
23 #include "gtest/gtest.h"
24 #include "absl/crc/internal/crc32c.h"
25 #include "absl/strings/str_cat.h"
26 #include "absl/strings/string_view.h"
27
28 namespace {
29
TEST(CRC32C,RFC3720)30 TEST(CRC32C, RFC3720) {
31 // Test the results of the vectors from
32 // https://www.rfc-editor.org/rfc/rfc3720#appendix-B.4
33 char data[32];
34
35 // 32 bytes of ones.
36 memset(data, 0, sizeof(data));
37 EXPECT_EQ(absl::ComputeCrc32c(absl::string_view(data, sizeof(data))),
38 absl::crc32c_t{0x8a9136aa});
39
40 // 32 bytes of ones.
41 memset(data, 0xff, sizeof(data));
42 EXPECT_EQ(absl::ComputeCrc32c(absl::string_view(data, sizeof(data))),
43 absl::crc32c_t{0x62a8ab43});
44
45 // 32 incrementing bytes.
46 for (int i = 0; i < 32; ++i) data[i] = static_cast<char>(i);
47 EXPECT_EQ(absl::ComputeCrc32c(absl::string_view(data, sizeof(data))),
48 absl::crc32c_t{0x46dd794e});
49
50 // 32 decrementing bytes.
51 for (int i = 0; i < 32; ++i) data[i] = static_cast<char>(31 - i);
52 EXPECT_EQ(absl::ComputeCrc32c(absl::string_view(data, sizeof(data))),
53 absl::crc32c_t{0x113fdb5c});
54
55 // An iSCSI - SCSI Read (10) Command PDU.
56 constexpr uint8_t cmd[48] = {
57 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
59 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x28, 0x00, 0x00, 0x00,
60 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 };
62 EXPECT_EQ(absl::ComputeCrc32c(absl::string_view(
63 reinterpret_cast<const char*>(cmd), sizeof(cmd))),
64 absl::crc32c_t{0xd9963a56});
65 }
66
TestString(size_t len)67 std::string TestString(size_t len) {
68 std::string result;
69 result.reserve(len);
70 for (size_t i = 0; i < len; ++i) {
71 result.push_back(static_cast<char>(i % 256));
72 }
73 return result;
74 }
75
TEST(CRC32C,Compute)76 TEST(CRC32C, Compute) {
77 EXPECT_EQ(absl::ComputeCrc32c(""), absl::crc32c_t{0});
78 EXPECT_EQ(absl::ComputeCrc32c("hello world"), absl::crc32c_t{0xc99465aa});
79 }
80
TEST(CRC32C,Extend)81 TEST(CRC32C, Extend) {
82 uint32_t base = 0xC99465AA; // CRC32C of "Hello World"
83 std::string extension = "Extension String";
84
85 EXPECT_EQ(
86 absl::ExtendCrc32c(absl::crc32c_t{base}, extension),
87 absl::crc32c_t{0xD2F65090}); // CRC32C of "Hello WorldExtension String"
88 }
89
TEST(CRC32C,ExtendByZeroes)90 TEST(CRC32C, ExtendByZeroes) {
91 std::string base = "hello world";
92 absl::crc32c_t base_crc = absl::crc32c_t{0xc99465aa};
93
94 constexpr size_t kExtendByValues[] = {100, 10000, 100000};
95 for (const size_t extend_by : kExtendByValues) {
96 SCOPED_TRACE(extend_by);
97 absl::crc32c_t crc2 = absl::ExtendCrc32cByZeroes(base_crc, extend_by);
98 EXPECT_EQ(crc2, absl::ComputeCrc32c(base + std::string(extend_by, '\0')));
99 }
100 }
101
TEST(CRC32C,UnextendByZeroes)102 TEST(CRC32C, UnextendByZeroes) {
103 constexpr size_t kExtendByValues[] = {2, 200, 20000, 200000, 20000000};
104 constexpr size_t kUnextendByValues[] = {0, 100, 10000, 100000, 10000000};
105
106 for (auto seed_crc : {absl::crc32c_t{0}, absl::crc32c_t{0xc99465aa}}) {
107 SCOPED_TRACE(seed_crc);
108 for (const size_t size_1 : kExtendByValues) {
109 for (const size_t size_2 : kUnextendByValues) {
110 size_t extend_size = std::max(size_1, size_2);
111 size_t unextend_size = std::min(size_1, size_2);
112 SCOPED_TRACE(extend_size);
113 SCOPED_TRACE(unextend_size);
114
115 // Extending by A zeroes an unextending by B<A zeros should be identical
116 // to extending by A-B zeroes.
117 absl::crc32c_t crc1 = seed_crc;
118 crc1 = absl::ExtendCrc32cByZeroes(crc1, extend_size);
119 crc1 = absl::crc_internal::UnextendCrc32cByZeroes(crc1, unextend_size);
120
121 absl::crc32c_t crc2 = seed_crc;
122 crc2 = absl::ExtendCrc32cByZeroes(crc2, extend_size - unextend_size);
123
124 EXPECT_EQ(crc1, crc2);
125 }
126 }
127 }
128
129 constexpr size_t kSizes[] = {0, 1, 100, 10000};
130 for (const size_t size : kSizes) {
131 SCOPED_TRACE(size);
132 std::string string_before = TestString(size);
133 std::string string_after = string_before + std::string(size, '\0');
134
135 absl::crc32c_t crc_before = absl::ComputeCrc32c(string_before);
136 absl::crc32c_t crc_after = absl::ComputeCrc32c(string_after);
137
138 EXPECT_EQ(crc_before,
139 absl::crc_internal::UnextendCrc32cByZeroes(crc_after, size));
140 }
141 }
142
TEST(CRC32C,Concat)143 TEST(CRC32C, Concat) {
144 std::string hello = "Hello, ";
145 std::string world = "world!";
146 std::string hello_world = absl::StrCat(hello, world);
147
148 absl::crc32c_t crc_a = absl::ComputeCrc32c(hello);
149 absl::crc32c_t crc_b = absl::ComputeCrc32c(world);
150 absl::crc32c_t crc_ab = absl::ComputeCrc32c(hello_world);
151
152 EXPECT_EQ(absl::ConcatCrc32c(crc_a, crc_b, world.size()), crc_ab);
153 }
154
TEST(CRC32C,Memcpy)155 TEST(CRC32C, Memcpy) {
156 constexpr size_t kBytesSize[] = {0, 1, 20, 500, 100000};
157 for (size_t bytes : kBytesSize) {
158 SCOPED_TRACE(bytes);
159 std::string sample_string = TestString(bytes);
160 std::string target_buffer = std::string(bytes, '\0');
161
162 absl::crc32c_t memcpy_crc =
163 absl::MemcpyCrc32c(&(target_buffer[0]), sample_string.data(), bytes);
164 absl::crc32c_t compute_crc = absl::ComputeCrc32c(sample_string);
165
166 EXPECT_EQ(memcpy_crc, compute_crc);
167 EXPECT_EQ(sample_string, target_buffer);
168 }
169 }
170
TEST(CRC32C,RemovePrefix)171 TEST(CRC32C, RemovePrefix) {
172 std::string hello = "Hello, ";
173 std::string world = "world!";
174 std::string hello_world = absl::StrCat(hello, world);
175
176 absl::crc32c_t crc_a = absl::ComputeCrc32c(hello);
177 absl::crc32c_t crc_b = absl::ComputeCrc32c(world);
178 absl::crc32c_t crc_ab = absl::ComputeCrc32c(hello_world);
179
180 EXPECT_EQ(absl::RemoveCrc32cPrefix(crc_a, crc_ab, world.size()), crc_b);
181 }
182
TEST(CRC32C,RemoveSuffix)183 TEST(CRC32C, RemoveSuffix) {
184 std::string hello = "Hello, ";
185 std::string world = "world!";
186 std::string hello_world = absl::StrCat(hello, world);
187
188 absl::crc32c_t crc_a = absl::ComputeCrc32c(hello);
189 absl::crc32c_t crc_b = absl::ComputeCrc32c(world);
190 absl::crc32c_t crc_ab = absl::ComputeCrc32c(hello_world);
191
192 EXPECT_EQ(absl::RemoveCrc32cSuffix(crc_ab, crc_b, world.size()), crc_a);
193 }
194 } // namespace
195