| // Copyright 2022 The Abseil 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 "absl/crc/crc32c.h" |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <sstream> |
| #include <string> |
| |
| #include "gtest/gtest.h" |
| #include "absl/crc/internal/crc32c.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/str_format.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace { |
| |
| TEST(CRC32C, RFC3720) { |
| // Test the results of the vectors from |
| // https://www.rfc-editor.org/rfc/rfc3720#appendix-B.4 |
| char data[32]; |
| |
| // 32 bytes of ones. |
| memset(data, 0, sizeof(data)); |
| EXPECT_EQ(absl::ComputeCrc32c(absl::string_view(data, sizeof(data))), |
| absl::crc32c_t{0x8a9136aa}); |
| |
| // 32 bytes of ones. |
| memset(data, 0xff, sizeof(data)); |
| EXPECT_EQ(absl::ComputeCrc32c(absl::string_view(data, sizeof(data))), |
| absl::crc32c_t{0x62a8ab43}); |
| |
| // 32 incrementing bytes. |
| for (int i = 0; i < 32; ++i) data[i] = static_cast<char>(i); |
| EXPECT_EQ(absl::ComputeCrc32c(absl::string_view(data, sizeof(data))), |
| absl::crc32c_t{0x46dd794e}); |
| |
| // 32 decrementing bytes. |
| for (int i = 0; i < 32; ++i) data[i] = static_cast<char>(31 - i); |
| EXPECT_EQ(absl::ComputeCrc32c(absl::string_view(data, sizeof(data))), |
| absl::crc32c_t{0x113fdb5c}); |
| |
| // An iSCSI - SCSI Read (10) Command PDU. |
| constexpr uint8_t cmd[48] = { |
| 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, |
| 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x28, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| }; |
| EXPECT_EQ(absl::ComputeCrc32c(absl::string_view( |
| reinterpret_cast<const char*>(cmd), sizeof(cmd))), |
| absl::crc32c_t{0xd9963a56}); |
| } |
| |
| std::string TestString(size_t len) { |
| std::string result; |
| result.reserve(len); |
| for (size_t i = 0; i < len; ++i) { |
| result.push_back(static_cast<char>(i % 256)); |
| } |
| return result; |
| } |
| |
| TEST(CRC32C, Compute) { |
| EXPECT_EQ(absl::ComputeCrc32c(""), absl::crc32c_t{0}); |
| EXPECT_EQ(absl::ComputeCrc32c("hello world"), absl::crc32c_t{0xc99465aa}); |
| } |
| |
| TEST(CRC32C, Extend) { |
| uint32_t base = 0xC99465AA; // CRC32C of "Hello World" |
| std::string extension = "Extension String"; |
| |
| EXPECT_EQ( |
| absl::ExtendCrc32c(absl::crc32c_t{base}, extension), |
| absl::crc32c_t{0xD2F65090}); // CRC32C of "Hello WorldExtension String" |
| } |
| |
| TEST(CRC32C, ExtendByZeroes) { |
| std::string base = "hello world"; |
| absl::crc32c_t base_crc = absl::crc32c_t{0xc99465aa}; |
| |
| constexpr size_t kExtendByValues[] = {100, 10000, 100000}; |
| for (const size_t extend_by : kExtendByValues) { |
| SCOPED_TRACE(extend_by); |
| absl::crc32c_t crc2 = absl::ExtendCrc32cByZeroes(base_crc, extend_by); |
| EXPECT_EQ(crc2, absl::ComputeCrc32c(base + std::string(extend_by, '\0'))); |
| } |
| } |
| |
| TEST(CRC32C, UnextendByZeroes) { |
| constexpr size_t kExtendByValues[] = {2, 200, 20000, 200000, 20000000}; |
| constexpr size_t kUnextendByValues[] = {0, 100, 10000, 100000, 10000000}; |
| |
| for (auto seed_crc : {absl::crc32c_t{0}, absl::crc32c_t{0xc99465aa}}) { |
| SCOPED_TRACE(seed_crc); |
| for (const size_t size_1 : kExtendByValues) { |
| for (const size_t size_2 : kUnextendByValues) { |
| size_t extend_size = std::max(size_1, size_2); |
| size_t unextend_size = std::min(size_1, size_2); |
| SCOPED_TRACE(extend_size); |
| SCOPED_TRACE(unextend_size); |
| |
| // Extending by A zeroes an unextending by B<A zeros should be identical |
| // to extending by A-B zeroes. |
| absl::crc32c_t crc1 = seed_crc; |
| crc1 = absl::ExtendCrc32cByZeroes(crc1, extend_size); |
| crc1 = absl::crc_internal::UnextendCrc32cByZeroes(crc1, unextend_size); |
| |
| absl::crc32c_t crc2 = seed_crc; |
| crc2 = absl::ExtendCrc32cByZeroes(crc2, extend_size - unextend_size); |
| |
| EXPECT_EQ(crc1, crc2); |
| } |
| } |
| } |
| |
| constexpr size_t kSizes[] = {0, 1, 100, 10000}; |
| for (const size_t size : kSizes) { |
| SCOPED_TRACE(size); |
| std::string string_before = TestString(size); |
| std::string string_after = string_before + std::string(size, '\0'); |
| |
| absl::crc32c_t crc_before = absl::ComputeCrc32c(string_before); |
| absl::crc32c_t crc_after = absl::ComputeCrc32c(string_after); |
| |
| EXPECT_EQ(crc_before, |
| absl::crc_internal::UnextendCrc32cByZeroes(crc_after, size)); |
| } |
| } |
| |
| TEST(CRC32C, Concat) { |
| std::string hello = "Hello, "; |
| std::string world = "world!"; |
| std::string hello_world = absl::StrCat(hello, world); |
| |
| absl::crc32c_t crc_a = absl::ComputeCrc32c(hello); |
| absl::crc32c_t crc_b = absl::ComputeCrc32c(world); |
| absl::crc32c_t crc_ab = absl::ComputeCrc32c(hello_world); |
| |
| EXPECT_EQ(absl::ConcatCrc32c(crc_a, crc_b, world.size()), crc_ab); |
| } |
| |
| TEST(CRC32C, Memcpy) { |
| constexpr size_t kBytesSize[] = {0, 1, 20, 500, 100000}; |
| for (size_t bytes : kBytesSize) { |
| SCOPED_TRACE(bytes); |
| std::string sample_string = TestString(bytes); |
| std::string target_buffer = std::string(bytes, '\0'); |
| |
| absl::crc32c_t memcpy_crc = |
| absl::MemcpyCrc32c(&(target_buffer[0]), sample_string.data(), bytes); |
| absl::crc32c_t compute_crc = absl::ComputeCrc32c(sample_string); |
| |
| EXPECT_EQ(memcpy_crc, compute_crc); |
| EXPECT_EQ(sample_string, target_buffer); |
| } |
| } |
| |
| TEST(CRC32C, RemovePrefix) { |
| std::string hello = "Hello, "; |
| std::string world = "world!"; |
| std::string hello_world = absl::StrCat(hello, world); |
| |
| absl::crc32c_t crc_a = absl::ComputeCrc32c(hello); |
| absl::crc32c_t crc_b = absl::ComputeCrc32c(world); |
| absl::crc32c_t crc_ab = absl::ComputeCrc32c(hello_world); |
| |
| EXPECT_EQ(absl::RemoveCrc32cPrefix(crc_a, crc_ab, world.size()), crc_b); |
| } |
| |
| TEST(CRC32C, RemoveSuffix) { |
| std::string hello = "Hello, "; |
| std::string world = "world!"; |
| std::string hello_world = absl::StrCat(hello, world); |
| |
| absl::crc32c_t crc_a = absl::ComputeCrc32c(hello); |
| absl::crc32c_t crc_b = absl::ComputeCrc32c(world); |
| absl::crc32c_t crc_ab = absl::ComputeCrc32c(hello_world); |
| |
| EXPECT_EQ(absl::RemoveCrc32cSuffix(crc_ab, crc_b, world.size()), crc_a); |
| } |
| |
| TEST(CRC32C, InsertionOperator) { |
| { |
| std::ostringstream buf; |
| buf << absl::crc32c_t{0xc99465aa}; |
| EXPECT_EQ(buf.str(), "c99465aa"); |
| } |
| { |
| std::ostringstream buf; |
| buf << absl::crc32c_t{0}; |
| EXPECT_EQ(buf.str(), "00000000"); |
| } |
| { |
| std::ostringstream buf; |
| buf << absl::crc32c_t{17}; |
| EXPECT_EQ(buf.str(), "00000011"); |
| } |
| } |
| |
| TEST(CRC32C, AbslStringify) { |
| // StrFormat |
| EXPECT_EQ(absl::StrFormat("%v", absl::crc32c_t{0xc99465aa}), "c99465aa"); |
| EXPECT_EQ(absl::StrFormat("%v", absl::crc32c_t{0}), "00000000"); |
| EXPECT_EQ(absl::StrFormat("%v", absl::crc32c_t{17}), "00000011"); |
| |
| // StrCat |
| EXPECT_EQ(absl::StrCat(absl::crc32c_t{0xc99465aa}), "c99465aa"); |
| EXPECT_EQ(absl::StrCat(absl::crc32c_t{0}), "00000000"); |
| EXPECT_EQ(absl::StrCat(absl::crc32c_t{17}), "00000011"); |
| } |
| |
| } // namespace |