xref: /aosp_15_r20/external/skia/tests/ChecksumTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2012 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAlign.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkChecksum.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
14*c8dee2aaSAndroid Build Coastguard Worker 
15*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
16*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
17*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
18*c8dee2aaSAndroid Build Coastguard Worker #include <string>
19*c8dee2aaSAndroid Build Coastguard Worker #include <string_view>
20*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(Checksum,r)21*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(Checksum, r) {
22*c8dee2aaSAndroid Build Coastguard Worker     // Put 128 random bytes into two identical buffers.  Any multiple of 4 will do.
23*c8dee2aaSAndroid Build Coastguard Worker     const size_t kBytes = SkAlign4(128);
24*c8dee2aaSAndroid Build Coastguard Worker     SkRandom rand;
25*c8dee2aaSAndroid Build Coastguard Worker     uint32_t data[kBytes/4], tweaked[kBytes/4];
26*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < std::size(tweaked); ++i) {
27*c8dee2aaSAndroid Build Coastguard Worker         data[i] = tweaked[i] = rand.nextU();
28*c8dee2aaSAndroid Build Coastguard Worker     }
29*c8dee2aaSAndroid Build Coastguard Worker 
30*c8dee2aaSAndroid Build Coastguard Worker     const uint32_t hash = SkChecksum::Hash32(data, kBytes);
31*c8dee2aaSAndroid Build Coastguard Worker     // Should be deterministic.
32*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, hash == SkChecksum::Hash32(data, kBytes));
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker     // Changing any single element should change the hash.
35*c8dee2aaSAndroid Build Coastguard Worker     for (size_t j = 0; j < std::size(tweaked); ++j) {
36*c8dee2aaSAndroid Build Coastguard Worker         const uint32_t saved = tweaked[j];
37*c8dee2aaSAndroid Build Coastguard Worker         tweaked[j] = rand.nextU();
38*c8dee2aaSAndroid Build Coastguard Worker         const uint32_t tweakedHash = SkChecksum::Hash32(tweaked, kBytes);
39*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, tweakedHash != hash);
40*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, tweakedHash == SkChecksum::Hash32(tweaked, kBytes));
41*c8dee2aaSAndroid Build Coastguard Worker         tweaked[j] = saved;
42*c8dee2aaSAndroid Build Coastguard Worker     }
43*c8dee2aaSAndroid Build Coastguard Worker }
44*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(GoodHash,r)45*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(GoodHash, r) {
46*c8dee2aaSAndroid Build Coastguard Worker     // 4 bytes --> hits SkChecksum::Mix fast path.
47*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, SkGoodHash()(( int32_t)4) ==  614249093);
48*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, SkGoodHash()((uint32_t)4) ==  614249093);
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(ChecksumCollisions,r)51*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(ChecksumCollisions, r) {
52*c8dee2aaSAndroid Build Coastguard Worker     // We noticed a few workloads that would cause hash collisions due to the way
53*c8dee2aaSAndroid Build Coastguard Worker     // our old optimized hashes split into three concurrent hashes and merged those hashes together.
54*c8dee2aaSAndroid Build Coastguard Worker     //
55*c8dee2aaSAndroid Build Coastguard Worker     // One of these two workloads ought to cause an unintentional hash collision on very similar
56*c8dee2aaSAndroid Build Coastguard Worker     // data in those old algorithms, the float version on 32-bit x86 and double elsewhere.
57*c8dee2aaSAndroid Build Coastguard Worker     {
58*c8dee2aaSAndroid Build Coastguard Worker         float a[9] = { 0, 1, 2,
59*c8dee2aaSAndroid Build Coastguard Worker                        3, 4, 5,
60*c8dee2aaSAndroid Build Coastguard Worker                        6, 7, 8, };
61*c8dee2aaSAndroid Build Coastguard Worker         float b[9] = { 1, 2, 0,
62*c8dee2aaSAndroid Build Coastguard Worker                        4, 5, 3,
63*c8dee2aaSAndroid Build Coastguard Worker                        7, 8, 6, };
64*c8dee2aaSAndroid Build Coastguard Worker 
65*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, SkChecksum::Hash32(a, sizeof(a)) != SkChecksum::Hash32(b, sizeof(b)));
66*c8dee2aaSAndroid Build Coastguard Worker     }
67*c8dee2aaSAndroid Build Coastguard Worker     {
68*c8dee2aaSAndroid Build Coastguard Worker         double a[9] = { 0, 1, 2,
69*c8dee2aaSAndroid Build Coastguard Worker                         3, 4, 5,
70*c8dee2aaSAndroid Build Coastguard Worker                         6, 7, 8, };
71*c8dee2aaSAndroid Build Coastguard Worker         double b[9] = { 1, 2, 0,
72*c8dee2aaSAndroid Build Coastguard Worker                         4, 5, 3,
73*c8dee2aaSAndroid Build Coastguard Worker                         7, 8, 6, };
74*c8dee2aaSAndroid Build Coastguard Worker 
75*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, SkChecksum::Hash32(a, sizeof(a)) != SkChecksum::Hash32(b, sizeof(b)));
76*c8dee2aaSAndroid Build Coastguard Worker     }
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(ChecksumConsistent,r)79*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(ChecksumConsistent, r) {
80*c8dee2aaSAndroid Build Coastguard Worker     // We don't guarantee that SkChecksum::Hash32 will return consistent results, but it does today.
81*c8dee2aaSAndroid Build Coastguard Worker     // Spot check a few:
82*c8dee2aaSAndroid Build Coastguard Worker     uint8_t bytes[256];
83*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 256; i++) {
84*c8dee2aaSAndroid Build Coastguard Worker         bytes[i] = i;
85*c8dee2aaSAndroid Build Coastguard Worker     }
86*c8dee2aaSAndroid Build Coastguard Worker     auto hash_bytes = [&](int n) { return SkChecksum::Hash32(bytes, n); };
87*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, hash_bytes(  0) == 0xe2bde459, "%08x", hash_bytes(  0));
88*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, hash_bytes(  1) == 0xe5f8bd85, "%08x", hash_bytes(  1));
89*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, hash_bytes(  2) == 0x77acd42a, "%08x", hash_bytes(  2));
90*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, hash_bytes(  7) == 0x78d0861f, "%08x", hash_bytes(  7));
91*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, hash_bytes( 32) == 0x4e73df6d, "%08x", hash_bytes( 32));
92*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, hash_bytes( 63) == 0x5e66a3f4, "%08x", hash_bytes( 63));
93*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, hash_bytes( 64) == 0x962d6746, "%08x", hash_bytes( 64));
94*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, hash_bytes( 99) == 0x79e09416, "%08x", hash_bytes( 99));
95*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, hash_bytes(255) == 0x85f837f0, "%08x", hash_bytes(255));
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(ChecksumStrings,r)98*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(ChecksumStrings, r) {
99*c8dee2aaSAndroid Build Coastguard Worker     constexpr char kMessage[] = "Checksums are supported for SkString, string, and string_view.";
100*c8dee2aaSAndroid Build Coastguard Worker     const uint32_t expectedHash = SkChecksum::Hash32(kMessage, strlen(kMessage));
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, expectedHash == SkGoodHash()(SkString(kMessage)));
103*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, expectedHash == SkGoodHash()(std::string(kMessage)));
104*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, expectedHash == SkGoodHash()(std::string_view(kMessage)));
105*c8dee2aaSAndroid Build Coastguard Worker }
106