hash_unittest.cc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <algorithm>
  16. #include <string>
  17. #include <vector>
  18. #include <gtest/gtest.h>
  19. #include <boost/lexical_cast.hpp>
  20. #include "../hash.h"
  21. #include "nsas_test.h"
  22. using namespace std;
  23. namespace isc {
  24. namespace nsas {
  25. // Utility function to count the number of unique values in a vector
  26. static uint32_t CountUnique(const vector<uint32_t>& input) {
  27. // Duplicate the vector as this will be destroyed in the process.
  28. vector<uint32_t> vcopy(input);
  29. // Check to see if values are unique. Do this by sorting the values into
  30. // ascending order, removing duplicates, and checking the size again.
  31. //
  32. // Note that "unique" only shifts elements around - it does not remove non-
  33. // unique values, so it does not change the size of the vector. The call to
  34. // erase removes the elements between the last unique element and the end
  35. // of the vector, so shrinking the vector.
  36. sort(vcopy.begin(), vcopy.end());
  37. vcopy.erase(unique(vcopy.begin(), vcopy.end()), vcopy.end());
  38. // ... and return the count of elements remaining.
  39. return (vcopy.size());
  40. }
  41. /// \brief Test Fixture Class
  42. class HashTest : public ::testing::Test {
  43. };
  44. // Test of the constructor
  45. TEST_F(HashTest, Constructor) {
  46. // Default constructor
  47. Hash hash1(HASHTABLE_DEFAULT_SIZE, 250);
  48. EXPECT_EQ(HASHTABLE_DEFAULT_SIZE, hash1.tableSize());
  49. EXPECT_EQ(250, hash1.maxKeyLength());
  50. }
  51. // Test of the hash algorithm. Without duplicating the code for the algorithm
  52. // here, testing is a bit awkward. So the tests will check that a series of
  53. // names get hashed to different values. (Choosing a HASHTABLE_DEFAULT_SIZE element array should
  54. // give minimal overlap; we'll allow for a maximum of 2 collisions with 50
  55. // similar names. If there are more, perhaps the algorithm is at fault.
  56. TEST_F(HashTest, Algorithm) {
  57. const int size = HASHTABLE_DEFAULT_SIZE; // Size of the hash table
  58. Hash hash(size, 255, false);// Hashing algorithm object with seed
  59. // randomisation disabled
  60. string base = "alphabeta"; // Base of the names to behashed
  61. vector<uint32_t> values; // Results stored here
  62. // Generate hash values
  63. for (int i = 0; i < 50; ++i) {
  64. string name = base + boost::lexical_cast<string>(i);
  65. uint32_t hashval = hash(HashKey(name.c_str(), name.size(),
  66. RRClass(0)));
  67. EXPECT_LT(hashval, size);
  68. values.push_back(hashval);
  69. }
  70. uint32_t cursize = values.size();
  71. // Count the unique values in the array
  72. uint32_t newsize = CountUnique(values);
  73. // We don't expect many clashes.
  74. EXPECT_GE(newsize + 2, cursize);
  75. }
  76. // Test the case mapping function.
  77. TEST_F(HashTest, CaseMapping) {
  78. Hash hash(HASHTABLE_DEFAULT_SIZE, 255);
  79. // Check all unsigned characters
  80. for (int i = 0; i < 255; ++i) {
  81. if ((i >= 'A') && (i <= 'Z')) {
  82. EXPECT_EQ(static_cast<unsigned char>(i - 'A' + 'a'),
  83. hash.mapLower((unsigned char)i));
  84. }
  85. else {
  86. EXPECT_EQ(i, hash.mapLower(i));
  87. }
  88. }
  89. }
  90. // Test the mapping of mixed-case names
  91. TEST_F(HashTest, MixedCase) {
  92. std::string test1 = "example1234.co.uk.";
  93. std::string test2 = "EXAmple1234.co.uk.";
  94. Hash hash(HASHTABLE_DEFAULT_SIZE, 255, false); // Disable randomisation for testing
  95. // Case not ignored, hashes should be different
  96. uint32_t value1 = hash(HashKey(test1.c_str(), test1.size(), RRClass::IN()),
  97. false);
  98. uint32_t value2 = hash(HashKey(test2.c_str(), test2.size(), RRClass::IN()),
  99. false);
  100. EXPECT_NE(value1, value2);
  101. // Case ignored, hashes should be the same
  102. uint32_t value3 = hash(HashKey(test1.c_str(), test1.size(), RRClass::IN()),
  103. true);
  104. uint32_t value4 = hash(HashKey(test2.c_str(), test2.size(), RRClass::IN()),
  105. true);
  106. EXPECT_EQ(value3, value4);
  107. // Check the default setting.
  108. uint32_t value5 = hash(HashKey(test1.c_str(), test1.size(), RRClass::IN()));
  109. uint32_t value6 = hash(HashKey(test2.c_str(), test2.size(), RRClass::IN()));
  110. EXPECT_EQ(value5, value6);
  111. // ... and just for good measure
  112. EXPECT_EQ(value1, value3);
  113. EXPECT_EQ(value1, value5);
  114. }
  115. // Test that the same name but different classes get mapped differently.
  116. TEST_F(HashTest, ClassCodes) {
  117. std::string test1 = "example1234.co.uk.";
  118. Hash hash(HASHTABLE_DEFAULT_SIZE, 255, false); // Disable randomisation for testing
  119. // Just try codes in the range 0 to 9 - more than covers the allocated
  120. // codes.
  121. vector<uint32_t> values;
  122. for (uint32_t i = 0; i < 10; ++i) {
  123. values.push_back(hash(HashKey(test1.c_str(), test1.size(),
  124. RRClass(i))));
  125. }
  126. // find the number of unique values in the array. Although there can
  127. // be some clashes, we don't expect too many.
  128. uint32_t cursize = values.size();
  129. // Count the unique values in the array
  130. uint32_t newsize = CountUnique(values);
  131. // We don't expect many clashes.
  132. EXPECT_GE(newsize + 2, cursize);
  133. }
  134. // Test that the code performs when the length of the key is excessive
  135. TEST_F(HashTest, Overlong) {
  136. // String 1 is a suitable prefix, string 2 is the same prefix plus 4096
  137. // repetions of the character 'x'.
  138. std::string string1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
  139. std::string string2 = string1 + string(4096, 'x');
  140. Hash hash(HASHTABLE_DEFAULT_SIZE, string1.size());
  141. // Do two hashes
  142. uint32_t value1 = hash(HashKey(string1.c_str(), string1.size(),
  143. RRClass(0)));
  144. uint32_t value2 = hash(HashKey(string2.c_str(), string2.size(),
  145. RRClass(0)));
  146. EXPECT_EQ(value1, value2);
  147. }
  148. } // namespace nsas
  149. } // namespace isc