1b1994897Sopenharmony_ci/**
2b1994897Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License.
5b1994897Sopenharmony_ci * You may obtain a copy of the License at
6b1994897Sopenharmony_ci *
7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8b1994897Sopenharmony_ci *
9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and
13b1994897Sopenharmony_ci * limitations under the License.
14b1994897Sopenharmony_ci */
15b1994897Sopenharmony_ci
16b1994897Sopenharmony_ci#include <ctime>
17b1994897Sopenharmony_ci#include "utils/hash.h"
18b1994897Sopenharmony_ci
19b1994897Sopenharmony_ci#include "gtest/gtest.h"
20b1994897Sopenharmony_ci#include "utils/logger.h"
21b1994897Sopenharmony_ci#include "mem/mem.h"
22b1994897Sopenharmony_ci#include "os/mem.h"
23b1994897Sopenharmony_ci#include "utils/asan_interface.h"
24b1994897Sopenharmony_ci
25b1994897Sopenharmony_cinamespace panda {
26b1994897Sopenharmony_ci
27b1994897Sopenharmony_ciclass HashTest : public testing::Test {
28b1994897Sopenharmony_cipublic:
29b1994897Sopenharmony_ci    HashTest()
30b1994897Sopenharmony_ci    {
31b1994897Sopenharmony_ci#ifdef PANDA_NIGHTLY_TEST_ON
32b1994897Sopenharmony_ci        seed_ = std::time(NULL);
33b1994897Sopenharmony_ci#else
34b1994897Sopenharmony_ci        seed_ = 0xDEADBEEF;
35b1994897Sopenharmony_ci#endif
36b1994897Sopenharmony_ci    }
37b1994897Sopenharmony_ci    ~HashTest() {}
38b1994897Sopenharmony_ci
39b1994897Sopenharmony_ciprotected:
40b1994897Sopenharmony_ci    template <class T>
41b1994897Sopenharmony_ci    void OneObject32bitsHashTest();
42b1994897Sopenharmony_ci    template <class T>
43b1994897Sopenharmony_ci    void OneStringHashTest();
44b1994897Sopenharmony_ci    template <class T>
45b1994897Sopenharmony_ci    void StringMemHashTest();
46b1994897Sopenharmony_ci    template <class T>
47b1994897Sopenharmony_ci    void EndOfPageStringHashTest();
48b1994897Sopenharmony_ci    static constexpr size_t KEY40INBYTES = 5;
49b1994897Sopenharmony_ci    static constexpr size_t KEY32INBYTES = 4;
50b1994897Sopenharmony_ci    static constexpr size_t KEY8INBYTES = 1;
51b1994897Sopenharmony_ci
52b1994897Sopenharmony_ci// Some platforms have this macro so do not redefine it.
53b1994897Sopenharmony_ci#ifndef PAGE_SIZE
54b1994897Sopenharmony_ci    static constexpr size_t PAGE_SIZE = SIZE_1K * 4;
55b1994897Sopenharmony_ci#endif
56b1994897Sopenharmony_ci
57b1994897Sopenharmony_ci    unsigned seed_;
58b1994897Sopenharmony_ci};
59b1994897Sopenharmony_ci
60b1994897Sopenharmony_citemplate <class T>
61b1994897Sopenharmony_civoid HashTest::OneObject32bitsHashTest()
62b1994897Sopenharmony_ci{
63b1994897Sopenharmony_ci    srand(seed_);
64b1994897Sopenharmony_ci
65b1994897Sopenharmony_ci    uint32_t object32 = rand();
66b1994897Sopenharmony_ci    uint32_t first_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object32), KEY32INBYTES);
67b1994897Sopenharmony_ci    uint32_t second_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object32), KEY32INBYTES);
68b1994897Sopenharmony_ci    if (first_hash != second_hash) {
69b1994897Sopenharmony_ci        std::cout << "Failed 32bit key hash on seed = 0x" << std::hex << seed_ << std::endl;
70b1994897Sopenharmony_ci    }
71b1994897Sopenharmony_ci    ASSERT_EQ(first_hash, second_hash);
72b1994897Sopenharmony_ci
73b1994897Sopenharmony_ci    uint8_t object8 = rand();
74b1994897Sopenharmony_ci    first_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object8), KEY8INBYTES);
75b1994897Sopenharmony_ci    second_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object8), KEY8INBYTES);
76b1994897Sopenharmony_ci    if (first_hash != second_hash) {
77b1994897Sopenharmony_ci        std::cout << "Failed 32bit key hash on seed = 0x" << std::hex << seed_ << std::endl;
78b1994897Sopenharmony_ci    }
79b1994897Sopenharmony_ci    ASSERT_EQ(first_hash, second_hash);
80b1994897Sopenharmony_ci
81b1994897Sopenharmony_ci    // Set up 64 bits value and use only 40 bits from it
82b1994897Sopenharmony_ci    uint64_t object40 = rand();
83b1994897Sopenharmony_ci    first_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object40), KEY40INBYTES);
84b1994897Sopenharmony_ci    second_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object40), KEY40INBYTES);
85b1994897Sopenharmony_ci    if (first_hash != second_hash) {
86b1994897Sopenharmony_ci        std::cout << "Failed 32bit key hash on seed = 0x" << std::hex << seed_ << std::endl;
87b1994897Sopenharmony_ci    }
88b1994897Sopenharmony_ci    ASSERT_EQ(first_hash, second_hash);
89b1994897Sopenharmony_ci}
90b1994897Sopenharmony_ci
91b1994897Sopenharmony_citemplate <class T>
92b1994897Sopenharmony_civoid HashTest::OneStringHashTest()
93b1994897Sopenharmony_ci{
94b1994897Sopenharmony_ci    char string[] = "Over 1000!\0";
95b1994897Sopenharmony_ci    // Dummy check. Don't ask me why...
96b1994897Sopenharmony_ci    if (sizeof(char) != sizeof(uint8_t)) {
97b1994897Sopenharmony_ci        return;
98b1994897Sopenharmony_ci    }
99b1994897Sopenharmony_ci    uint8_t *mutf8_string = reinterpret_cast<uint8_t *>(string);
100b1994897Sopenharmony_ci    uint32_t first_hash = T::GetHash32String(mutf8_string);
101b1994897Sopenharmony_ci    uint32_t second_hash = T::GetHash32String(mutf8_string);
102b1994897Sopenharmony_ci    ASSERT_EQ(first_hash, second_hash);
103b1994897Sopenharmony_ci}
104b1994897Sopenharmony_ci
105b1994897Sopenharmony_citemplate <class T>
106b1994897Sopenharmony_civoid HashTest::StringMemHashTest()
107b1994897Sopenharmony_ci{
108b1994897Sopenharmony_ci    char string[] = "COULD YOU CREATE MORE COMPLEX TESTS,OK?\0";
109b1994897Sopenharmony_ci    size_t string_size = strlen(string);
110b1994897Sopenharmony_ci    uint8_t *mutf8_string = reinterpret_cast<uint8_t *>(string);
111b1994897Sopenharmony_ci    uint32_t second_hash = T::GetHash32(mutf8_string, string_size);
112b1994897Sopenharmony_ci    uint32_t first_hash = T::GetHash32String(mutf8_string);
113b1994897Sopenharmony_ci    ASSERT_EQ(first_hash, second_hash);
114b1994897Sopenharmony_ci}
115b1994897Sopenharmony_ci
116b1994897Sopenharmony_citemplate <class T>
117b1994897Sopenharmony_civoid HashTest::EndOfPageStringHashTest()
118b1994897Sopenharmony_ci{
119b1994897Sopenharmony_ci    constexpr const int64_t immTwo = 2;
120b1994897Sopenharmony_ci    size_t string_size = 3;
121b1994897Sopenharmony_ci    constexpr size_t ALLOC_SIZE = PAGE_SIZE * 2;
122b1994897Sopenharmony_ci    void *mem = panda::os::mem::MapRWAnonymousRaw(ALLOC_SIZE);
123b1994897Sopenharmony_ci    ASAN_UNPOISON_MEMORY_REGION(mem, ALLOC_SIZE);
124b1994897Sopenharmony_ci    panda::os::mem::MakeMemProtected(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(mem) + PAGE_SIZE), PAGE_SIZE);
125b1994897Sopenharmony_ci    char *string =
126b1994897Sopenharmony_ci        reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(mem) + PAGE_SIZE) - sizeof(char) * string_size);
127b1994897Sopenharmony_ci    string[0] = 'O';
128b1994897Sopenharmony_ci    string[1] = 'K';
129b1994897Sopenharmony_ci    string[immTwo] = '\0';
130b1994897Sopenharmony_ci    uint8_t *mutf8_string = reinterpret_cast<uint8_t *>(string);
131b1994897Sopenharmony_ci    uint32_t second_hash = T::GetHash32(mutf8_string, string_size - 1);
132b1994897Sopenharmony_ci    uint32_t first_hash = T::GetHash32String(mutf8_string);
133b1994897Sopenharmony_ci    ASSERT_EQ(first_hash, second_hash);
134b1994897Sopenharmony_ci    auto res = panda::os::mem::UnmapRaw(mem, ALLOC_SIZE);
135b1994897Sopenharmony_ci    ASSERT_FALSE(res);
136b1994897Sopenharmony_ci}
137b1994897Sopenharmony_ci
138b1994897Sopenharmony_ci// If we hash an object twice, it must return the same value
139b1994897Sopenharmony_ci// Do it for 8 bits key, 32 bits and 40 bits key.
140b1994897Sopenharmony_ciTEST_F(HashTest, OneObjectHashTest)
141b1994897Sopenharmony_ci{
142b1994897Sopenharmony_ci    HashTest::OneObject32bitsHashTest<MurmurHash32<DEFAULT_SEED>>();
143b1994897Sopenharmony_ci}
144b1994897Sopenharmony_ci
145b1994897Sopenharmony_ci// If we hash a string twice, it must return the same value
146b1994897Sopenharmony_ciTEST_F(HashTest, OneStringHashTest)
147b1994897Sopenharmony_ci{
148b1994897Sopenharmony_ci    HashTest::OneStringHashTest<MurmurHash32<DEFAULT_SEED>>();
149b1994897Sopenharmony_ci}
150b1994897Sopenharmony_ci
151b1994897Sopenharmony_ci// If we hash a string with out string method,
152b1994897Sopenharmony_ci// we should get the same result as we use a pointer to string as a raw memory.
153b1994897Sopenharmony_ciTEST_F(HashTest, StringMemHashTest)
154b1994897Sopenharmony_ci{
155b1994897Sopenharmony_ci    HashTest::StringMemHashTest<MurmurHash32<DEFAULT_SEED>>();
156b1994897Sopenharmony_ci}
157b1994897Sopenharmony_ci
158b1994897Sopenharmony_ci// Try to hash the string which located at the end of allocated page.
159b1994897Sopenharmony_ci// Check that we will not have SEGERROR here.
160b1994897Sopenharmony_ciTEST_F(HashTest, EndOfPageStringHashTest)
161b1994897Sopenharmony_ci{
162b1994897Sopenharmony_ci    HashTest::EndOfPageStringHashTest<MurmurHash32<DEFAULT_SEED>>();
163b1994897Sopenharmony_ci}
164b1994897Sopenharmony_ci
165b1994897Sopenharmony_ci}  // namespace panda
166