1 extern "C" {
2 #include <linux/errno.h>
3 #include <linux/xxhash.h>
4 }
5 #include <gtest/gtest.h>
6 #include <array>
7 #include <iostream>
8 #include <memory>
9 #include <string>
10 #define XXH_STATIC_LINKING_ONLY
11 #include <xxhash.h>
12 
13 using namespace std;
14 
15 namespace {
16 const std::array<std::string, 11> kTestInputs = {
17   "",
18   "0",
19   "01234",
20   "0123456789abcde",
21   "0123456789abcdef",
22   "0123456789abcdef0",
23   "0123456789abcdef0123",
24   "0123456789abcdef0123456789abcde",
25   "0123456789abcdef0123456789abcdef",
26   "0123456789abcdef0123456789abcdef0",
27   "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
28 };
29 
testXXH32(const void * input,const size_t length,uint32_t seed)30 bool testXXH32(const void *input, const size_t length, uint32_t seed) {
31   return XXH32(input, length, seed) == xxh32(input, length, seed);
32 }
33 
testXXH64(const void * input,const size_t length,uint32_t seed)34 bool testXXH64(const void *input, const size_t length, uint32_t seed) {
35   return XXH64(input, length, seed) == xxh64(input, length, seed);
36 }
37 
38 class XXH32State {
39   struct xxh32_state kernelState;
40   XXH32_state_t state;
41 
42 public:
XXH32State(const uint32_t seed)43   explicit XXH32State(const uint32_t seed) { reset(seed); }
XXH32State(XXH32State const & other)44   XXH32State(XXH32State const& other) noexcept {
45     xxh32_copy_state(&kernelState, &other.kernelState);
46     XXH32_copyState(&state, &other.state);
47   }
operator =(XXH32State const & other)48   XXH32State& operator=(XXH32State const& other) noexcept {
49     xxh32_copy_state(&kernelState, &other.kernelState);
50     XXH32_copyState(&state, &other.state);
51     return *this;
52   }
53 
reset(const uint32_t seed)54   void reset(const uint32_t seed) {
55     xxh32_reset(&kernelState, seed);
56     EXPECT_EQ(0, XXH32_reset(&state, seed));
57   }
58 
update(const void * input,const size_t length)59   void update(const void *input, const size_t length) {
60     EXPECT_EQ(0, xxh32_update(&kernelState, input, length));
61     EXPECT_EQ(0, (int)XXH32_update(&state, input, length));
62   }
63 
testDigest() const64   bool testDigest() const {
65     return xxh32_digest(&kernelState) == XXH32_digest(&state);
66   }
67 };
68 
69 class XXH64State {
70   struct xxh64_state kernelState;
71   XXH64_state_t state;
72 
73 public:
XXH64State(const uint64_t seed)74   explicit XXH64State(const uint64_t seed) { reset(seed); }
XXH64State(XXH64State const & other)75   XXH64State(XXH64State const& other) noexcept {
76     xxh64_copy_state(&kernelState, &other.kernelState);
77     XXH64_copyState(&state, &other.state);
78   }
operator =(XXH64State const & other)79   XXH64State& operator=(XXH64State const& other) noexcept {
80     xxh64_copy_state(&kernelState, &other.kernelState);
81     XXH64_copyState(&state, &other.state);
82     return *this;
83   }
84 
reset(const uint64_t seed)85   void reset(const uint64_t seed) {
86     xxh64_reset(&kernelState, seed);
87     EXPECT_EQ(0, XXH64_reset(&state, seed));
88   }
89 
update(const void * input,const size_t length)90   void update(const void *input, const size_t length) {
91     EXPECT_EQ(0, xxh64_update(&kernelState, input, length));
92     EXPECT_EQ(0, (int)XXH64_update(&state, input, length));
93   }
94 
testDigest() const95   bool testDigest() const {
96     return xxh64_digest(&kernelState) == XXH64_digest(&state);
97   }
98 };
99 }
100 
TEST(Simple,Null)101 TEST(Simple, Null) {
102   EXPECT_TRUE(testXXH32(NULL, 0, 0));
103   EXPECT_TRUE(testXXH64(NULL, 0, 0));
104 }
105 
TEST(Stream,Null)106 TEST(Stream, Null) {
107   struct xxh32_state state32;
108   xxh32_reset(&state32, 0);
109   EXPECT_EQ(-EINVAL, xxh32_update(&state32, NULL, 0));
110 
111   struct xxh64_state state64;
112   xxh64_reset(&state64, 0);
113   EXPECT_EQ(-EINVAL, xxh64_update(&state64, NULL, 0));
114 }
115 
TEST(Simple,TestInputs)116 TEST(Simple, TestInputs) {
117   for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
118     for (auto const input : kTestInputs) {
119       EXPECT_TRUE(testXXH32(input.data(), input.size(), seed));
120       EXPECT_TRUE(testXXH64(input.data(), input.size(), (uint64_t)seed));
121     }
122   }
123 }
124 
TEST(Stream,TestInputs)125 TEST(Stream, TestInputs) {
126   for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
127     for (auto const input : kTestInputs) {
128       XXH32State s32(seed);
129       XXH64State s64(seed);
130       s32.update(input.data(), input.size());
131       s64.update(input.data(), input.size());
132       EXPECT_TRUE(s32.testDigest());
133       EXPECT_TRUE(s64.testDigest());
134     }
135   }
136 }
137 
TEST(Stream,MultipleTestInputs)138 TEST(Stream, MultipleTestInputs) {
139   for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
140     XXH32State s32(seed);
141     XXH64State s64(seed);
142     for (auto const input : kTestInputs) {
143       s32.update(input.data(), input.size());
144       s64.update(input.data(), input.size());
145     }
146     EXPECT_TRUE(s32.testDigest());
147     EXPECT_TRUE(s64.testDigest());
148   }
149 }
150 
TEST(Stream,CopyState)151 TEST(Stream, CopyState) {
152   for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
153     XXH32State s32(seed);
154     XXH64State s64(seed);
155     for (auto const input : kTestInputs) {
156       auto t32(s32);
157       t32.update(input.data(), input.size());
158       s32 = t32;
159       auto t64(s64);
160       t64.update(input.data(), input.size());
161       s64 = t64;
162     }
163     EXPECT_TRUE(s32.testDigest());
164     EXPECT_TRUE(s64.testDigest());
165   }
166 }
167