diff options
author | John Hawthorn <john.hawthorn@gmail.com> | 2017-04-03 19:03:47 -0700 |
---|---|---|
committer | John Hawthorn <john.hawthorn@gmail.com> | 2017-04-03 19:30:07 -0700 |
commit | a47b34dc0797af82947e4608f5b8690aff62ec60 (patch) | |
tree | f6594aada4b417cd7934a5d97ceaa51fd9fa3bd7 /test/test_properties.c | |
parent | dfe82eb18d19f7cde3c0f0099718af06c94c314c (diff) |
Add property based testing using thief
Diffstat (limited to 'test/test_properties.c')
-rw-r--r-- | test/test_properties.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/test/test_properties.c b/test/test_properties.c index e69de29..1fcdf80 100644 --- a/test/test_properties.c +++ b/test/test_properties.c @@ -0,0 +1,163 @@ +#define _DEFAULT_SOURCE +#include <string.h> + +#include "greatest/greatest.h" +#include "theft/theft.h" + +#include "match.h" + +static void *string_alloc_cb(struct theft *t, theft_hash seed, void *env) { + (void)env; + int limit = 128; + + size_t sz = (size_t)(seed % limit) + 1; + char *str = malloc(sz + 1); + if (str == NULL) { + return THEFT_ERROR; + } + + for (size_t i = 0; i < sz; i += sizeof(theft_hash)) { + theft_hash s = theft_random(t); + for (uint8_t b = 0; b < sizeof(theft_hash); b++) { + if (i + b >= sz) { + break; + } + str[i + b] = (uint8_t)(s >> (8 * b)) & 0xff; + } + } + str[sz] = 0; + + return str; +} + +static void string_free_cb(void *instance, void *env) { + free(instance); + (void)env; +} + +static void string_print_cb(FILE *f, void *instance, void *env) { + char *str = (char *)instance; + (void)env; + size_t size = strlen(str); + fprintf(f, "str[%zd]:\n ", size); + uint8_t bytes = 0; + for (size_t i = 0; i < size; i++) { + fprintf(f, "%02x", str[i]); + bytes++; + if (bytes == 16) { + fprintf(f, "\n "); + bytes = 0; + } + } + fprintf(f, "\n"); +} + +static uint64_t string_hash_cb(void *instance, void *env) { + char *str = (char *)instance; + int size = strlen(str); + (void)env; + return theft_hash_onepass(str, size); +} + +static void *string_shrink_cb(void *instance, uint32_t tactic, void *env) { + char *str = (char *)instance; + int n = strlen(str); + + if (tactic == 0) { /* first half */ + return strndup(str, n / 2); + } else if (tactic == 1) { /* second half */ + return strndup(str + (n / 2), n / 2); + } else { + return THEFT_NO_MORE_TACTICS; + } +} + +static struct theft_type_info string_info = { + .alloc = string_alloc_cb, + .free = string_free_cb, + .print = string_print_cb, + .hash = string_hash_cb, + .shrink = string_shrink_cb, +}; + +static theft_trial_res prop_should_return_results_if_there_is_a_match(char *needle, + char *haystack) { + int match_exists = has_match(needle, haystack); + if (!match_exists) + return THEFT_TRIAL_SKIP; + + score_t score = match(needle, haystack); + + if (needle[0] == '\0') + return THEFT_TRIAL_SKIP; + + if (score == SCORE_MIN) + return THEFT_TRIAL_FAIL; + + return THEFT_TRIAL_PASS; +} + +TEST should_return_results_if_there_is_a_match() { + struct theft *t = theft_init(0); + struct theft_cfg cfg = { + .name = __func__, + .fun = prop_should_return_results_if_there_is_a_match, + .type_info = {&string_info, &string_info}, + .trials = 100000, + }; + + theft_run_res res = theft_run(t, &cfg); + theft_free(t); + GREATEST_ASSERT_EQm("should_return_results_if_there_is_a_match", THEFT_RUN_PASS, res); + PASS(); +} + +static theft_trial_res prop_positions_should_match_characters_in_string(char *needle, + char *haystack) { + int match_exists = has_match(needle, haystack); + if (!match_exists) + return THEFT_TRIAL_SKIP; + + int n = strlen(needle); + size_t *positions = calloc(n, sizeof(size_t)); + if (!positions) + return THEFT_TRIAL_ERROR; + + match_positions(needle, haystack, positions); + + /* Must be increasing */ + for (int i = 1; i < n; i++) { + if (positions[i] <= positions[i - 1]) { + return THEFT_TRIAL_FAIL; + } + } + + for (int i = 0; i < n; i++) { + if (toupper(needle[i]) != toupper(haystack[positions[i]])) { + return THEFT_TRIAL_FAIL; + } + } + + free(positions); + return THEFT_TRIAL_PASS; +} + +TEST positions_should_match_characters_in_string() { + struct theft *t = theft_init(0); + struct theft_cfg cfg = { + .name = __func__, + .fun = prop_positions_should_match_characters_in_string, + .type_info = {&string_info, &string_info}, + .trials = 100000, + }; + + theft_run_res res = theft_run(t, &cfg); + theft_free(t); + GREATEST_ASSERT_EQm("should_return_results_if_there_is_a_match", THEFT_RUN_PASS, res); + PASS(); +} + +SUITE(properties) { + RUN_TEST(should_return_results_if_there_is_a_match); + RUN_TEST(positions_should_match_characters_in_string); +} |