1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
#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) {
(void)env;
char *str = (char *)instance;
int size = strlen(str);
return theft_hash_onepass((uint8_t *)str, size);
}
static void *string_shrink_cb(void *instance, uint32_t tactic, void *env) {
(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;
}
}
/* Matching characters must be in returned positions */
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_suite) {
RUN_TEST(should_return_results_if_there_is_a_match);
RUN_TEST(positions_should_match_characters_in_string);
}
|