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