1 #include "iwkv.h"
2 #include "iwlog.h"
3 #include "iwutils.h"
4 #include "iwcfg.h"
5 #include "iwkv_tests.h"
6 
7 #define KBUFSZ 128
8 #define VBUFSZ 128
9 char kbuf[KBUFSZ];
10 char vbuf[VBUFSZ];
11 
12 extern int8_t iwkv_next_level;
13 
logstage(FILE * f,const char * name,IWDB db)14 static int logstage(FILE *f, const char *name, IWDB db) {
15   int rci = fprintf(f, "\n#### Stage: %s\n", name);
16   iwkvd_db(f, db, IWKVD_PRINT_NO_LEVEVELS | IWKVD_PRINT_VALS, 0);
17   fflush(f);
18   return rci < 0 ? rci : 0;
19 }
20 
logstage2(FILE * f,const char * name,IWDB db)21 static int logstage2(FILE *f, const char *name, IWDB db) {
22   int rci = fprintf(f, "\n#### Stage: %s\n", name);
23   iwkvd_db(f, db, IWKVD_PRINT_NO_LEVEVELS | IWKVD_PRINT_VALS, 0);
24   fflush(f);
25   return rci < 0 ? rci : 0;
26 }
27 
init_suite()28 int init_suite() {
29   iwrc rc = iwkv_init();
30   return rc;
31 }
32 
clean_suite()33 int clean_suite() {
34   return 0;
35 }
36 
37 // Test5 staff
38 struct Test5DUP1 {
39   bool _mv;
40   bool _1v;
41   bool _10v;
42 };
43 
_test5dup5visitor(uint64_t dv,int64_t idx,void * op)44 static int64_t _test5dup5visitor(uint64_t dv, int64_t idx, void *op) {
45   CU_ASSERT_PTR_NOT_NULL_FATAL(op);
46   struct Test5DUP1 *s = op;
47   switch (dv) {
48     case -1ULL:
49       s->_mv = true;
50       break;
51     case 1ULL:
52       s->_1v = true;
53       break;
54     case 10ULL:
55       s->_10v = true;
56       break;
57     default:
58       CU_FAIL("Invalid dup value");
59       break;
60   }
61   return 1;
62 }
63 
64 // Test Slides
iwkv_test3_impl(int fmt_version)65 static void iwkv_test3_impl(int fmt_version) {
66   FILE *f = fmt_version > 1 ? fopen("iwkv_test1_3_v2.log", "w+") : fopen("iwkv_test1_3.log", "w+");
67   CU_ASSERT_PTR_NOT_NULL(f);
68 
69   iwrc rc;
70   IWKV_val key = { 0 };
71   IWKV_val val = { 0 };
72   IWKV iwkv;
73   IWDB db1;
74   IWKV_OPTS opts = {
75     .path        = "iwkv_test1_3.db",
76     .oflags      = IWKV_TRUNC,
77     .fmt_version = fmt_version
78   };
79 
80   rc = iwkv_open(&opts, &iwkv);
81   CU_ASSERT_EQUAL_FATAL(rc, 0);
82   rc = iwkv_db(iwkv, 1, 0, &db1);
83   CU_ASSERT_EQUAL_FATAL(rc, 0);
84 
85   for (int i = -23, c = 0; i <= 23; ++i) {
86     for (int j = 0; j < 63; ++j, ++c) {
87       iwkv_next_level = i < 0 ? -i : i;
88       snprintf(kbuf, KBUFSZ, "%05dkkk", c);
89       snprintf(vbuf, VBUFSZ, "%05dval", c);
90       key.data = kbuf;
91       key.size = strlen(key.data);
92       val.data = vbuf;
93       val.size = strlen(val.data);
94       rc = iwkv_put(db1, &key, &val, 0);
95       CU_ASSERT_EQUAL_FATAL(rc, 0);
96     }
97   }
98   //       middle
99   // 23 \    |    / 23
100   //     \   |   /
101   //    0 \__|__/ 0
102   iwkv_next_level = 23;
103   // put: 01858aaa in order to split middle zero sblk
104   snprintf(kbuf, KBUFSZ, "%05daaa", 1858);
105   snprintf(vbuf, VBUFSZ, "%05dval", 1858);
106   rc = iwkv_put(db1, &key, &val, 0);
107   CU_ASSERT_EQUAL_FATAL(rc, 0);
108 
109   logstage2(f, "iwkv_test3", db1);
110 
111   rc = iwkv_close(&iwkv);
112   CU_ASSERT_EQUAL_FATAL(rc, 0);
113   // Compare logs with referenced
114 #ifndef _WIN32
115   FILE *r = fmt_version > 1 ? fopen("iwkv_test1_3_v2.ref", "r+") : fopen("iwkv_test1_3.ref", "r+");
116 #else
117   FILE *r = fmt_version > 1 ? fopen("iwkv_test1_3w_v2.ref", "r+") : fopen("iwkv_test1_3w.ref", "r+");
118 #endif
119   CU_ASSERT_PTR_NOT_NULL(r);
120   int rci = cmp_files(r, f);
121   CU_ASSERT_EQUAL_FATAL(rci, 0);
122   fclose(f);
123   fclose(r);
124 }
125 
iwkv_test3_v1()126 static void iwkv_test3_v1() {
127   iwkv_test3_impl(1);
128 }
129 
iwkv_test3_v2()130 static void iwkv_test3_v2() {
131   iwkv_test3_impl(2);
132 }
133 
iwkv_test2_impl(int fmt_version)134 static void iwkv_test2_impl(int fmt_version) {
135   FILE *f = fmt_version > 1 ? fopen("iwkv_test1_2_v2.log", "w+") : fopen("iwkv_test1_2.log", "w+");
136   CU_ASSERT_PTR_NOT_NULL(f);
137 
138   iwrc rc;
139   IWKV_val key = { 0 };
140   IWKV_val val = { 0 };
141   IWKV iwkv;
142   IWDB db1;
143   IWKV_OPTS opts = {
144     .path        = "iwkv_test1_2.db",
145     .oflags      = IWKV_TRUNC,
146     .fmt_version = fmt_version
147   };
148 
149   rc = iwkv_open(&opts, &iwkv);
150   CU_ASSERT_EQUAL_FATAL(rc, 0);
151   rc = iwkv_db(iwkv, 1, 0, &db1);
152   CU_ASSERT_EQUAL_FATAL(rc, 0);
153 
154   for (int i = 252 * 2; i >= 0; --i) { // 189
155     snprintf(kbuf, KBUFSZ, "%03dkkk", i);
156     snprintf(vbuf, VBUFSZ, "%03dval", i);
157     key.data = kbuf;
158     key.size = strlen(key.data);
159     val.data = vbuf;
160     val.size = strlen(val.data);
161     rc = iwkv_put(db1, &key, &val, 0);
162     CU_ASSERT_EQUAL_FATAL(rc, 0);
163   }
164   logstage(f, "desc sorted keys inserted", db1);
165 
166   for (int i = 0; i <= 252 * 2; ++i) {
167     int cret;
168     snprintf(kbuf, KBUFSZ, "%03dkkk", i);
169     snprintf(vbuf, VBUFSZ, "%03dval", i);
170     int vsize = strlen(vbuf);
171     key.data = kbuf;
172     key.size = strlen(key.data);
173     rc = iwkv_get(db1, &key, &val);
174     CU_ASSERT_EQUAL_FATAL(rc, 0);
175     IW_CMP(cret, vbuf, vsize, val.data, val.size);
176     CU_ASSERT_EQUAL_FATAL(cret, 0);
177     iwkv_kv_dispose(0, &val);
178   }
179 
180   //  snprintf(kbuf, KBUFSZ, "%03dkkk", 64);
181   //  key.data = kbuf;
182   //  key.size = strlen(key.data);
183   //  rc = iwkv_del(db1, &key);
184   //  CU_ASSERT_EQUAL_FATAL(rc, 0);
185   //  logstage(f, "removed 064kkk", db1);
186   //
187   //
188   //  snprintf(kbuf, KBUFSZ, "%03dkkk", 126);
189   //  key.data = kbuf;
190   //  key.size = strlen(key.data);
191   //  rc = iwkv_del(db1, &key);
192   //  CU_ASSERT_EQUAL_FATAL(rc, 0);
193   //  logstage(f, "removed 126kkk", db1);
194   //
195   //
196   //  // Now delete more than half of block records
197   //  // 126
198   //  for (int i = 64; i <= 99; ++i) {
199   //    snprintf(kbuf, KBUFSZ, "%03dkkk", i);
200   //    key.data = kbuf;
201   //    key.size = strlen(key.data);
202   //    rc = iwkv_del(db1, &key);
203   //    if (i == 64) {
204   //      CU_ASSERT_EQUAL(rc, IWKV_ERROR_NOTFOUND);
205   //      rc = 0;
206   //      continue;
207   //    }
208   //    CU_ASSERT_EQUAL_FATAL(rc, 0);
209   //  }
210   //  logstage(f, "removed 065kkk - 099kkk", db1); // 125
211   //
212   //  for (int i = 100; i <= 125; ++i) {
213   //    snprintf(kbuf, KBUFSZ, "%03dkkk", i);
214   //    key.data = kbuf;
215   //    key.size = strlen(key.data);
216   //    rc = iwkv_del(db1, &key);
217   //    CU_ASSERT_EQUAL_FATAL(rc, 0);
218   //  }
219   //  logstage(f, "removed all keys in SBLK[54]", db1); // 125
220 
221   rc = iwkv_db_destroy(&db1);      // Destroy DB and remove all db blocks
222   CU_ASSERT_EQUAL_FATAL(rc, 0);
223 
224   rc = iwkv_close(&iwkv);
225   CU_ASSERT_EQUAL_FATAL(rc, 0);
226 
227   // Reopen DB then check db1
228   rc = iwkv_open(&opts, &iwkv);
229   CU_ASSERT_EQUAL_FATAL(rc, 0);
230 
231   rc = iwkv_db(iwkv, 1, 0, &db1);
232   CU_ASSERT_EQUAL_FATAL(rc, 0);
233   logstage(f, "db1 destroyed", db1);
234   rc = iwkv_close(&iwkv);
235   CU_ASSERT_EQUAL_FATAL(rc, 0);
236 
237   // Compare logs with referenced
238 #ifndef _WIN32
239   FILE *r = fmt_version > 1 ? fopen("iwkv_test1_2_v2.ref", "r+") : fopen("iwkv_test1_2.ref", "r+");
240 #else
241   FILE *r = fmt_version > 1 ? fopen("iwkv_test1_2w_v2.ref", "r+") : fopen("iwkv_test1_2w.ref", "r+");
242 #endif
243   CU_ASSERT_PTR_NOT_NULL(r);
244   int rci = cmp_files(r, f);
245   CU_ASSERT_EQUAL_FATAL(rci, 0);
246   fclose(f);
247   fclose(r);
248 }
249 
iwkv_test2_v1()250 static void iwkv_test2_v1() {
251   iwkv_test2_impl(1);
252 }
253 
iwkv_test2_v2()254 static void iwkv_test2_v2() {
255   iwkv_test2_impl(2);
256 }
257 
iwkv_test1_impl(int fmt_version)258 static void iwkv_test1_impl(int fmt_version) {
259   FILE *f = fmt_version > 1 ? fopen("iwkv_test1_1_v2.log", "w+") : fopen("iwkv_test1_1.log", "w+");
260   CU_ASSERT_PTR_NOT_NULL(f);
261   char buf[128];
262   size_t vsize;
263 
264   IWKV_OPTS opts = {
265     .path        = "iwkv_test1.db",
266     .oflags      = IWKV_TRUNC,
267     .fmt_version = fmt_version
268   };
269   // Test open/close
270   IWKV iwkv;
271   IWDB db1, db2, db3;
272   iwrc rc;
273   IWKV_val key = { .data = "foo" };
274   key.size = strlen(key.data);
275   IWKV_val val = { .data = "bar" };
276   val.size = strlen(val.data);
277 
278   rc = iwkv_open(&opts, &iwkv);
279   CU_ASSERT_EQUAL_FATAL(rc, 0);
280   rc = iwkv_close(&iwkv);
281   CU_ASSERT_EQUAL_FATAL(rc, 0);
282 
283   // Test open/close existing db
284   opts.oflags = 0;
285   rc = iwkv_open(&opts, &iwkv);
286   CU_ASSERT_EQUAL_FATAL(rc, 0);
287   rc = iwkv_close(&iwkv);
288   CU_ASSERT_EQUAL_FATAL(rc, 0);
289 
290   // Test create/destroy db
291   rc = iwkv_open(&opts, &iwkv);
292   CU_ASSERT_EQUAL_FATAL(rc, 0);
293   rc = iwkv_db(iwkv, 1, 0, &db1);
294   CU_ASSERT_EQUAL_FATAL(rc, 0);
295   rc = iwkv_db(iwkv, 2, 0, &db2); // destroyed
296   CU_ASSERT_EQUAL_FATAL(rc, 0);
297   rc = iwkv_db(iwkv, 3, 0, &db3);
298   CU_ASSERT_EQUAL_FATAL(rc, 0);
299   rc = iwkv_db_destroy(&db2);     // destroyed
300   CU_ASSERT_EQUAL_FATAL(rc, 0);
301   rc = iwkv_close(&iwkv);
302   CU_ASSERT_EQUAL_FATAL(rc, 0);
303 
304   // Test one in read-only mode
305   opts.oflags = IWKV_RDONLY;
306   opts.path = "not-existing.db";
307   rc = iwkv_open(&opts, &iwkv);
308   CU_ASSERT_TRUE_FATAL(rc);
309   iwrc_strip_errno(&rc);
310 #ifdef _WIN32
311   iwrc_strip_werror(&rc);
312 #endif
313   CU_ASSERT_EQUAL(rc, IW_ERROR_NOT_EXISTS);
314 
315   // Open in read-only mode and acquire not existing db
316   opts.path = "iwkv_test1.db";
317   rc = iwkv_open(&opts, &iwkv);
318   CU_ASSERT_EQUAL_FATAL(rc, 0);
319 
320   rc = iwkv_db(iwkv, 2, 0, &db2);
321   CU_ASSERT_EQUAL(rc, IW_ERROR_READONLY);
322 
323   rc = iwkv_db(iwkv, 1, 0, &db1);
324   CU_ASSERT_EQUAL_FATAL(rc, 0);
325 
326   rc = iwkv_db(iwkv, 3, 0, &db3);
327   CU_ASSERT_EQUAL_FATAL(rc, 0);
328 
329   logstage(f, "empty db", db1);
330 
331   rc = iwkv_close(&iwkv);
332   CU_ASSERT_EQUAL_FATAL(rc, 0);
333 
334   // Open in write mode, then put a simple kv
335   opts.oflags = 0;
336   rc = iwkv_open(&opts, &iwkv);
337   CU_ASSERT_EQUAL_FATAL(rc, 0);
338   rc = iwkv_db(iwkv, 1, 0, &db1);
339   CU_ASSERT_EQUAL_FATAL(rc, 0);
340   // iwkv_next_level = 3;
341   rc = iwkv_put(db1, &key, &val, 0);
342   CU_ASSERT_EQUAL_FATAL(rc, 0);
343 
344   logstage(f, "put foo:bar", db1);
345 
346   rc = iwkv_close(&iwkv);
347   CU_ASSERT_EQUAL_FATAL(rc, 0);
348 
349   // Open db and get out single record
350   rc = iwkv_open(&opts, &iwkv);
351   CU_ASSERT_EQUAL_FATAL(rc, 0);
352   rc = iwkv_db(iwkv, 1, 0, &db1);
353   CU_ASSERT_EQUAL_FATAL(rc, 0);
354   val.size = 0;
355   val.data = 0;
356 
357   rc = iwkv_get(db1, &key, &val);
358   CU_ASSERT_EQUAL_FATAL(rc, 0);
359   CU_ASSERT_NSTRING_EQUAL(key.data, "foo", key.size);
360   CU_ASSERT_NSTRING_EQUAL(val.data, "bar", val.size);
361   iwkv_kv_dispose(0, &val);
362 
363   rc = iwkv_get_copy(db1, &key, buf, sizeof(buf), &vsize);
364   CU_ASSERT_EQUAL_FATAL(rc, 0);
365   CU_ASSERT_EQUAL(3, vsize);
366   CU_ASSERT_NSTRING_EQUAL(buf, "bar", vsize);
367 
368   rc = iwkv_get_copy(db1, &key, buf, 1, &vsize);
369   CU_ASSERT_EQUAL_FATAL(rc, 0);
370   CU_ASSERT_EQUAL(3, vsize);
371   CU_ASSERT_NSTRING_EQUAL(buf, "b", 1);
372 
373   // put foo->bazzz
374   key.data = "foo";
375   key.size = strlen(key.data);
376   val.data = "bazzz";
377   val.size = strlen(val.data);
378   rc = iwkv_put(db1, &key, &val, 0);
379   CU_ASSERT_EQUAL_FATAL(rc, 0);
380 
381   // put foo->zzz with IWKV_NO_OVERWRITE
382   val.data = "zzz";
383   val.size = strlen(val.data);
384   rc = iwkv_put(db1, &key, &val, IWKV_NO_OVERWRITE);
385 
386   CU_ASSERT_EQUAL_FATAL(rc, IWKV_ERROR_KEY_EXISTS);
387   rc = iwkv_get(db1, &key, &val);
388   CU_ASSERT_NSTRING_EQUAL(key.data, "foo", key.size);
389   CU_ASSERT_NSTRING_EQUAL(val.data, "bazzz", val.size);
390   iwkv_kv_dispose(0, &val);
391 
392   logstage(f, "put foo:bazz", db1);
393 
394   // put foo->''
395   val.data = "";
396   val.size = strlen(val.data);
397   rc = iwkv_put(db1, &key, &val, 0);
398   CU_ASSERT_EQUAL_FATAL(rc, 0);
399   rc = iwkv_get(db1, &key, &val);
400   CU_ASSERT_NSTRING_EQUAL(key.data, "foo", key.size);
401   CU_ASSERT_NSTRING_EQUAL(val.data, "", val.size);
402   iwkv_kv_dispose(0, &val);
403 
404   logstage(f, "put foo:", db1);
405 
406   val.data = "bar";
407   val.size = strlen(val.data);
408   rc = iwkv_put(db1, &key, &val, 0);
409   CU_ASSERT_EQUAL_FATAL(rc, 0);
410   rc = iwkv_get(db1, &key, &val);
411   CU_ASSERT_NSTRING_EQUAL(key.data, "foo", key.size);
412   CU_ASSERT_NSTRING_EQUAL(val.data, "bar", val.size);
413   iwkv_kv_dispose(0, &val);
414 
415   logstage(f, "put foo:bar", db1);
416 
417   // remove key/value
418   rc = iwkv_del(db1, &key, 0);
419   CU_ASSERT_EQUAL_FATAL(rc, 0);
420   rc = iwkv_get(db1, &key, &val);
421   CU_ASSERT_EQUAL_FATAL(rc, IWKV_ERROR_NOTFOUND);
422 
423   logstage(f, "remove foo:bar", db1);
424 
425   rc = iwkv_close(&iwkv);
426   CU_ASSERT_EQUAL_FATAL(rc, 0);
427 
428   rc = iwkv_open(&opts, &iwkv);
429   CU_ASSERT_EQUAL_FATAL(rc, 0);
430   rc = iwkv_db(iwkv, 1, 0, &db1);
431   CU_ASSERT_EQUAL_FATAL(rc, 0);
432   rc = iwkv_get(db1, &key, &val);
433   CU_ASSERT_EQUAL_FATAL(rc, IWKV_ERROR_NOTFOUND);
434 
435   // iwkv_next_level = 0;
436 
437   for (int i = 0; i < 127 * 2; i += 2) {
438     snprintf(kbuf, KBUFSZ, "%03dkkk", i);
439     snprintf(vbuf, VBUFSZ, "%03dval", i);
440     key.data = kbuf;
441     key.size = strlen(key.data);
442     val.data = vbuf;
443     val.size = strlen(val.data);
444     rc = iwkv_put(db1, &key, &val, 0);
445     CU_ASSERT_EQUAL_FATAL(rc, 0);
446   }
447 
448   logstage(f, "fill up first block", db1);
449 
450   // iwkv_next_level = 0;
451   for (int i = 0; i < 127 * 2; i += 2) {
452     snprintf(kbuf, KBUFSZ, "%03dkkk", i);
453     snprintf(vbuf, VBUFSZ, "%03dval", i);
454     key.data = kbuf;
455     key.size = strlen(key.data);
456     rc = iwkv_get(db1, &key, &val);
457     CU_ASSERT_EQUAL_FATAL(rc, 0);
458     CU_ASSERT_EQUAL_FATAL(strncmp(val.data, vbuf, val.size), 0);
459     iwkv_kv_dispose(0, &val);
460   }
461 
462   for (int i = 1; i < 127 * 2; i += 2) {
463     snprintf(kbuf, KBUFSZ, "%03dkkk", i);
464     snprintf(vbuf, VBUFSZ, "%03dval", i);
465     key.data = kbuf;
466     key.size = strlen(key.data);
467     val.data = vbuf;
468     val.size = strlen(val.data);
469     //logstage(stderr, "!!!!!!", db1);
470     rc = iwkv_put(db1, &key, &val, 0);
471     CU_ASSERT_EQUAL_FATAL(rc, 0);
472     //logstage(stderr, "??????", db1);
473   }
474 
475   logstage(f, "fill up second block", db1);
476 
477   // Check basic cursor operations
478   IWKV_cursor cur1;
479 
480   rc = iwkv_cursor_open(db1, &cur1, IWKV_CURSOR_BEFORE_FIRST, 0);
481   CU_ASSERT_EQUAL_FATAL(rc, 0);
482   rc = iwkv_cursor_to(cur1, IWKV_CURSOR_PREV);
483   CU_ASSERT_EQUAL(rc, IWKV_ERROR_NOTFOUND);
484   rc = iwkv_cursor_close(&cur1);
485   CU_ASSERT_EQUAL_FATAL(rc, 0);
486 
487   rc = iwkv_cursor_open(db1, &cur1, IWKV_CURSOR_AFTER_LAST, 0);
488   CU_ASSERT_EQUAL_FATAL(rc, 0);
489   rc = iwkv_cursor_get(cur1, &key, &val);
490   CU_ASSERT_EQUAL(rc, IWKV_ERROR_NOTFOUND);
491   rc = iwkv_cursor_to(cur1, IWKV_CURSOR_NEXT);
492   CU_ASSERT_EQUAL(rc, IWKV_ERROR_NOTFOUND);
493   rc = iwkv_cursor_close(&cur1);
494   CU_ASSERT_EQUAL_FATAL(rc, 0);
495 
496   rc = iwkv_cursor_open(db1, &cur1, IWKV_CURSOR_AFTER_LAST, 0);
497   CU_ASSERT_EQUAL_FATAL(rc, 0);
498 
499   rc = iwkv_cursor_to(cur1, IWKV_CURSOR_PREV);
500   CU_ASSERT_EQUAL_FATAL(rc, 0);
501 
502   int i = 0;
503   do {
504     IWKV_val key;
505     IWKV_val val;
506     iwrc rc2 = iwkv_cursor_get(cur1, &key, &val);
507     CU_ASSERT_EQUAL_FATAL(rc2, 0);
508     snprintf(kbuf, KBUFSZ, "%03dkkk", i);
509     snprintf(vbuf, VBUFSZ, "%03dval", i);
510     CU_ASSERT_EQUAL(strncmp(key.data, kbuf, key.size), 0);
511     CU_ASSERT_EQUAL(strncmp(val.data, vbuf, val.size), 0);
512     iwkv_kv_dispose(&key, &val);
513     if (i == 2) {
514       rc2 = iwkv_cursor_to(cur1, IWKV_CURSOR_PREV);
515       CU_ASSERT_EQUAL_FATAL(rc2, 0);
516       rc2 = iwkv_cursor_get(cur1, &key, &val);
517       CU_ASSERT_EQUAL_FATAL(rc2, 0);
518       snprintf(kbuf, KBUFSZ, "%03dkkk", i + 1);
519       snprintf(vbuf, VBUFSZ, "%03dval", i + 1);
520       CU_ASSERT_EQUAL(strncmp(key.data, kbuf, key.size), 0);
521       CU_ASSERT_EQUAL(strncmp(val.data, vbuf, val.size), 0);
522       rc2 = iwkv_cursor_to(cur1, IWKV_CURSOR_NEXT);
523       CU_ASSERT_EQUAL_FATAL(rc2, 0);
524       iwkv_kv_dispose(&key, &val);
525     }
526     ++i;
527   } while (!(rc = iwkv_cursor_to(cur1, IWKV_CURSOR_PREV)));
528   CU_ASSERT_EQUAL(rc, IWKV_ERROR_NOTFOUND);
529   rc = iwkv_cursor_close(&cur1);
530   CU_ASSERT_EQUAL_FATAL(rc, 0);
531 
532   --i;
533   rc = iwkv_cursor_open(db1, &cur1, IWKV_CURSOR_BEFORE_FIRST, 0);
534   while (!(rc = iwkv_cursor_to(cur1, IWKV_CURSOR_NEXT))) {
535     IWKV_val key;
536     IWKV_val val;
537     iwrc rc2 = iwkv_cursor_get(cur1, &key, &val);
538     CU_ASSERT_EQUAL_FATAL(rc2, 0);
539     snprintf(kbuf, KBUFSZ, "%03dkkk", i);
540     snprintf(vbuf, VBUFSZ, "%03dval", i);
541     --i;
542     CU_ASSERT_EQUAL(strncmp(key.data, kbuf, key.size), 0);
543     CU_ASSERT_EQUAL(strncmp(val.data, vbuf, val.size), 0);
544     iwkv_kv_dispose(&key, &val);
545   }
546   CU_ASSERT_EQUAL(rc, IWKV_ERROR_NOTFOUND);
547   rc = iwkv_cursor_close(&cur1);
548   CU_ASSERT_EQUAL_FATAL(rc, 0);
549 
550   // Set cursor to key
551   do {
552     IWKV_val key;
553     IWKV_val val;
554     snprintf(kbuf, KBUFSZ, "%03dkkk", 30);
555     snprintf(vbuf, VBUFSZ, "%03dval", 30);
556     key.data = kbuf;
557     key.size = strlen(kbuf);
558     rc = iwkv_cursor_open(db1, &cur1, IWKV_CURSOR_EQ, &key);
559     CU_ASSERT_EQUAL_FATAL(rc, 0);
560     iwrc rc2 = iwkv_cursor_get(cur1, &key, &val);
561     CU_ASSERT_EQUAL_FATAL(rc2, 0);
562     CU_ASSERT_EQUAL(strncmp(key.data, kbuf, key.size), 0);
563     CU_ASSERT_EQUAL(strncmp(val.data, vbuf, val.size), 0);
564     iwkv_kv_dispose(&key, &val);
565 
566     // Move to GE 000
567     snprintf(kbuf, KBUFSZ, "%03d", 0);
568     snprintf(vbuf, VBUFSZ, "%03dval", 0);
569     key.data = kbuf;
570     key.size = strlen(kbuf);
571     rc2 = iwkv_cursor_to_key(cur1, IWKV_CURSOR_GE, &key);
572     if (rc2) {
573       iwlog_ecode_error3(rc2);
574     }
575     CU_ASSERT_EQUAL_FATAL(rc2, 0);
576     rc2 = iwkv_cursor_get(cur1, &key, &val);
577     CU_ASSERT_EQUAL_FATAL(rc2, 0);
578     snprintf(kbuf, KBUFSZ, "%03dkkk", 0);
579     snprintf(vbuf, VBUFSZ, "%03dval", 0);
580     CU_ASSERT_EQUAL(strncmp(key.data, kbuf, key.size), 0);
581     CU_ASSERT_EQUAL(strncmp(val.data, vbuf, val.size), 0);
582     iwkv_kv_dispose(&key, &val);
583 
584     // Move to EQ 000
585     snprintf(kbuf, KBUFSZ, "%03d", 0);
586     snprintf(vbuf, VBUFSZ, "%03dval", 0);
587     key.data = kbuf;
588     key.size = strlen(kbuf);
589     rc2 = iwkv_cursor_to_key(cur1, IWKV_CURSOR_EQ, &key);
590     CU_ASSERT_EQUAL(rc2, IWKV_ERROR_NOTFOUND);
591 
592     rc = iwkv_cursor_close(&cur1);
593     CU_ASSERT_EQUAL_FATAL(rc, 0);
594   } while (0);
595 
596   rc = iwkv_close(&iwkv);
597   CU_ASSERT_EQUAL_FATAL(rc, 0);
598 
599   rc = iwkv_open(&opts, &iwkv);
600   CU_ASSERT_EQUAL_FATAL(rc, 0);
601   rc = iwkv_db(iwkv, 1, 0, &db1);
602   CU_ASSERT_EQUAL_FATAL(rc, 0);
603 
604   logstage(f, "state after reopen", db1);
605 
606   // Put a big key
607   snprintf(kbuf, KBUFSZ, "abracadabrabracadabrabracadabrabracadabrabracadabrabracadabrabracadabr1");
608   key.size = strlen(kbuf);
609   snprintf(vbuf, VBUFSZ, "vabracadabrabracadabrabracadabrabracadabrabracadabrabracadabrabracadabr");
610   val.size = strlen(vbuf);
611   rc = iwkv_db(iwkv, 1, 0, &db1);
612   CU_ASSERT_EQUAL_FATAL(rc, 0);
613   rc = iwkv_put(db1, &key, &val, 0);
614   CU_ASSERT_EQUAL_FATAL(rc, 0);
615   rc = iwkv_get(db1, &key, &val);
616   CU_ASSERT_EQUAL_FATAL(rc, 0);
617   CU_ASSERT_EQUAL_FATAL(strncmp(val.data, vbuf, val.size), 0);
618   iwkv_kv_dispose(0, &val);
619 
620   logstage(f, "a big key", db1);
621 
622   // 061kkk:061val
623   // Set value with cursor
624   snprintf(kbuf, KBUFSZ, "%03dkkk", 61);
625   snprintf(vbuf, VBUFSZ, "%03dval2", 61);
626   key.data = kbuf;
627   key.size = strlen(kbuf);
628   val.data = vbuf;
629   val.size = strlen(vbuf);
630 
631   // Cursor set
632   rc = iwkv_cursor_open(db1, &cur1, IWKV_CURSOR_EQ, &key);
633   CU_ASSERT_EQUAL_FATAL(rc, 0);
634   rc = iwkv_cursor_set(cur1, &val, 0);
635   CU_ASSERT_EQUAL_FATAL(rc, 0);
636   key.data = 0;
637   val.data = 0;
638   rc = iwkv_cursor_get(cur1, &key, &val);
639   CU_ASSERT_EQUAL_FATAL(rc, 0);
640   CU_ASSERT_EQUAL(strncmp(key.data, kbuf, key.size), 0);
641   CU_ASSERT_EQUAL(strncmp(val.data, vbuf, val.size), 0);
642   iwkv_kv_dispose(&key, &val);
643   rc = iwkv_cursor_close(&cur1);
644   CU_ASSERT_EQUAL_FATAL(rc, 0);
645 
646   // Set in write mode
647   snprintf(kbuf, KBUFSZ, "%03dkkk", 61);
648   snprintf(vbuf, VBUFSZ, "%03dval3", 61);
649   key.data = kbuf;
650   key.size = strlen(kbuf);
651   val.data = vbuf;
652   val.size = strlen(vbuf);
653   rc = iwkv_cursor_open(db1, &cur1, IWKV_CURSOR_EQ, &key);
654   CU_ASSERT_EQUAL_FATAL(rc, 0);
655   rc = iwkv_cursor_set(cur1, &val, 0);
656   CU_ASSERT_EQUAL_FATAL(rc, 0);
657   key.data = 0;
658   val.data = 0;
659   rc = iwkv_cursor_get(cur1, &key, &val);
660   CU_ASSERT_EQUAL_FATAL(rc, 0);
661   CU_ASSERT_EQUAL(strncmp(key.data, kbuf, key.size), 0);
662   CU_ASSERT_EQUAL(strncmp(val.data, vbuf, val.size), 0);
663   iwkv_kv_dispose(&key, &val);
664   rc = iwkv_cursor_close(&cur1);
665   CU_ASSERT_EQUAL_FATAL(rc, 0);
666 
667   rc = iwkv_close(&iwkv);
668   CU_ASSERT_EQUAL_FATAL(rc, 0);
669 
670   // Compare logs with referenced
671 #ifndef _WIN32
672   FILE *r = fmt_version > 1 ? fopen("iwkv_test1_1_v2.ref", "r+") : fopen("iwkv_test1_1.ref", "r+");
673 #else
674   FILE *r = fmt_version > 1 ? fopen("iwkv_test1_1w_v2.ref", "r+") : fopen("iwkv_test1_1w.ref", "r+");
675 #endif
676   CU_ASSERT_PTR_NOT_NULL_FATAL(r);
677   int rci = cmp_files(r, f);
678   CU_ASSERT_EQUAL_FATAL(rci, 0);
679   fclose(r);
680   fclose(f);
681 }
682 
iwkv_test1_v1()683 static void iwkv_test1_v1() {
684   iwkv_test1_impl(1);
685 }
686 
iwkv_test1_v2()687 static void iwkv_test1_v2() {
688   iwkv_test1_impl(2);
689 }
690 
iwkv_test8_impl(int fmt_version)691 static void iwkv_test8_impl(int fmt_version) {
692   IWKV_OPTS opts = {
693     .path        = "iwkv_test1_8.db",
694     .oflags      = IWKV_TRUNC,
695     .fmt_version = fmt_version
696   };
697   IWKV iwkv;
698   IWDB db1;
699   IWKV_cursor cur;
700   IWKV_val key;
701   IWKV_val val = {
702     .data = "foo",
703     .size = sizeof("foo") - 1
704   };
705   IWKV_val oval;
706   size_t ksz;
707   uint64_t llv = 1;
708   uint64_t llv2;
709 
710   iwrc rc = iwkv_open(&opts, &iwkv);
711   CU_ASSERT_EQUAL_FATAL(rc, 0);
712 
713   rc = iwkv_db(iwkv, 1, IWDB_VNUM64_KEYS, &db1);
714   CU_ASSERT_EQUAL_FATAL(rc, 0);
715 
716   key.data = &llv;
717   key.size = sizeof(llv);
718 
719   rc = iwkv_put(db1, &key, &val, 0);
720   CU_ASSERT_EQUAL_FATAL(rc, 0);
721 
722   rc = iwkv_get(db1, &key, &oval);
723   CU_ASSERT_EQUAL_FATAL(rc, 0);
724   iwkv_val_dispose(&oval);
725 
726   llv = 0xffffffffffffffe;
727   key.data = &llv;
728 
729   rc = iwkv_put(db1, &key, &val, 0);
730   CU_ASSERT_EQUAL_FATAL(rc, 0);
731 
732   rc = iwkv_get(db1, &key, &oval);
733   CU_ASSERT_EQUAL_FATAL(rc, 0);
734   iwkv_val_dispose(&oval);
735 
736   rc = iwkv_get_copy(db1, &key, &llv2, sizeof(llv2), &ksz);
737   CU_ASSERT_EQUAL_FATAL(rc, 0);
738 
739   rc = iwkv_cursor_open(db1, &cur, IWKV_CURSOR_EQ, &key);
740   CU_ASSERT_EQUAL_FATAL(rc, 0);
741 
742   llv = 0xffffffffffffffffULL;
743   rc = iwkv_put(db1, &key, &val, 0);
744   CU_ASSERT_EQUAL(rc, IW_ERROR_OVERFLOW);
745 
746 
747   llv = 0;
748   int64_t compound;
749   rc = iwkv_cursor_copy_key(cur, &llv, sizeof(llv), &ksz, &compound);
750   CU_ASSERT_EQUAL_FATAL(rc, 0);
751   CU_ASSERT_EQUAL(llv, 0xffffffffffffffe);
752 
753   llv = 0;
754   rc = iwkv_cursor_get(cur, &oval, 0);
755   CU_ASSERT_EQUAL_FATAL(rc, 0);
756   CU_ASSERT_EQUAL_FATAL(oval.size, sizeof(llv));
757   memcpy(&llv, oval.data, sizeof(llv));
758   CU_ASSERT_EQUAL(llv, 0xffffffffffffffe);
759   iwkv_val_dispose(&oval);
760 
761   rc = iwkv_cursor_to(cur, IWKV_CURSOR_NEXT);
762   CU_ASSERT_EQUAL_FATAL(rc, 0);
763 
764   llv = 0;
765   rc = iwkv_cursor_copy_key(cur, &llv, sizeof(llv), &ksz, &compound);
766   CU_ASSERT_EQUAL_FATAL(rc, 0);
767   CU_ASSERT_EQUAL(llv, 1);
768 
769   iwkv_cursor_close(&cur);
770 
771   rc = iwkv_close(&iwkv);
772   CU_ASSERT_EQUAL_FATAL(rc, 0);
773 }
774 
iwkv_test8_v1()775 static void iwkv_test8_v1() {
776   iwkv_test1_impl(1);
777 }
778 
iwkv_test8_v2()779 static void iwkv_test8_v2() {
780   iwkv_test1_impl(2);
781 }
782 
iwkv_test7_impl(int fmt_version)783 static void iwkv_test7_impl(int fmt_version) {
784   IWKV_OPTS opts = {
785     .path        = "iwkv_test1_7.db",
786     .oflags      = IWKV_TRUNC,
787     .fmt_version = fmt_version
788   };
789   IWKV iwkv;
790   IWDB db1;
791   IWKV_val key, val;
792   int64_t llv;
793   key.data = "foo";
794   key.size = strlen(key.data);
795 
796   iwrc rc = iwkv_open(&opts, &iwkv);
797   CU_ASSERT_EQUAL_FATAL(rc, 0);
798 
799   rc = iwkv_db(iwkv, 1, 0, &db1);
800   CU_ASSERT_EQUAL_FATAL(rc, 0);
801 
802   llv = 1;
803   val.data = &llv;
804   val.size = sizeof(llv);
805 
806   rc = iwkv_put(db1, &key, &val, IWKV_VAL_INCREMENT);
807   CU_ASSERT_EQUAL_FATAL(rc, 0);
808 
809   rc = iwkv_put(db1, &key, &val, IWKV_VAL_INCREMENT);
810   CU_ASSERT_EQUAL_FATAL(rc, 0);
811 
812   rc = iwkv_put(db1, &key, &val, IWKV_VAL_INCREMENT);
813   CU_ASSERT_EQUAL_FATAL(rc, 0);
814 
815   llv = 0;
816   val.data = 0;
817   val.size = 0;
818   rc = iwkv_get(db1, &key, &val);
819   CU_ASSERT_EQUAL_FATAL(rc, 0);
820   CU_ASSERT_EQUAL_FATAL(val.size, sizeof(llv));
821   memcpy(&llv, val.data, sizeof(llv));
822   llv = IW_ITOHLL(llv);
823   CU_ASSERT_EQUAL(llv, 3);
824   iwkv_val_dispose(&val);
825 
826   rc = iwkv_close(&iwkv);
827   CU_ASSERT_EQUAL_FATAL(rc, 0);
828 }
829 
iwkv_test7_v1()830 static void iwkv_test7_v1() {
831   iwkv_test7_impl(1);
832 }
833 
iwkv_test7_v2()834 static void iwkv_test7_v2() {
835   iwkv_test7_impl(2);
836 }
837 
iwkv_test6_impl(int fmt_version)838 static void iwkv_test6_impl(int fmt_version) {
839   IWKV_OPTS opts = {
840     .path        = "iwkv_test1_6.db",
841     .oflags      = IWKV_TRUNC,
842     .fmt_version = fmt_version
843   };
844   const int vbsiz = 1000 * 1000;
845   // Test open/close
846   char kbuf[100];
847   char *vbuf = malloc(vbsiz);
848   IWKV iwkv;
849   IWDB db1;
850   IWKV_val key, val;
851 
852   iwrc rc = iwkv_open(&opts, &iwkv);
853   CU_ASSERT_EQUAL_FATAL(rc, 0);
854 
855   rc = iwkv_db(iwkv, 1, 0, &db1);
856   CU_ASSERT_EQUAL_FATAL(rc, 0);
857   key.data = kbuf;
858   val.data = vbuf;
859   val.size = vbsiz;
860   for (int i = 0; i < 20; ++i) {
861     memset(vbuf, ' ' + i + 1, vbsiz);
862     snprintf(kbuf, sizeof(kbuf), "%016d", i);
863     key.size = strlen(kbuf);
864     rc = iwkv_put(db1, &key, &val, 0);
865     if (rc) {
866       iwlog_ecode_error3(rc);
867     }
868     CU_ASSERT_EQUAL_FATAL(rc, 0);
869   }
870   rc = iwkv_close(&iwkv);
871   CU_ASSERT_EQUAL_FATAL(rc, 0);
872   free(vbuf);
873 }
874 
iwkv_test6_v1()875 static void iwkv_test6_v1() {
876   iwkv_test6_impl(1);
877 }
878 
iwkv_test6_v2()879 static void iwkv_test6_v2() {
880   iwkv_test6_impl(2);
881 }
882 
iwkv_test9(void)883 static void iwkv_test9(void) {
884   IWKV_OPTS opts = {
885     .path = "garbage.data",
886   };
887   // Test open/close
888   IWKV iwkv;
889   iwrc rc = iwkv_open(&opts, &iwkv);
890   CU_ASSERT_EQUAL(rc, IWFS_ERROR_INVALID_FILEMETA);
891   rc = iwkv_close(&iwkv);
892   CU_ASSERT_EQUAL(rc, IW_ERROR_INVALID_STATE);
893 }
894 
main()895 int main() {
896   CU_pSuite pSuite = NULL;
897 
898   /* Initialize the CUnit test registry */
899   if (CUE_SUCCESS != CU_initialize_registry()) {
900     return CU_get_error();
901   }
902 
903   /* Add a suite to the registry */
904   pSuite = CU_add_suite("iwkv_test1", init_suite, clean_suite);
905 
906   if (NULL == pSuite) {
907     CU_cleanup_registry();
908     return CU_get_error();
909   }
910 
911   /* Add the tests to the suite */
912   if (  (NULL == CU_add_test(pSuite, "iwkv_test1_v1", iwkv_test1_v1))
913      || (NULL == CU_add_test(pSuite, "iwkv_test1_v2", iwkv_test1_v2))
914      || (NULL == CU_add_test(pSuite, "iwkv_test2_v1", iwkv_test2_v1))
915      || (NULL == CU_add_test(pSuite, "iwkv_test2_v2", iwkv_test2_v2))
916      || (NULL == CU_add_test(pSuite, "iwkv_test3_v1", iwkv_test3_v1))
917      || (NULL == CU_add_test(pSuite, "iwkv_test3_v2", iwkv_test3_v2)) ||
918 
919         //-    (NULL == CU_add_test(pSuite, "iwkv_test4", iwkv_test4)) ||
920         //-    (NULL == CU_add_test(pSuite, "iwkv_test5", iwkv_test5)) ||
921 
922         (NULL == CU_add_test(pSuite, "iwkv_test6_v1", iwkv_test6_v1))
923      || (NULL == CU_add_test(pSuite, "iwkv_test6_v2", iwkv_test6_v2))
924      || (NULL == CU_add_test(pSuite, "iwkv_test7_v1", iwkv_test7_v1))
925      || (NULL == CU_add_test(pSuite, "iwkv_test7_v2", iwkv_test7_v2))
926      || (NULL == CU_add_test(pSuite, "iwkv_test8_v1", iwkv_test8_v1))
927      || (NULL == CU_add_test(pSuite, "iwkv_test8_v2", iwkv_test8_v2))
928      || (NULL == CU_add_test(pSuite, "iwkv_test9", iwkv_test9))) {
929     CU_cleanup_registry();
930     return CU_get_error();
931   }
932 
933   /* Run all tests using the CUnit Basic interface */
934   CU_basic_set_mode(CU_BRM_VERBOSE);
935   CU_basic_run_tests();
936   int ret = CU_get_error() || CU_get_number_of_failures();
937   CU_cleanup_registry();
938   return ret;
939 }
940