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