static void test9() { struct KeyVal *kv; _check_err(KeyVal_new(&kv), "KeyVal_new"); _check_err(KeyVal_setValue(kv, "k1", "k3"), "KeyVal_setValue"); // sets k1 to k3 _check_err(KeyVal_setValue(kv, "k2::k3", "${k1}"), "KeyVal_setValue"); // sets k2::k3 to "k3" _check_err(KeyVal_setValue(kv, "k4", "${k2::${k1}}"), "KeyVal_setValue"); // sets k4 to "k3" // baseline writing: _check_err(KeyVal_save(kv, OUT, 0, 0), "KeyVal_save"); ok(_check_output("`k1` = `k3`\n`k2::k3` = `${k1}`\n`k4` = `${k2::${k1}}`\n") == 0, "9a. saving with interp=0, align=0"); // writing with just interp: _check_err(KeyVal_save(kv, OUT, 1, 0), "KeyVal_save"); ok(_check_output("`k1` = `k3`\n`k2::k3` = `k3`\n`k4` = `k3`\n") == 0, "9b. saving with interp=1, align=0"); // writing with just align: _check_err(KeyVal_save(kv, OUT, 0, 1), "KeyVal_save"); ok(_check_output("`k1` = `k3`\n`k2::k3` = `${k1}`\n`k4` = `${k2::${k1}}`\n") == 0, "9c. saving with interp=0, align=1"); // writing with both interp and align: _check_err(KeyVal_save(kv, OUT, 1, 1), "KeyVal_save"); ok(_check_output("`k1` = `k3`\n`k2::k3` = `k3`\n`k4` = `k3`\n") == 0, "9d. saving with interp=1, align=1"); _check_err(KeyVal_delete(kv), "KeyVal_delete"); }
int main(int ac, char* av[]) { GError* err = NULL; char* uri = ac == 2 ? av[1] : "https://localhost:4444/RPC2"; xr_debug_enabled = XR_DEBUG_CALL; xr_client_conn* conn = xr_client_new(&err); if (_check_err(&err)) goto err; xr_client_open(conn, uri, &err); if (_check_err(&err)) goto err; // start job gint job_id = TTest2_startQuery(conn, "http://localhost/slow.php", &err); if (_check_err(&err)) goto err; // poll job result while (TRUE) { TQueryResult* result = TTest2_completeQuery(conn, job_id, &err); if (err && err->code != T_XMLRPC_ERROR_TEST2_AGAIN) { _check_err(&err); goto err; } if (result) { g_print("Job done, result:\n%s\n", result->response); TQueryResult_free(result); break; } else g_usleep(1000 * 1000); g_clear_error(&err); } xr_client_free(conn); xr_fini(); return 0; err: xr_client_free(conn); xr_fini(); return 1; }
static void test1() { struct KeyVal *kv; _check_err(KeyVal_new(&kv), "KeyVal_new"); // 1a: missing file remove(IN); _check_load_return(kv, 2, "1a. detects missing input file"); // 1b: file with complete crap in it _set_input("this file has complete crap in it\n"); _check_load_return(kv, 1, "1b. detects complete crap"); // 1c: file with EOF in key _set_input("`key"); _check_load_return(kv, 1, "1c. detects EOF in key"); // 1d/1e: file with missing "=" or "remove" _set_input("`key`\n"); _check_load_return(kv, 1, "1d. detects '\\n' instead of '=' or 'remove'"); _set_input("`key`"); _check_load_return(kv, 1, "1e. detects EOF instead of '=' or 'remove'"); // 1f: file with "foo" instead of "=" or "remove" _set_input("`key` foo"); _check_load_return(kv, 1, "1f. detects crap instead of '=' or 'remove'"); // 1g/1h: file with missing value _set_input("`key` =\n"); _check_load_return(kv, 1, "1g. detects '\\n' instead of value"); _set_input("`key` ="); _check_load_return(kv, 1, "1h. detects EOF instead of value"); // 1i: file with EOF in value _set_input("`key` = `val"); _check_load_return(kv, 1, "1i. detects EOF in value (missing close-quote)"); // 1j: file with comment after value (sorry, not allowed!) _set_input("`key` = `val` #moo!"); _check_load_return(kv, 1, "1j. detects comment after value"); _check_err(KeyVal_delete(kv), "KeyVal_delete"); }
static void test5() { struct KeyVal *kv; _check_err(KeyVal_new(&kv), "KeyVal_new"); // 5a: key and val with escaped quote. Input should look like this: // `\`key\\` = `\\val\`` // `key\`\`key` = `val\\\\val` const char *TEXT = "`\\`key\\\\` = `\\\\val\\``\n`key\\`\\`key` = `val\\\\\\\\val`\n"; _set_input(TEXT); if (!ok(KeyVal_load(kv, IN) == 0, "5a. reads escapes ok")) return; // 5b. escapes on the outside of key: char *value; _check_err(KeyVal_getValue(&value, kv, "`key\\", 0), "KeyVal_getValue"); if (ok(value != 0, "5b. key with escapes at start and end")) { // 5c. escapes on the outsides of value: ok(strcmp(value, "\\val`") == 0, "5c. value with escapes at start and end"); } // 5d. (consecutive) escapes in the middle of key: _check_err(KeyVal_getValue(&value, kv, "key``key", 0), "KeyVal_getValue"); if (ok(value != 0, "5d. key with consecutive escapes in middle")) { // 5e. (consecutive) escapes in the middle of value: ok(strcmp(value, "val\\\\val") == 0, "5e. value with consecutive escapes in middle"); } // 5f. write out this nastiness: _check_err(KeyVal_save(kv, OUT, 0, 0), "KeyVal_save"); ok(_check_output(TEXT) == 0, "5f. escapes write out correctly"); _check_err(KeyVal_delete(kv), "KeyVal_delete"); }
static void test2() { struct KeyVal *kv; _check_err(KeyVal_new(&kv), "KeyVal_new"); // 2a: file with nothing in it FILE *fh = fopen(IN, "w"); fclose(fh); _check_load_return(kv, 0, "2a. empty input file"); // 2b: file with only whitespace _set_input(" \t \t \n\t\t \n\n "); // also tests missing \n at EOF _check_load_return(kv, 0, "2b. whitespace-only input file"); // 2c: file with only comments _set_input("# nothing\n# at all!\n"); _check_load_return(kv, 0, "2c. comment-only input file"); // 2d: save it out; should get nothing _check_err(KeyVal_save(kv, OUT, 0, 0), "KeyVal_save"); ok(_check_output("") == 0, "2d. writing out empty input generates empty output"); _check_err(KeyVal_delete(kv), "KeyVal_delete"); }
static void test8() { struct KeyVal *kv; _check_err(KeyVal_new(&kv), "KeyVal_new"); _check_err(KeyVal_setValue(kv, "k1", "2"), "KeyVal_setValue"); _check_err(KeyVal_setValue(kv, "k2", "asdf${k1}zxcv"), "KeyVal_setValue"); // in middle _check_err(KeyVal_setValue(kv, "k3", "${k1}zxcv"), "KeyVal_setValue"); // at beginning _check_err(KeyVal_setValue(kv, "k4", "asdf${k1}"), "KeyVal_setValue"); // at end _check_err(KeyVal_setValue(kv, "k5", "a${k1}b${k1}${k1}c"), "KeyVal_setValue"); // multiple values _check_err(KeyVal_setValue(kv, "k6", "${k${k1}}"), "KeyVal_setValue"); // embedded variables _check_err(KeyVal_setValue(kv, "k7", "}${"), "KeyVal_setValue"); // weird string 1 _check_err(KeyVal_setValue(kv, "k8", "${}"), "KeyVal_setValue"); // weird string 2 _check_err(KeyVal_setValue(kv, "k9", "${k10}"), "KeyVal_setValue"); // mutually recursive variables _check_err(KeyVal_setValue(kv, "k10", "${k9}"), "KeyVal_setValue"); // mutually recursive variables char *value; _check_err(KeyVal_getValue(&value, kv, "k2", 1), "KeyVal_getValue"); if (!ok(strcmp(value, "asdf2zxcv") == 0, "8a. variable in middle of string")) { printf(" - got '%s' instead of 'asdf2zxcv'\n", value); } free(value); _check_err(KeyVal_getValue(&value, kv, "k3", 1), "KeyVal_getValue"); ok(strcmp(value, "2zxcv") == 0, "8b. variable at beginning of string"); free(value); _check_err(KeyVal_getValue(&value, kv, "k4", 1), "KeyVal_getValue"); ok(strcmp(value, "asdf2") == 0, "8c. variable at end of string"); free(value); _check_err(KeyVal_getValue(&value, kv, "k5", 1), "KeyVal_getValue"); ok(strcmp(value, "a2b22c") == 0, "8d. multiple variables in the string"); free(value); _check_err(KeyVal_getValue(&value, kv, "k6", 1), "KeyVal_getValue"); ok(strcmp(value, "asdf2zxcv") == 0, "8e. embedded variables"); free(value); _check_err(KeyVal_getValue(&value, kv, "k7", 1), "KeyVal_getValue"); ok(strcmp(value, "}${") == 0, "8f. weird initial closing brace"); free(value); _check_err(KeyVal_getValue(&value, kv, "k8", 1), "KeyVal_getValue"); ok(strcmp(value, "${}") == 0, "8g. empty variable name"); free(value); unsigned char getvalue_res = KeyVal_getValue(&value, kv, "k9", 1); ok(getvalue_res == 2, "8h. recursive variables detected"); _check_err(KeyVal_delete(kv), "KeyVal_delete"); }
static void test7() { struct KeyVal *kv; _check_err(KeyVal_new(&kv), "KeyVal_new"); // empty arrays: unsigned long index; _check_err(KeyVal_findIdealIndex(&index, kv, "a"), "KeyVal_findIdealIndex"); ok(index == 0, "7a. findIdealIndex ok on empty array"); ok(KeyVal_findIndex(&index, kv, "a") == 2, "7b. findIndex ok on empty array"); // one element: _check_err(KeyVal_setValue(kv, "2", "asdf"), "KeyVal_setValue"); // searching something that should go in front: _check_err(KeyVal_findIdealIndex(&index, kv, "1"), "KeyVal_findIdealIndex"); ok(index == 0, "7d. findIdealIndex-1 ok on array1"); ok(KeyVal_findIndex(&index, kv, "1") == 2, "7e. findIndex-1 ok on array1"); // searching the one thing that's in it: _check_err(KeyVal_findIdealIndex(&index, kv, "2"), "KeyVal_findIdealIndex"); ok(index == 0, "7g. findIdealIndex-2 ok on array1"); _check_err(KeyVal_findIndex(&index, kv, "2"), "KeyVal_findIndex"); ok(index == 0, "7h. findIndex-2 ok on array1"); // searching something that should go at the end: _check_err(KeyVal_findIdealIndex(&index, kv, "3"), "KeyVal_findIdealIndex"); ok(index == 1, "7j. findIdealIndex-3 ok on array1"); ok(KeyVal_findIndex(&index, kv, "3") == 2, "7k. findIndex-3 ok on array1"); // two elements: _check_err(KeyVal_setValue(kv, "4", "asdf"), "KeyVal_setValue"); // searching something that should go in front: _check_err(KeyVal_findIdealIndex(&index, kv, "1"), "KeyVal_findIdealIndex"); ok(index == 0, "7m. findIdealIndex-1 ok on array2"); ok(KeyVal_findIndex(&index, kv, "1") == 2, "7n. findIndex-1 ok on array2"); // searching the first thing that's in it: _check_err(KeyVal_findIdealIndex(&index, kv, "2"), "KeyVal_findIdealIndex"); ok(index == 0, "7p. findIdealIndex-2 ok on array2"); _check_err(KeyVal_findIndex(&index, kv, "2"), "KeyVal_findIndex"); ok(index == 0, "7q. findIndex-2 ok on array2"); // searching something that should go in the middle: _check_err(KeyVal_findIdealIndex(&index, kv, "3"), "KeyVal_findIdealIndex"); ok(index == 1, "7s. findIdealIndex-3 ok on array2"); ok(KeyVal_findIndex(&index, kv, "3") == 2, "7t. findIndex-3 ok on array2"); // searching the second thing that's in it: _check_err(KeyVal_findIdealIndex(&index, kv, "4"), "KeyVal_findIdealIndex"); ok(index == 1, "7v. findIdealIndex-4 ok on array2"); _check_err(KeyVal_findIndex(&index, kv, "4"), "KeyVal_findIndex"); ok(index == 1, "7w. findIndex-4 ok on array2"); // searching something that should go at the end: _check_err(KeyVal_findIdealIndex(&index, kv, "5"), "KeyVal_findIdealIndex"); ok(index == 2, "7y. findIdealIndex-5 ok on array2"); ok(KeyVal_findIndex(&index, kv, "5") == 2, "7z. findIndex-5 ok on array2"); // three elements: _check_err(KeyVal_setValue(kv, "6", "asdf"), "KeyVal_setValue"); // searching something that should go in front: _check_err(KeyVal_findIdealIndex(&index, kv, "1"), "KeyVal_findIdealIndex"); ok(index == 0, "7ab. findIdealIndex-1 ok on array3"); ok(KeyVal_findIndex(&index, kv, "1") == 2, "7ac. findIndex-1 ok on array3"); // searching the first thing that's in it: _check_err(KeyVal_findIdealIndex(&index, kv, "2"), "KeyVal_findIdealIndex"); ok(index == 0, "7ae. findIdealIndex-2 ok on array3"); _check_err(KeyVal_findIndex(&index, kv, "2"), "KeyVal_findIndex"); ok(index == 0, "7af. findIndex-2 ok on array3"); // searching something that should go in the middle: _check_err(KeyVal_findIdealIndex(&index, kv, "3"), "KeyVal_findIdealIndex"); ok(index == 1, "7ah. findIdealIndex-3 ok on array3"); ok(KeyVal_findIndex(&index, kv, "3") == 2, "7ai. findIndex-3 ok on array3"); // searching the second thing that's in it: _check_err(KeyVal_findIdealIndex(&index, kv, "4"), "KeyVal_findIdealIndex"); ok(index == 1, "7ak. findIdealIndex-4 ok on array3"); _check_err(KeyVal_findIndex(&index, kv, "4"), "KeyVal_findIndex"); ok(index == 1, "7al. findIndex-4 ok on array3"); // searching something that should go in the middle: _check_err(KeyVal_findIdealIndex(&index, kv, "5"), "KeyVal_findIdealIndex"); ok(index == 2, "7an. findIdealIndex-5 ok on array3"); ok(KeyVal_findIndex(&index, kv, "5") == 2, "7ao. findIndex-5 ok on array3"); // searching the second thing that's in it: _check_err(KeyVal_findIdealIndex(&index, kv, "6"), "KeyVal_findIdealIndex"); ok(index == 2, "7aq. findIdealIndex-6 ok on array3"); _check_err(KeyVal_findIndex(&index, kv, "6"), "KeyVal_findIndex"); ok(index == 2, "7ar. findIndex-6 ok on array3"); // searching something that should go at the end: _check_err(KeyVal_findIdealIndex(&index, kv, "7"), "KeyVal_findIdealIndex"); ok(index == 3, "7at. findIdealIndex-7 ok on array3"); ok(KeyVal_findIndex(&index, kv, "7") == 2, "7au. findIndex-7 ok on array3"); // we'll assume all larger cases successfully degrade into one of the // above. Yay, partition testing! _check_err(KeyVal_delete(kv), "KeyVal_delete"); }
static void test6() { // create million-line input: // - first key is alphabetic // - optional second key is numeric // - third key is also numeric because I ran out of ideas // - value is just the key backwards FILE *fh = fopen(IN, "w"); if (!fh) { printf("[ERROR] cannot write to %s!\n", IN); ++test_fails; return; } char key[1024]; char val[1024]; char tmp[16]; // this is a surprisingly effective speedup // foreach first-key in [a..z]_level: for (char a = 'a'; a <= 'z'; ++a) { //for (char a = 'a'; a <= 'a'; ++a) { sprintf(tmp, "%c%s", a, "_level"); // foreach second-key in none, 1..9: for (int b = 10; b >= 0; --b) { // out of order to test sorting if (!b) { reverse(val, tmp); fprintf(fh, "`%s` = `%s`\n", tmp, val); continue; } // foreach third-key in none, 1..3847: (to make it ~million lines) for (int c = 0; c < 3847; ++c) { //for (int c = 0; c < 1; ++c) { if (!c) { sprintf(key, "%s::%d", tmp, b); } else { sprintf(key, "%s::%d::%d", tmp, b, c); } reverse(val, key); fprintf(fh, "`%s` = `%s`\n", key, val); } } } fclose(fh); struct KeyVal *kv; _check_err(KeyVal_new(&kv), "KeyVal_new"); // 6a: reads the huge input (update for later: may want to report load-time?) //printf("loading huge file..\n"); if (!ok(KeyVal_load(kv, IN) == 0, "6a. reads big input")) return; //printf("done!!\n"); // 6b: size is right unsigned long size; _check_err(KeyVal_size(&size, kv), "KeyVal_size"); if (!ok(size == 1000246, "6b. big input has 1,000,246 settings")) { printf(" -> thinks it has %lu settings\n", size); } char **keys; _check_err(KeyVal_getKeys(&keys, kv, "b_level"), "KeyVal_getKeys"); if (keys) { // count them; should be 11, which means it returns downstream sub-keys only once int num_keys = 0; for (char **ptr = keys; *ptr; ++ptr) { ++num_keys; } if (ok(num_keys == 10, "6c. number of keys under 'b_level' is exactly 10")) { // I guess make sure they are what I think they should be. Probably overkill: ok(strcmp(keys[0], "1") == 0, "6e. keys[0]=1"); ok(strcmp(keys[1], "10") == 0, "6f. keys[1]=10"); ok(strcmp(keys[2], "2") == 0, "6g. keys[2]=2"); ok(strcmp(keys[3], "3") == 0, "6h. keys[3]=3"); ok(strcmp(keys[4], "4") == 0, "6i. keys[4]=4"); ok(strcmp(keys[5], "5") == 0, "6j. keys[5]=5"); ok(strcmp(keys[6], "6") == 0, "6k. keys[6]=6"); ok(strcmp(keys[7], "7") == 0, "6l. keys[7]=7"); ok(strcmp(keys[8], "8") == 0, "6m. keys[8]=8"); ok(strcmp(keys[9], "9") == 0, "6n. keys[9]=9"); } for (char **ptr = keys; *ptr; ++ptr) { free(*ptr); } free(keys); } else { printf("[UNEXPECTED-3] getKeys should never return a null result\n"); } // check that getAllKeys at least doesn't do nothing: _check_err(KeyVal_getAllKeys(&keys, kv), "KeyVal_getAllKeys"); if (keys) { int count = 0; while (keys[count]) { free(keys[count]); ++count; } free(keys); if (!ok(count == 1000246, "6o. getAllKeys returns 1,000,246 keys")) printf(" -> thinks it has %d settings\n", count); } else { printf("[UNEXPECTED-4] getAllKeys should never return a null result\n"); } // random getValue, just 'cuz: char *value; _check_err(KeyVal_getValue(&value, kv, "o_level::3::1500", 0), "KeyVal_getValue"); if (ok(value != 0, "6p. random key in the middle exists")) { ok(strcmp(value, "0051::3::level_o") == 0, "6q. random key has the right value"); } // hasValue: unsigned char boolflag; _check_err(KeyVal_hasValue(&boolflag, kv, "c_level::2::42"), "KeyVal_hasValue"); ok(boolflag, "6q. hasValue on value"); _check_err(KeyVal_remove(kv, "b_level::1"), "KeyVal_remove"); // need a strict sub-key to test [6r] _check_err(KeyVal_hasValue(&boolflag, kv, "b_level::1"), "KeyVal_hasValue"); ok(!boolflag, "6r. hasValue on keys"); _check_err(KeyVal_hasValue(&boolflag, kv, "c_level::moo"), "KeyVal_hasValue"); ok(!boolflag, "6s. hasValue on nothing"); // hasKeys: _check_err(KeyVal_hasKeys(&boolflag, kv, "c_level::2::42"), "KeyVal_hasKeys"); ok(!boolflag, "6t. hasKeys on value"); _check_err(KeyVal_hasKeys(&boolflag, kv, "c_level::2"), "KeyVal_hasKeys"); ok(boolflag, "6u. hasKeys on keys"); _check_err(KeyVal_hasKeys(&boolflag, kv, "c_level::moo"), "KeyVal_hasKeys"); ok(!boolflag, "6v. hasKeys on nothing"); // exists:: _check_err(KeyVal_exists(&boolflag, kv, "c_level::2::42"), "KeyVal_exists"); ok(boolflag, "6w. exists on value"); _check_err(KeyVal_exists(&boolflag, kv, "c_level::2"), "KeyVal_exists"); ok(boolflag, "6x. exists on keys"); _check_err(KeyVal_exists(&boolflag, kv, "c_level::moo"), "KeyVal_exists"); ok(!boolflag, "6y. exists on nothing"); //KeyVal_save(kv, OUT, 0, 0); //DEBUG //printf("--saved to '%s'\n", OUT); _check_err(KeyVal_delete(kv), "KeyVal_delete"); }
static void test4() { struct KeyVal *kv; _check_err(KeyVal_new(&kv), "KeyVal_new"); // intentionally not in alphabetic order: _check_err(KeyVal_setValue(kv, "seagram's", "7"), "KeyVal_setValue"); _check_err(KeyVal_setValue(kv, "jack", "daniel's"), "KeyVal_setValue"); // 4a. size set from setValues: unsigned long size; _check_err(KeyVal_size(&size, kv), "KeyVal_size"); ok(size == 2, "4a. size=2"); // 4b: search for first existing: char *value; _check_err(KeyVal_getValue(&value, kv, "jack", 0), "KeyVal_getValue"); if (ok(value != 0, "4b. search for existing 'jack'")) { // 4c: has the right value: ok(strcmp(value, "daniel's") == 0, "4c. jack => daniel's"); } // 4d: search for non-existing key that would be in the middle of existing ones _check_err(KeyVal_getValue(&value, kv, "jim::beam", 0), "KeyVal_getValue"); ok(value == 0, "4d. checking for mid-value nonexistent key"); // 4e: search for last existing: _check_err(KeyVal_getValue(&value, kv, "seagram's", 0), "KeyVal_getValue"); if (ok(value != 0, "4e. search for existing 'seagram's'")) { // 4f: has the right value: ok(strcmp(value, "7") == 0, "4f. seagram's => 7"); } // 4g: save it out; should get two lines in order _check_err(KeyVal_save(kv, OUT, 0, 0), "KeyVal_save"); ok(_check_output("`jack` = `daniel's`\n`seagram's` = `7`\n") == 0, "4g. writes out correctly"); // 4h: remove one; should still have the other _check_err(KeyVal_remove(kv, "seagram's"), "KeyVal_remove"); _check_err(KeyVal_size(&size, kv), "KeyVal_size"); ok(size == 1, "4h. removing 'seagram's'"); _check_err(KeyVal_getValue(&value, kv, "jack", 0), "KeyVal_getValue"); // 4i: removing one didn't affect the other's value, either: if (ok(value != 0, "4i. 'jack' ok after removing seagram's")) { // 4j: has the right value: ok(strcmp(value, "daniel's") == 0, "4j. jack => daniel's, still"); } _check_err(KeyVal_delete(kv), "KeyVal_delete"); }
static void test3() { struct KeyVal *kv; _check_err(KeyVal_new(&kv), "KeyVal_new"); // 3a: unloaded kv should be empty: unsigned long size; _check_err(KeyVal_size(&size, kv), "KeyVal_size"); ok(size == 0, "3a. uninitialized KeyVal empty"); // 3b: single-element file _set_input("`key` = `val`\n"); // minimal typical input if (!ok(KeyVal_load(kv, IN) == 0, "3b. reads single-element input")) return; // 3c: size set from file input _check_err(KeyVal_size(&size, kv), "KeyVal_size"); ok(size == 1, "3c. size of single-element input is 1"); // 3d: search for element before it: char *value; _check_err(KeyVal_getValue(&value, kv, "asdf", 0), "KeyVal_getValue"); if (!ok(value == 0, "3d. search for nonexistent 'asdf'")) { printf(" - instead found '%s'!\n", value); } // 3e: search for element after it: _check_err(KeyVal_getValue(&value, kv, "zxcv", 0), "KeyVal_getValue"); ok(value == 0, "3e. search for nonexistent 'zxcv'"); // 3f: search for it itself: _check_err(KeyVal_getValue(&value, kv, "key", 0), "KeyVal_getValue"); if (ok(value != 0, "3f. search for existing 'key'")) { // 3g: has the right value: ok(strcmp(value, "val") == 0, "3g. 'key' has value 'val'"); } // 3h: search for subset key: _check_err(KeyVal_getValue(&value, kv, "ke", 0), "KeyVal_getValue"); if (!ok(value == 0, "3h. search for subset 'ke'")) { printf(" - instead found '%s'!\n", value); } // 3i: search for superset key: _check_err(KeyVal_getValue(&value, kv, "keysha", 0), "KeyVal_getValue"); ok(value == 0, "3i. search for superset 'keysha'"); // 3j: getKeys returns one thing char ** keys; _check_err(KeyVal_getKeys(&keys, kv, ""), "KeyVal_getKeys"); if (keys) { if (!ok(keys[0]!=0 && !strcmp(keys[0], "key") && keys[1]==0, "3j. getKeys returns ['key']")) { printf("keys returned:\n"); for (char **f = keys; *f; ++f) { printf(" '%s'\n", *f); } } for (char **f = keys; *f; ++f) { free(*f); } free(keys); } else { printf("[UNEXPECTED-1] getKeys should never return a null result"); } // 3k: hasValue should find it: unsigned char boolflag; _check_err(KeyVal_hasValue(&boolflag, kv, "key"), "KeyVal_hasValue"); ok(boolflag == 1, "3k. hasValue finds 'key'"); // 3l: hasKeys should not segfault on it: _check_err(KeyVal_hasKeys(&boolflag, kv, "key"), "KeyVal_hasKeys"); ok(boolflag == 0, "3l. hasKeys does not segfault on last element, and doesn't report 'key'"); // 3m: exists should also find it: _check_err(KeyVal_exists(&boolflag, kv, "key"), "KeyVal_exists"); ok(boolflag == 1, "3m. exists finds 'key'"); // 3n: save it out; should get single value _check_err(KeyVal_save(kv, OUT, 0, 0), "KeyVal_save"); ok(_check_output("`key` = `val`\n") == 0, "3n. writes out the single value"); // 3o: removing element before: _check_err(KeyVal_remove(kv, "asdf"), "KeyVal_remove"); _check_err(KeyVal_size(&size, kv), "KeyVal_size"); ok(size == 1, "3o. removing nonexistent 'asdf'"); // 3p: removing element after: _check_err(KeyVal_remove(kv, "zxcv"), "KeyVal_remove"); _check_err(KeyVal_size(&size, kv), "KeyVal_size"); ok(size == 1, "3p. removing nonexistent 'zxcv'"); // 3q: removing element: _check_err(KeyVal_remove(kv, "key"), "KeyVal_remove"); _check_err(KeyVal_size(&size, kv), "KeyVal_size"); ok(size == 0, "3q. removing 'key'"); // 3r: getKeys returns nothing _check_err(KeyVal_getKeys(&keys, kv, ""), "KeyVal_getKeys"); if (keys) { ok(keys[0] == 0, "3r: getKeys now returns ['']"); free(keys); } else { printf("[UNEXPECTED-2] getKeys should never return a null result"); } // 3s: save it out; should get nothing now _check_err(KeyVal_save(kv, OUT, 0, 0), "KeyVal_save"); ok(_check_output("") == 0, "3s. writes out empty file"); _check_err(KeyVal_delete(kv), "KeyVal_delete"); }