proxygen
PerfectIndexMapTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
13 #include <string>
14 
15 using namespace folly;
16 using namespace proxygen;
17 
18 // This struct exists to WAR the gtest limitation that we can only pass a
19 // single template parameter to our test fixture. Thus in this case our single
20 // test parameter contains the type and value information required to
21 // instantiate the map under test correctly.
22 template <
23  typename Key,
24  Key OtherKey,
25  Key NoneKey,
26  Key (*PerfectHashStrToKey)(const std::string&),
27  bool AllowDuplicates,
28  bool CaseInsensitive,
29  uint8_t KeyCommonOffset,
30  uint64_t NumKeys>
32  typedef Key TKey;
33  static const Key TOtherKey = OtherKey;
34  static const Key TNoneKey = NoneKey;
35  static const bool TAllowDuplicates = AllowDuplicates;
36  static const bool TCaseInsensitive = CaseInsensitive;
37 
38  // Pass through wrapper for the hashing method.
39  // This method only exists because am unsure how to properly capture it and
40  // expose it as a subsequent template parameter for consumers.
41  static Key Hash(const std::string& name){
42  return PerfectHashStrToKey(name);
43  }
44 
45  static const uint8_t TKeyCommonOffset = KeyCommonOffset;
46  static const uint64_t TNumKeys = NumKeys;
47 };
48 
49 // Wrapper test class allowing us to create the desired PerfectIndexMap via
50 // the specified template parameter
51 template<class T>
53  protected:
55  typename T::TKey,
56  T::TOtherKey,
57  T::TNoneKey,
58  T::Hash,
59  T::TAllowDuplicates,
60  T::TCaseInsensitive>
62 };
63 
64 // Register the template configurations we wish to automatically test
65 typedef testing::Types<
70  HTTPCommonHeaders::hash,
71  false,
72  true,
74  HTTPCommonHeaders::num_header_codes>,
79  HTTPCommonHeaders::hash,
80  true,
81  true,
83  HTTPCommonHeaders::num_header_codes>,
88  HTTPCommonHeaders::hash,
89  true,
90  false,
92  HTTPCommonHeaders::num_header_codes>,
97  HTTPCommonHeaders::hash,
98  false,
99  false,
101  HTTPCommonHeaders::num_header_codes>
104 
105 TYPED_TEST(PerfectIndexMapTests, BasicKeySetAddRemoveGetSingleOrNone) {
106  typedef typename TypeParam::TKey Key;
107 
108  EXPECT_EQ(this->testMap_.size(), 0);
109 
110  // Insert numInserted distinct keys and duplicate values into the map.
111  auto numInserted = TypeParam::TNumKeys - TypeParam::TKeyCommonOffset;
112  for (uint64_t j = TypeParam::TKeyCommonOffset; j < TypeParam::TNumKeys; ++j) {
113  this->testMap_.set(static_cast<Key>(j), std::to_string(j));
114  }
115  EXPECT_EQ(this->testMap_.size(), numInserted);
116 
117  // Setting a duplicate should not increase the size of the map, regardless
118  // of whether duplicates are supported
119  Key key = static_cast<Key>(TypeParam::TKeyCommonOffset);
120  this->testMap_.set(key, std::to_string(TypeParam::TKeyCommonOffset));
121  EXPECT_EQ(this->testMap_.size(), numInserted);
122 
123  // Adding is only allowed when duplicates are and so here we expect the size
124  // of the map to change.
125  if (TypeParam::TAllowDuplicates) {
126  this->testMap_.add(key, std::to_string(TypeParam::TKeyCommonOffset));
127  EXPECT_EQ(this->testMap_.size(), numInserted + 1);
128  }
129 
130  // Remove the last added element in the map (and its duplicate if applicable)
131  // Adjusts numInserted as appropriate
132  this->testMap_.remove(key);
133  EXPECT_EQ(this->testMap_.size(), --numInserted);
134 
135  // Verify the integrity of the map
136  for (uint64_t j = TypeParam::TKeyCommonOffset + 1;
137  j < TypeParam::TNumKeys; ++j) {
138  key = static_cast<Key>(j);
139  auto optional = this->testMap_.getSingleOrNone(key);
140  ASSERT_TRUE(optional.hasValue());
141  ASSERT_EQ(optional.value(), std::to_string(j));
142  }
143 }
144 
145 TYPED_TEST(PerfectIndexMapTests, BasicOtherKeySetAddRemoveGetSingleOrNone) {
146  EXPECT_EQ(this->testMap_.size(), 0);
147 
148  // Insert numInserted distinct keys and values in to the map
149  int numInserted = 10;
151  for (int num = 0; num < numInserted; ++num) {
152  val = std::to_string(num);
153  this->testMap_.set(val, val);
154  }
155  EXPECT_EQ(this->testMap_.size(), numInserted);
156 
157  // Setting a duplicate should not increase the size of the map, regardless
158  // of whether duplicates are supported
159  this->testMap_.set(val, val);
160  EXPECT_EQ(this->testMap_.size(), numInserted);
161 
162  // Adding is only allowed when duplicates are and so here we expect the size
163  // of the map to change.
164  if (TypeParam::TAllowDuplicates) {
165  this->testMap_.add(val, val);
166  EXPECT_EQ(this->testMap_.size(), numInserted + 1);
167  }
168 
169  // Remove the last added element in the map (and its duplicate if applicable)
170  // Adjusts numInserted as appropriate
171  this->testMap_.remove(val);
172  EXPECT_EQ(this->testMap_.size(), --numInserted);
173 
174  // Verify the integrity of the map
175  for (int num = 0; num < numInserted; ++num) {
176  val = std::to_string(num);
177  auto optional = this->testMap_.getSingleOrNone(val);
178  ASSERT_TRUE(optional.hasValue());
179  ASSERT_EQ(optional.value(), val);
180  }
181 }
182 
183 // Note there is no corresponding key string case sensitivity test as that is
184 // controlled by the specified hashing function of the map. The user in
185 // creating the map thus chooses whether the hashing function should be case
186 // sensitive or not and thus does not require explicit testing as part of this
187 // class
188 TYPED_TEST(PerfectIndexMapTests, OtherStringCaseSensitivity) {
189  std::string testString = "test";
190  std::string modTestString = "tEsT";
191  std::string addModTestString = "TeSt";
192  this->testMap_.set(testString, testString);
193 
194  auto currentCount = this->testMap_.size();
196  if (TypeParam::TCaseInsensitive) {
197  optional = this->testMap_.getSingleOrNone(modTestString);
198  ASSERT_TRUE(optional.hasValue());
199  ASSERT_EQ(optional.value(), testString);
200 
201  this->testMap_.set(modTestString, modTestString);
202  EXPECT_EQ(this->testMap_.size(), currentCount);
203 
204  optional = this->testMap_.getSingleOrNone(testString);
205  ASSERT_TRUE(optional.hasValue());
206  ASSERT_EQ(optional.value(), modTestString);
207  } else {
208  this->testMap_.set(modTestString, modTestString);
209  EXPECT_EQ(this->testMap_.size(), ++currentCount);
210 
211  this->testMap_.set(testString, testString);
212  EXPECT_EQ(this->testMap_.size(), currentCount);
213 
214  optional = this->testMap_.getSingleOrNone(testString);
215  ASSERT_TRUE(optional.hasValue());
216  ASSERT_EQ(optional.value(), testString);
217 
218  optional = this->testMap_.getSingleOrNone(modTestString);
219  ASSERT_TRUE(optional.hasValue());
220  ASSERT_EQ(optional.value(), modTestString);
221  }
222 
223  if (TypeParam::TAllowDuplicates) {
224  // Finally verify that two exact same keys are treated as duplicates.
225  this->testMap_.add(addModTestString, addModTestString);
226  optional = this->testMap_.getSingleOrNone(testString);
227  if (TypeParam::TCaseInsensitive) {
228  EXPECT_FALSE(optional.hasValue());
229  } else {
230  EXPECT_TRUE(optional.has_value());
231  }
232  }
233 }
static Key Hash(const std::string &name)
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
internal::KeyMatcher< M > Key(M inner_matcher)
double val
Definition: String.cpp:273
FOLLY_CPP14_CONSTEXPR bool has_value() const noexcept
Definition: Optional.h:296
TYPED_TEST_CASE(SynchronizedTest, SynchronizedTestTypes)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
PerfectIndexMap< typename T::TKey, T::TOtherKey, T::TNoneKey, T::Hash, T::TAllowDuplicates, T::TCaseInsensitive > testMap_
const char * name
Definition: http_parser.c:437
testing::Types< PerfectIndexMapTestsTemplateParams< HTTPHeaderCode, HTTP_HEADER_OTHER, HTTP_HEADER_NONE, HTTPCommonHeaders::hash, false, true, HTTPHeaderCodeCommonOffset, HTTPCommonHeaders::num_header_codes >, PerfectIndexMapTestsTemplateParams< HTTPHeaderCode, HTTP_HEADER_OTHER, HTTP_HEADER_NONE, HTTPCommonHeaders::hash, true, true, HTTPHeaderCodeCommonOffset, HTTPCommonHeaders::num_header_codes >, PerfectIndexMapTestsTemplateParams< HTTPHeaderCode, HTTP_HEADER_OTHER, HTTP_HEADER_NONE, HTTPCommonHeaders::hash, true, false, HTTPHeaderCodeCommonOffset, HTTPCommonHeaders::num_header_codes >, PerfectIndexMapTestsTemplateParams< HTTPHeaderCode, HTTP_HEADER_OTHER, HTTP_HEADER_NONE, HTTPCommonHeaders::hash, false, false, HTTPHeaderCodeCommonOffset, HTTPCommonHeaders::num_header_codes > > TestTypes
TYPED_TEST(SynchronizedTest, Basic)
FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept
Definition: Optional.h:300
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
const char * string
Definition: Conv.cpp:212
const uint8_t HTTPHeaderCodeCommonOffset
FOLLY_CPP14_CONSTEXPR const Value & value() const &
Definition: Optional.h:268
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865