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.
 
 
 
 
 
 

162 rivejä
4.3 KiB

  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/crypto.h>
  18. #include <openssl/lhash.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <algorithm>
  23. #include <memory>
  24. #include <map>
  25. #include <string>
  26. #include <utility>
  27. #include <vector>
  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. int main(int argc, char **argv) {
  50. CRYPTO_library_init();
  51. std::unique_ptr<_LHASH, FreeLHASH> lh(
  52. lh_new((lhash_hash_func)lh_strhash, (lhash_cmp_func)strcmp));
  53. if (!lh) {
  54. return 1;
  55. }
  56. // lh is expected to store a canonical instance of each string. dummy_lh
  57. // mirrors what it stores for comparison. It also manages ownership of the
  58. // pointers.
  59. std::map<std::string, std::unique_ptr<char[]>> dummy_lh;
  60. for (unsigned i = 0; i < 100000; i++) {
  61. if (dummy_lh.size() != lh_num_items(lh.get())) {
  62. fprintf(stderr, "Length mismatch\n");
  63. return 1;
  64. }
  65. // Check the entire contents and test |lh_doall_arg|. This takes O(N) time,
  66. // so only do it every few iterations.
  67. //
  68. // TODO(davidben): |lh_doall_arg| also supports modifying the hash in the
  69. // callback. Test this.
  70. if (i % 1000 == 0) {
  71. using ValueList = std::vector<const char *>;
  72. ValueList expected, actual;
  73. for (const auto &pair : dummy_lh) {
  74. expected.push_back(pair.second.get());
  75. }
  76. std::sort(expected.begin(), expected.end());
  77. lh_doall_arg(lh.get(),
  78. [](void *ptr, void *arg) {
  79. ValueList *out = reinterpret_cast<ValueList *>(arg);
  80. out->push_back(reinterpret_cast<char *>(ptr));
  81. },
  82. &actual);
  83. std::sort(actual.begin(), actual.end());
  84. if (expected != actual) {
  85. fprintf(stderr, "Contents mismatch\n");
  86. return 1;
  87. }
  88. }
  89. enum Action {
  90. kRetrieve = 0,
  91. kInsert,
  92. kDelete,
  93. };
  94. Action action = static_cast<Action>(rand() % 3);
  95. switch (action) {
  96. case kRetrieve: {
  97. std::unique_ptr<char[]> key = RandString();
  98. void *value = lh_retrieve(lh.get(), key.get());
  99. if (value != Lookup(&dummy_lh, key.get())) {
  100. fprintf(stderr, "lh_retrieve failure\n");
  101. return 1;
  102. }
  103. break;
  104. }
  105. case kInsert: {
  106. std::unique_ptr<char[]> key = RandString();
  107. void *previous;
  108. if (!lh_insert(lh.get(), &previous, key.get())) {
  109. return 1;
  110. }
  111. if (previous != Lookup(&dummy_lh, key.get())) {
  112. fprintf(stderr, "lh_insert failure\n");
  113. return 1;
  114. }
  115. dummy_lh[key.get()] = std::move(key);
  116. break;
  117. }
  118. case kDelete: {
  119. std::unique_ptr<char[]> key = RandString();
  120. void *value = lh_delete(lh.get(), key.get());
  121. if (value != Lookup(&dummy_lh, key.get())) {
  122. fprintf(stderr, "lh_delete failure\n");
  123. return 1;
  124. }
  125. dummy_lh.erase(key.get());
  126. break;
  127. }
  128. default:
  129. abort();
  130. }
  131. }
  132. printf("PASS\n");
  133. return 0;
  134. }