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}