123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <config.h>
- #include <algorithm>
- #include <string>
- #include <vector>
- #include <gtest/gtest.h>
- #include <boost/lexical_cast.hpp>
- #include "../hash.h"
- #include "nsas_test.h"
- using namespace std;
- namespace isc {
- namespace nsas {
- // Utility function to count the number of unique values in a vector
- static uint32_t CountUnique(const vector<uint32_t>& input) {
- // Duplicate the vector as this will be destroyed in the process.
- vector<uint32_t> vcopy(input);
- // Check to see if values are unique. Do this by sorting the values into
- // ascending order, removing duplicates, and checking the size again.
- //
- // Note that "unique" only shifts elements around - it does not remove non-
- // unique values, so it does not change the size of the vector. The call to
- // erase removes the elements between the last unique element and the end
- // of the vector, so shrinking the vector.
- sort(vcopy.begin(), vcopy.end());
- vcopy.erase(unique(vcopy.begin(), vcopy.end()), vcopy.end());
- // ... and return the count of elements remaining.
- return (vcopy.size());
- }
- /// \brief Test Fixture Class
- class HashTest : public ::testing::Test {
- };
- // Test of the constructor
- TEST_F(HashTest, Constructor) {
-
- // Default constructor
- Hash hash1(HASHTABLE_DEFAULT_SIZE, 250);
- EXPECT_EQ(HASHTABLE_DEFAULT_SIZE, hash1.tableSize());
- EXPECT_EQ(250, hash1.maxKeyLength());
- }
- // Test of the hash algorithm. Without duplicating the code for the algorithm
- // here, testing is a bit awkward. So the tests will check that a series of
- // names get hashed to different values. (Choosing a HASHTABLE_DEFAULT_SIZE element array should
- // give minimal overlap; we'll allow for a maximum of 2 collisions with 50
- // similar names. If there are more, perhaps the algorithm is at fault.
- TEST_F(HashTest, Algorithm) {
- const int size = HASHTABLE_DEFAULT_SIZE; // Size of the hash table
- Hash hash(size, 255, false);// Hashing algorithm object with seed
- // randomisation disabled
- string base = "alphabeta"; // Base of the names to behashed
- vector<uint32_t> values; // Results stored here
- // Generate hash values
- for (int i = 0; i < 50; ++i) {
- string name = base + boost::lexical_cast<string>(i);
- uint32_t hashval = hash(HashKey(name.c_str(), name.size(),
- RRClass(0)));
- EXPECT_LT(hashval, size);
- values.push_back(hashval);
- }
- uint32_t cursize = values.size();
- // Count the unique values in the array
- uint32_t newsize = CountUnique(values);
- // We don't expect many clashes.
- EXPECT_GE(newsize + 2, cursize);
- }
- // Test the case mapping function.
- TEST_F(HashTest, CaseMapping) {
- Hash hash(HASHTABLE_DEFAULT_SIZE, 255);
-
- // Check all unsigned characters
- for (int i = 0; i < 255; ++i) {
- if ((i >= 'A') && (i <= 'Z')) {
- EXPECT_EQ(static_cast<unsigned char>(i - 'A' + 'a'),
- hash.mapLower((unsigned char)i));
- }
- else {
- EXPECT_EQ(i, hash.mapLower(i));
- }
- }
- }
- // Test the mapping of mixed-case names
- TEST_F(HashTest, MixedCase) {
- std::string test1 = "example1234.co.uk.";
- std::string test2 = "EXAmple1234.co.uk.";
- Hash hash(HASHTABLE_DEFAULT_SIZE, 255, false); // Disable randomisation for testing
- // Case not ignored, hashes should be different
- uint32_t value1 = hash(HashKey(test1.c_str(), test1.size(), RRClass::IN()),
- false);
- uint32_t value2 = hash(HashKey(test2.c_str(), test2.size(), RRClass::IN()),
- false);
- EXPECT_NE(value1, value2);
- // Case ignored, hashes should be the same
- uint32_t value3 = hash(HashKey(test1.c_str(), test1.size(), RRClass::IN()),
- true);
- uint32_t value4 = hash(HashKey(test2.c_str(), test2.size(), RRClass::IN()),
- true);
- EXPECT_EQ(value3, value4);
- // Check the default setting.
- uint32_t value5 = hash(HashKey(test1.c_str(), test1.size(), RRClass::IN()));
- uint32_t value6 = hash(HashKey(test2.c_str(), test2.size(), RRClass::IN()));
- EXPECT_EQ(value5, value6);
- // ... and just for good measure
- EXPECT_EQ(value1, value3);
- EXPECT_EQ(value1, value5);
- }
- // Test that the same name but different classes get mapped differently.
- TEST_F(HashTest, ClassCodes) {
- std::string test1 = "example1234.co.uk.";
- Hash hash(HASHTABLE_DEFAULT_SIZE, 255, false); // Disable randomisation for testing
- // Just try codes in the range 0 to 9 - more than covers the allocated
- // codes.
- vector<uint32_t> values;
- for (uint32_t i = 0; i < 10; ++i) {
- values.push_back(hash(HashKey(test1.c_str(), test1.size(),
- RRClass(i))));
- }
- // find the number of unique values in the array. Although there can
- // be some clashes, we don't expect too many.
- uint32_t cursize = values.size();
- // Count the unique values in the array
- uint32_t newsize = CountUnique(values);
- // We don't expect many clashes.
- EXPECT_GE(newsize + 2, cursize);
- }
- // Test that the code performs when the length of the key is excessive
- TEST_F(HashTest, Overlong) {
- // String 1 is a suitable prefix, string 2 is the same prefix plus 4096
- // repetions of the character 'x'.
- std::string string1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
- std::string string2 = string1 + string(4096, 'x');
- Hash hash(HASHTABLE_DEFAULT_SIZE, string1.size());
- // Do two hashes
- uint32_t value1 = hash(HashKey(string1.c_str(), string1.size(),
- RRClass(0)));
- uint32_t value2 = hash(HashKey(string2.c_str(), string2.size(),
- RRClass(0)));
- EXPECT_EQ(value1, value2);
- }
- } // namespace nsas
- } // namespace isc
|