You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lhash_test.cc 3.8 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /* Copyright (c) 2014, Google Inc.
  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 THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
  14. #if !defined(_POSIX_C_SOURCE)
  15. #define _POSIX_C_SOURCE 201410L
  16. #endif
  17. #include <openssl/lhash.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <algorithm>
  22. #include <memory>
  23. #include <map>
  24. #include <string>
  25. #include <utility>
  26. #include <vector>
  27. #include <gtest/gtest.h>
  28. static std::unique_ptr<char[]> RandString(void) {
  29. unsigned len = 1 + (rand() % 3);
  30. std::unique_ptr<char[]> ret(new char[len + 1]);
  31. for (unsigned i = 0; i < len; i++) {
  32. ret[i] = '0' + (rand() & 7);
  33. }
  34. ret[len] = 0;
  35. return ret;
  36. }
  37. struct FreeLHASH {
  38. void operator()(_LHASH *lh) { lh_free(lh); }
  39. };
  40. static const char *Lookup(
  41. std::map<std::string, std::unique_ptr<char[]>> *dummy_lh, const char *key) {
  42. // Using operator[] implicitly inserts into the map.
  43. auto iter = dummy_lh->find(key);
  44. if (iter == dummy_lh->end()) {
  45. return nullptr;
  46. }
  47. return iter->second.get();
  48. }
  49. TEST(LHashTest, Basic) {
  50. std::unique_ptr<_LHASH, FreeLHASH> lh(
  51. lh_new((lhash_hash_func)lh_strhash, (lhash_cmp_func)strcmp));
  52. ASSERT_TRUE(lh);
  53. // lh is expected to store a canonical instance of each string. dummy_lh
  54. // mirrors what it stores for comparison. It also manages ownership of the
  55. // pointers.
  56. std::map<std::string, std::unique_ptr<char[]>> dummy_lh;
  57. for (unsigned i = 0; i < 100000; i++) {
  58. EXPECT_EQ(dummy_lh.size(), lh_num_items(lh.get()));
  59. // Check the entire contents and test |lh_doall_arg|. This takes O(N) time,
  60. // so only do it every few iterations.
  61. //
  62. // TODO(davidben): |lh_doall_arg| also supports modifying the hash in the
  63. // callback. Test this.
  64. if (i % 1000 == 0) {
  65. using ValueList = std::vector<const char *>;
  66. ValueList expected, actual;
  67. for (const auto &pair : dummy_lh) {
  68. expected.push_back(pair.second.get());
  69. }
  70. std::sort(expected.begin(), expected.end());
  71. lh_doall_arg(lh.get(),
  72. [](void *ptr, void *arg) {
  73. ValueList *out = reinterpret_cast<ValueList *>(arg);
  74. out->push_back(reinterpret_cast<char *>(ptr));
  75. },
  76. &actual);
  77. std::sort(actual.begin(), actual.end());
  78. EXPECT_EQ(expected, actual);
  79. }
  80. enum Action {
  81. kRetrieve = 0,
  82. kInsert,
  83. kDelete,
  84. };
  85. Action action = static_cast<Action>(rand() % 3);
  86. switch (action) {
  87. case kRetrieve: {
  88. std::unique_ptr<char[]> key = RandString();
  89. void *value = lh_retrieve(lh.get(), key.get());
  90. EXPECT_EQ(Lookup(&dummy_lh, key.get()), value);
  91. break;
  92. }
  93. case kInsert: {
  94. std::unique_ptr<char[]> key = RandString();
  95. void *previous;
  96. ASSERT_TRUE(lh_insert(lh.get(), &previous, key.get()));
  97. EXPECT_EQ(Lookup(&dummy_lh, key.get()), previous);
  98. dummy_lh[key.get()] = std::move(key);
  99. break;
  100. }
  101. case kDelete: {
  102. std::unique_ptr<char[]> key = RandString();
  103. void *value = lh_delete(lh.get(), key.get());
  104. EXPECT_EQ(Lookup(&dummy_lh, key.get()), value);
  105. dummy_lh.erase(key.get());
  106. break;
  107. }
  108. }
  109. }
  110. }