1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/string_pool.h"
18
19 #include <random>
20
21 #include "gtest/gtest.h"
22
23 namespace perfetto {
24 namespace trace_processor {
25 namespace {
26
TEST(StringPoolTest,EmptyPool)27 TEST(StringPoolTest, EmptyPool) {
28 StringPool pool;
29
30 ASSERT_EQ(pool.Get(0).c_str(), nullptr);
31
32 auto it = pool.CreateIterator();
33 ASSERT_TRUE(it);
34 ASSERT_EQ(it.StringView().c_str(), nullptr);
35 ASSERT_FALSE(++it);
36 }
37
TEST(StringPoolTest,InternAndRetrieve)38 TEST(StringPoolTest, InternAndRetrieve) {
39 StringPool pool;
40
41 static char kString[] = "Test String";
42 auto id = pool.InternString(kString);
43 ASSERT_STREQ(pool.Get(id).c_str(), kString);
44 ASSERT_EQ(pool.Get(id), kString);
45 ASSERT_EQ(id, pool.InternString(kString));
46 }
47
TEST(StringPoolTest,NullPointerHandling)48 TEST(StringPoolTest, NullPointerHandling) {
49 StringPool pool;
50
51 auto id = pool.InternString(NullTermStringView());
52 ASSERT_EQ(id, 0);
53 ASSERT_EQ(pool.Get(id).c_str(), nullptr);
54 }
55
TEST(StringPoolTest,Iterator)56 TEST(StringPoolTest, Iterator) {
57 StringPool pool;
58
59 auto it = pool.CreateIterator();
60 ASSERT_TRUE(it);
61 ASSERT_EQ(it.StringView().c_str(), nullptr);
62 ASSERT_FALSE(++it);
63
64 static char kString[] = "Test String";
65 pool.InternString(kString);
66
67 it = pool.CreateIterator();
68 ASSERT_TRUE(++it);
69 ASSERT_STREQ(it.StringView().c_str(), kString);
70 ASSERT_FALSE(++it);
71 }
72
TEST(StringPoolTest,ConstIterator)73 TEST(StringPoolTest, ConstIterator) {
74 StringPool pool;
75 static char kString[] = "Test String";
76 pool.InternString(kString);
77
78 const StringPool& const_pool = pool;
79
80 auto it = const_pool.CreateIterator();
81 ASSERT_TRUE(it);
82 ASSERT_TRUE(++it);
83 ASSERT_STREQ(it.StringView().c_str(), kString);
84 ASSERT_FALSE(++it);
85 }
86
TEST(StringPoolTest,StressTest)87 TEST(StringPoolTest, StressTest) {
88 // First create a buffer with 8MB of random characters.
89 constexpr size_t kBufferSize = 8 * 1024 * 1024;
90 std::minstd_rand0 rnd_engine(0);
91 std::unique_ptr<char[]> buffer(new char[kBufferSize]);
92 for (size_t i = 0; i < kBufferSize; i++)
93 buffer.get()[i] = 'A' + (rnd_engine() % 26);
94
95 // Next create strings of length 0 to 16k in length from this buffer and
96 // intern them, storing their ids.
97 StringPool pool;
98 std::multimap<StringPool::Id, base::StringView> string_map;
99 constexpr uint16_t kMaxStrSize = 16u * 1024u - 1;
100 for (size_t i = 0;;) {
101 size_t length = static_cast<uint64_t>(rnd_engine()) % (kMaxStrSize + 1);
102 if (i + length > kBufferSize)
103 break;
104
105 auto str = base::StringView(&buffer.get()[i], length);
106 string_map.emplace(pool.InternString(str), str);
107 i += length;
108 }
109
110 // Finally, iterate through each string in the string pool, check that all ids
111 // that match in the multimap are equal, and finish by checking we've removed
112 // every item in the multimap.
113 for (auto it = pool.CreateIterator(); it; ++it) {
114 ASSERT_EQ(it.StringView(), pool.Get(it.StringId()));
115
116 auto it_pair = string_map.equal_range(it.StringId());
117 for (auto in_it = it_pair.first; in_it != it_pair.second; ++in_it) {
118 ASSERT_EQ(it.StringView(), in_it->second);
119 }
120 string_map.erase(it_pair.first, it_pair.second);
121 }
122 ASSERT_EQ(string_map.size(), 0);
123 }
124
125 } // namespace
126 } // namespace trace_processor
127 } // namespace perfetto
128