1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 
6 #include "rocksdb/slice.h"
7 
8 #include "port/port.h"
9 #include "port/stack_trace.h"
10 #include "rocksdb/data_structure.h"
11 #include "rocksdb/types.h"
12 #include "test_util/testharness.h"
13 #include "test_util/testutil.h"
14 
15 namespace ROCKSDB_NAMESPACE {
16 
17 // Use this to keep track of the cleanups that were actually performed
Multiplier(void * arg1,void * arg2)18 void Multiplier(void* arg1, void* arg2) {
19   int* res = reinterpret_cast<int*>(arg1);
20   int* num = reinterpret_cast<int*>(arg2);
21   *res *= *num;
22 }
23 
24 class PinnableSliceTest : public testing::Test {
25  public:
AssertSameData(const std::string & expected,const PinnableSlice & slice)26   void AssertSameData(const std::string& expected,
27                       const PinnableSlice& slice) {
28     std::string got;
29     got.assign(slice.data(), slice.size());
30     ASSERT_EQ(expected, got);
31   }
32 };
33 
34 // Test that the external buffer is moved instead of being copied.
TEST_F(PinnableSliceTest,MoveExternalBuffer)35 TEST_F(PinnableSliceTest, MoveExternalBuffer) {
36   Slice s("123");
37   std::string buf;
38   PinnableSlice v1(&buf);
39   v1.PinSelf(s);
40 
41   PinnableSlice v2(std::move(v1));
42   ASSERT_EQ(buf.data(), v2.data());
43   ASSERT_EQ(&buf, v2.GetSelf());
44 
45   PinnableSlice v3;
46   v3 = std::move(v2);
47   ASSERT_EQ(buf.data(), v3.data());
48   ASSERT_EQ(&buf, v3.GetSelf());
49 }
50 
TEST_F(PinnableSliceTest,Move)51 TEST_F(PinnableSliceTest, Move) {
52   int n2 = 2;
53   int res = 1;
54   const std::string const_str1 = "123";
55   const std::string const_str2 = "ABC";
56   Slice slice1(const_str1);
57   Slice slice2(const_str2);
58 
59   {
60     // Test move constructor on a pinned slice.
61     res = 1;
62     PinnableSlice v1;
63     v1.PinSlice(slice1, Multiplier, &res, &n2);
64     PinnableSlice v2(std::move(v1));
65 
66     // Since v1's Cleanable has been moved to v2,
67     // no cleanup should happen in Reset.
68     v1.Reset();
69     ASSERT_EQ(1, res);
70 
71     AssertSameData(const_str1, v2);
72   }
73   // v2 is cleaned up.
74   ASSERT_EQ(2, res);
75 
76   {
77     // Test move constructor on an unpinned slice.
78     PinnableSlice v1;
79     v1.PinSelf(slice1);
80     PinnableSlice v2(std::move(v1));
81 
82     AssertSameData(const_str1, v2);
83   }
84 
85   {
86     // Test move assignment from a pinned slice to
87     // another pinned slice.
88     res = 1;
89     PinnableSlice v1;
90     v1.PinSlice(slice1, Multiplier, &res, &n2);
91     PinnableSlice v2;
92     v2.PinSlice(slice2, Multiplier, &res, &n2);
93     v2 = std::move(v1);
94 
95     // v2's Cleanable will be Reset before moving
96     // anything from v1.
97     ASSERT_EQ(2, res);
98     // Since v1's Cleanable has been moved to v2,
99     // no cleanup should happen in Reset.
100     v1.Reset();
101     ASSERT_EQ(2, res);
102 
103     AssertSameData(const_str1, v2);
104   }
105   // The Cleanable moved from v1 to v2 will be Reset.
106   ASSERT_EQ(4, res);
107 
108   {
109     // Test move assignment from a pinned slice to
110     // an unpinned slice.
111     res = 1;
112     PinnableSlice v1;
113     v1.PinSlice(slice1, Multiplier, &res, &n2);
114     PinnableSlice v2;
115     v2.PinSelf(slice2);
116     v2 = std::move(v1);
117 
118     // Since v1's Cleanable has been moved to v2,
119     // no cleanup should happen in Reset.
120     v1.Reset();
121     ASSERT_EQ(1, res);
122 
123     AssertSameData(const_str1, v2);
124   }
125   // The Cleanable moved from v1 to v2 will be Reset.
126   ASSERT_EQ(2, res);
127 
128   {
129     // Test move assignment from an upinned slice to
130     // another unpinned slice.
131     PinnableSlice v1;
132     v1.PinSelf(slice1);
133     PinnableSlice v2;
134     v2.PinSelf(slice2);
135     v2 = std::move(v1);
136 
137     AssertSameData(const_str1, v2);
138   }
139 
140   {
141     // Test move assignment from an upinned slice to
142     // a pinned slice.
143     res = 1;
144     PinnableSlice v1;
145     v1.PinSelf(slice1);
146     PinnableSlice v2;
147     v2.PinSlice(slice2, Multiplier, &res, &n2);
148     v2 = std::move(v1);
149 
150     // v2's Cleanable will be Reset before moving
151     // anything from v1.
152     ASSERT_EQ(2, res);
153 
154     AssertSameData(const_str1, v2);
155   }
156   // No Cleanable is moved from v1 to v2, so no more cleanup.
157   ASSERT_EQ(2, res);
158 }
159 
160 // Unit test for SmallEnumSet
161 class SmallEnumSetTest : public testing::Test {
162  public:
SmallEnumSetTest()163   SmallEnumSetTest() {}
~SmallEnumSetTest()164   ~SmallEnumSetTest() {}
165 };
166 
TEST_F(SmallEnumSetTest,SmallSetTest)167 TEST_F(SmallEnumSetTest, SmallSetTest) {
168   FileTypeSet fs;
169   ASSERT_TRUE(fs.Add(FileType::kIdentityFile));
170   ASSERT_FALSE(fs.Add(FileType::kIdentityFile));
171   ASSERT_TRUE(fs.Add(FileType::kInfoLogFile));
172   ASSERT_TRUE(fs.Contains(FileType::kIdentityFile));
173   ASSERT_FALSE(fs.Contains(FileType::kDBLockFile));
174 }
175 
176 }  // namespace ROCKSDB_NAMESPACE
177 
main(int argc,char ** argv)178 int main(int argc, char** argv) {
179   ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
180   ::testing::InitGoogleTest(&argc, argv);
181   return RUN_ALL_TESTS();
182 }
183