bitcoinleveldb_db/harness.rs
1crate::ix!();
2
3///----------------------
4struct Harness {
5 options: Options,
6 constructor: *mut Constructor,
7}
8
9impl Default for Harness {
10
11 fn default() -> Self {
12 todo!();
13 /*
14 : constructor(nullptr),
15
16
17 */
18 }
19}
20
21impl Drop for Harness {
22 fn drop(&mut self) {
23 todo!();
24 /*
25 delete constructor_;
26 */
27 }
28}
29
30impl Harness {
31
32 pub fn init(&mut self, args: &TestArgs) {
33
34 todo!();
35 /*
36 delete constructor_;
37 constructor_ = nullptr;
38 options_ = Options();
39
40 options_.block_restart_interval = args.restart_interval;
41 // Use shorter block size for tests to exercise block boundary
42 // conditions more.
43 options_.block_size = 256;
44 if (args.reverse_compare) {
45 options_.comparator = &reverse_key_comparator;
46 }
47 switch (args.type) {
48 case TABLE_TEST:
49 constructor_ = new TableConstructor(options_.comparator);
50 break;
51 case BLOCK_TEST:
52 constructor_ = new BlockConstructor(options_.comparator);
53 break;
54 case MEMTABLE_TEST:
55 constructor_ = new MemTableConstructor(options_.comparator);
56 break;
57 case DB_TEST:
58 constructor_ = new DBConstructor(options_.comparator);
59 break;
60 }
61 */
62 }
63
64 pub fn add(&mut self,
65 key_: &String,
66 value: &String) {
67
68 todo!();
69 /*
70 constructor_->Add(key, value);
71 */
72 }
73
74 pub fn test(&mut self, rnd: *mut Random) {
75
76 todo!();
77 /*
78 std::vector<std::string> keys;
79 KVMap data;
80 constructor_->Finish(options_, &keys, &data);
81
82 TestForwardScan(keys, data);
83 TestBackwardScan(keys, data);
84 TestRandomAccess(rnd, keys, data);
85 */
86 }
87
88 pub fn test_forward_scan(&mut self,
89 keys: &Vec<String>,
90 data: &KVMap) {
91
92 todo!();
93 /*
94 Iterator* iter = constructor_->NewIterator();
95 ASSERT_TRUE(!iter->Valid());
96 iter->SeekToFirst();
97 for (KVMap::const_iterator model_iter = data.begin();
98 model_iter != data.end(); ++model_iter) {
99 ASSERT_EQ(ToString(data, model_iter), ToString(iter));
100 iter->Next();
101 }
102 ASSERT_TRUE(!iter->Valid());
103 delete iter;
104 */
105 }
106
107 pub fn test_backward_scan(&mut self,
108 keys: &Vec<String>,
109 data: &KVMap) {
110
111 todo!();
112 /*
113 Iterator* iter = constructor_->NewIterator();
114 ASSERT_TRUE(!iter->Valid());
115 iter->SeekToLast();
116 for (KVMap::const_reverse_iterator model_iter = data.rbegin();
117 model_iter != data.rend(); ++model_iter) {
118 ASSERT_EQ(ToString(data, model_iter), ToString(iter));
119 iter->Prev();
120 }
121 ASSERT_TRUE(!iter->Valid());
122 delete iter;
123 */
124 }
125
126 pub fn test_random_access(&mut self,
127 rnd: *mut Random,
128 keys: &Vec<String>,
129 data: &KVMap) {
130
131 todo!();
132 /*
133 static const bool kVerbose = false;
134 Iterator* iter = constructor_->NewIterator();
135 ASSERT_TRUE(!iter->Valid());
136 KVMap::const_iterator model_iter = data.begin();
137 if (kVerbose) fprintf(stderr, "---\n");
138 for (int i = 0; i < 200; i++) {
139 const int toss = rnd->Uniform(5);
140 switch (toss) {
141 case 0: {
142 if (iter->Valid()) {
143 if (kVerbose) fprintf(stderr, "Next\n");
144 iter->Next();
145 ++model_iter;
146 ASSERT_EQ(ToString(data, model_iter), ToString(iter));
147 }
148 break;
149 }
150
151 case 1: {
152 if (kVerbose) fprintf(stderr, "SeekToFirst\n");
153 iter->SeekToFirst();
154 model_iter = data.begin();
155 ASSERT_EQ(ToString(data, model_iter), ToString(iter));
156 break;
157 }
158
159 case 2: {
160 std::string key = PickRandomKey(rnd, keys);
161 model_iter = data.lower_bound(key);
162 if (kVerbose)
163 fprintf(stderr, "Seek '%s'\n", EscapeString(key).c_str());
164 iter->Seek(Slice(key));
165 ASSERT_EQ(ToString(data, model_iter), ToString(iter));
166 break;
167 }
168
169 case 3: {
170 if (iter->Valid()) {
171 if (kVerbose) fprintf(stderr, "Prev\n");
172 iter->Prev();
173 if (model_iter == data.begin()) {
174 model_iter = data.end(); // Wrap around to invalid value
175 } else {
176 --model_iter;
177 }
178 ASSERT_EQ(ToString(data, model_iter), ToString(iter));
179 }
180 break;
181 }
182
183 case 4: {
184 if (kVerbose) fprintf(stderr, "SeekToLast\n");
185 iter->SeekToLast();
186 if (keys.empty()) {
187 model_iter = data.end();
188 } else {
189 std::string last = data.rbegin()->first;
190 model_iter = data.lower_bound(last);
191 }
192 ASSERT_EQ(ToString(data, model_iter), ToString(iter));
193 break;
194 }
195 }
196 }
197 delete iter;
198 */
199 }
200
201 pub fn to_string_with_data<'a>(&mut self,
202 data: &KVMap,
203 it: &dyn std::iter::Iterator<Item = (&'a String,&'a String)>) -> String {
204
205 todo!();
206 /*
207 if (it == data.end()) {
208 return "END";
209 } else {
210 return "'" + it->first + "->" + it->second + "'";
211 }
212 */
213 }
214
215 pub fn to_string_rev<'a>(&mut self,
216 data: &KVMap,
217 it: &dyn DoubleEndedIterator<Item = (&'a String,&'a String)>) -> String {
218
219 todo!();
220 /*
221 if (it == data.rend()) {
222 return "END";
223 } else {
224 return "'" + it->first + "->" + it->second + "'";
225 }
226 */
227 }
228
229 pub fn to_string(&mut self, it: *const LevelDBIterator) -> String {
230
231 todo!();
232 /*
233 if (!it->Valid()) {
234 return "END";
235 } else {
236 return "'" + it->key().ToString() + "->" + it->value().ToString() + "'";
237 }
238 */
239 }
240
241 pub fn pick_random_key(&mut self,
242 rnd: *mut Random,
243 keys: &Vec<String>) -> String {
244
245 todo!();
246 /*
247 if (keys.empty()) {
248 return "foo";
249 } else {
250 const int index = rnd->Uniform(keys.size());
251 std::string result = keys[index];
252 switch (rnd->Uniform(3)) {
253 case 0:
254 // Return an existing key
255 break;
256 case 1: {
257 // Attempt to return something smaller than an existing key
258 if (!result.empty() && result[result.size() - 1] > '\0') {
259 result[result.size() - 1]--;
260 }
261 break;
262 }
263 case 2: {
264 // Return something larger than an existing key
265 Increment(options_.comparator, &result);
266 break;
267 }
268 }
269 return result;
270 }
271 */
272 }
273
274 /**
275 Returns nullptr if not running against a DB
276 */
277 pub fn db(&self) -> *mut dyn DB {
278
279 todo!();
280 /*
281 return constructor_->db();
282 */
283 }
284}
285
286/**
287 Test empty table/block.
288 */
289#[test] fn harness_empty() {
290 todo!();
291 /*
292
293 for (int i = 0; i < kNumTestArgs; i++) {
294 Init(kTestArgList[i]);
295 Random rnd(test::RandomSeed() + 1);
296 Test(&rnd);
297 }
298
299 */
300}
301
302/**
303 | Special test for a block with no restart
304 | entries. The C++ leveldb code never generates
305 | such blocks, but the Java version of leveldb
306 | seems to.
307 */
308#[test] fn harness_zero_restart_points_in_block() {
309 todo!();
310 /*
311
312 char data[sizeof(uint32_t)];
313 memset(data, 0, sizeof(data));
314 BlockContents contents;
315 contents.data = Slice(data, sizeof(data));
316 contents.cachable = false;
317 contents.heap_allocated = false;
318 Block block(contents);
319 Iterator* iter = block.NewIterator(BytewiseComparator());
320 iter->SeekToFirst();
321 ASSERT_TRUE(!iter->Valid());
322 iter->SeekToLast();
323 ASSERT_TRUE(!iter->Valid());
324 iter->Seek("foo");
325 ASSERT_TRUE(!iter->Valid());
326 delete iter;
327
328 */
329}
330
331/**
332 | Test the empty key
333 |
334 */
335#[test] fn harness_simple_empty_key() {
336 todo!();
337 /*
338
339 for (int i = 0; i < kNumTestArgs; i++) {
340 Init(kTestArgList[i]);
341 Random rnd(test::RandomSeed() + 1);
342 Add("", "v");
343 Test(&rnd);
344 }
345
346 */
347}
348
349#[test] fn harness_simple_single() {
350 todo!();
351 /*
352
353 for (int i = 0; i < kNumTestArgs; i++) {
354 Init(kTestArgList[i]);
355 Random rnd(test::RandomSeed() + 2);
356 Add("abc", "v");
357 Test(&rnd);
358 }
359
360 */
361}
362
363#[test] fn harness_simple_multi() {
364 todo!();
365 /*
366
367 for (int i = 0; i < kNumTestArgs; i++) {
368 Init(kTestArgList[i]);
369 Random rnd(test::RandomSeed() + 3);
370 Add("abc", "v");
371 Add("abcd", "v");
372 Add("ac", "v2");
373 Test(&rnd);
374 }
375
376 */
377}
378
379#[test] fn harness_simple_special_key() {
380 todo!();
381 /*
382
383 for (int i = 0; i < kNumTestArgs; i++) {
384 Init(kTestArgList[i]);
385 Random rnd(test::RandomSeed() + 4);
386 Add("\xff\xff", "v3");
387 Test(&rnd);
388 }
389
390 */
391}
392
393#[test] fn harness_randomized() {
394 todo!();
395 /*
396
397 for (int i = 0; i < kNumTestArgs; i++) {
398 Init(kTestArgList[i]);
399 Random rnd(test::RandomSeed() + 5);
400 for (int num_entries = 0; num_entries < 2000;
401 num_entries += (num_entries < 50 ? 1 : 200)) {
402 if ((num_entries % 10) == 0) {
403 fprintf(stderr, "case %d of %d: num_entries = %d\n", (i + 1),
404 int(kNumTestArgs), num_entries);
405 }
406 for (int e = 0; e < num_entries; e++) {
407 std::string v;
408 Add(test::RandomKey(&rnd, rnd.Skewed(4)),
409 test::RandomString(&rnd, rnd.Skewed(5), &v).ToString());
410 }
411 Test(&rnd);
412 }
413 }
414
415 */
416}
417
418#[test] fn harness_randomized_longdb() {
419 todo!();
420 /*
421
422 Random rnd(test::RandomSeed());
423 TestArgs args = {DB_TEST, false, 16};
424 Init(args);
425 int num_entries = 100000;
426 for (int e = 0; e < num_entries; e++) {
427 std::string v;
428 Add(test::RandomKey(&rnd, rnd.Skewed(4)),
429 test::RandomString(&rnd, rnd.Skewed(5), &v).ToString());
430 }
431 Test(&rnd);
432
433 // We must have created enough data to force merging
434 int files = 0;
435 for (int level = 0; level < config::kNumLevels; level++) {
436 std::string value;
437 char name[100];
438 snprintf(name, sizeof(name), "leveldb.num-files-at-level%d", level);
439 ASSERT_TRUE(db()->GetProperty(name, &value));
440 files += atoi(value.c_str());
441 }
442 ASSERT_GT(files, 0);
443
444 */
445}
446
447pub enum TestType {
448 TABLE_TEST,
449 BLOCK_TEST,
450 MEMTABLE_TEST,
451 DB_TEST
452}
453
454pub struct TestArgs {
455 ty: TestType,
456 reverse_compare: bool,
457 restart_interval: i32,
458}
459
460lazy_static!{
461 /*
462 static const TestArgs TestArgList[] = {
463 {TABLE_TEST, false, 16},
464 {TABLE_TEST, false, 1},
465 {TABLE_TEST, false, 1024},
466 {TABLE_TEST, true, 16},
467 {TABLE_TEST, true, 1},
468 {TABLE_TEST, true, 1024},
469
470 {BLOCK_TEST, false, 16},
471 {BLOCK_TEST, false, 1},
472 {BLOCK_TEST, false, 1024},
473 {BLOCK_TEST, true, 16},
474 {BLOCK_TEST, true, 1},
475 {BLOCK_TEST, true, 1024},
476
477 // Restart interval does not matter for memtables
478 {MEMTABLE_TEST, false, 16},
479 {MEMTABLE_TEST, true, 16},
480
481 // Do not bother with restart interval variations for DB
482 {DB_TEST, false, 16},
483 {DB_TEST, true, 16},
484 };
485
486 const NUM_TEST_ARGS: i32 = size_of_val(&TEST_ARG_LIST) / size_of_val(&TEST_ARG_LIST[0]);
487 */
488}
489
490pub struct TableTest {}
491
492#[test] fn table_test_approximate_offset_of_plain() {
493 todo!();
494 /*
495
496 TableConstructor c(BytewiseComparator());
497 c.Add("k01", "hello");
498 c.Add("k02", "hello2");
499 c.Add("k03", std::string(10000, 'x'));
500 c.Add("k04", std::string(200000, 'x'));
501 c.Add("k05", std::string(300000, 'x'));
502 c.Add("k06", "hello3");
503 c.Add("k07", std::string(100000, 'x'));
504 std::vector<std::string> keys;
505 KVMap kvmap;
506 Options options;
507 options.block_size = 1024;
508 options.compression = kNoCompression;
509 c.Finish(options, &keys, &kvmap);
510
511 ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0));
512 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0));
513 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01a"), 0, 0));
514 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0));
515 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 0, 0));
516 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 10000, 11000));
517 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04a"), 210000, 211000));
518 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k05"), 210000, 211000));
519 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"), 510000, 511000));
520 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"), 510000, 511000));
521 ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 610000, 612000));
522
523 */
524}
525
526pub fn snappy_compression_supported() -> bool {
527
528 todo!();
529 /*
530 std::string out;
531 Slice in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
532 return Snappy_Compress(in.data(), in.size(), &out);
533 */
534}
535
536#[test] fn table_test_approximate_offset_of_compressed() {
537 todo!();
538 /*
539
540 if (!SnappyCompressionSupported()) {
541 fprintf(stderr, "skipping compression tests\n");
542 return;
543 }
544
545 Random rnd(301);
546 TableConstructor c(BytewiseComparator());
547 std::string tmp;
548 c.Add("k01", "hello");
549 c.Add("k02", test::CompressibleString(&rnd, 0.25, 10000, &tmp));
550 c.Add("k03", "hello3");
551 c.Add("k04", test::CompressibleString(&rnd, 0.25, 10000, &tmp));
552 std::vector<std::string> keys;
553 KVMap kvmap;
554 Options options;
555 options.block_size = 1024;
556 options.compression = kSnappyCompression;
557 c.Finish(options, &keys, &kvmap);
558
559 // Expected upper and lower bounds of space used by compressible strings.
560 static const int kSlop = 1000; // Compressor effectiveness varies.
561 const int expected = 2500; // 10000 * compression ratio (0.25)
562 const int min_z = expected - kSlop;
563 const int max_z = expected + kSlop;
564
565 ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, kSlop));
566 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, kSlop));
567 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, kSlop));
568 // Have now emitted a large compressible string, so adjust expected offset.
569 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), min_z, max_z));
570 ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), min_z, max_z));
571 // Have now emitted two large compressible strings, so adjust expected offset.
572 ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 2 * min_z, 2 * max_z));
573
574 */
575}
576
577pub fn tabletable_test_main (
578 argc: i32,
579 argv: *mut *mut u8) -> i32 {
580
581 todo!();
582 /*
583 return leveldb::test::RunAllTests();
584 */
585}