1 #include <ccan/bdelta/bdelta.h>
2 #include <ccan/bdelta/bdelta.c>
3 #include <ccan/tap/tap.h>
10 * Finds a pseudorandom 32-bit number from 0 to 2^32-1 .
11 * Uses the BCPL linear congruential generator method.
13 * Used instead of system RNG to ensure tests are consistent.
15 static uint32_t rand32(void)
19 * Tests should be run with a different random function
20 * from time to time. I've found that the method below
21 * sometimes behaves poorly for testing purposes.
22 * For example, rand32() % N might only return even numbers.
24 assert(RAND_MAX == 2147483647);
25 return ((random() & 0xFFFF) << 16) | (random() & 0xFFFF);
27 static uint32_t rand32_state = 0;
28 rand32_state *= (uint32_t)0x7FF8A3ED;
29 rand32_state += (uint32_t)0x2AA01D31;
34 #define RSTRING_OK 0 /* Operation succeeded */
35 #define RSTRING_MEMORY 1 /* Memory allocation failed */
36 #define RSTRING_ZERO_CARDINALITY 2 /* Cardinality of byte range is zero */
37 #define RSTRING_RANGE_OVERLAP 3 /* Byte range contains overlapping characters */
39 struct rstring_byte_range {
40 unsigned int cardinality;
41 unsigned int multiplier;
45 static int check_range(const struct rstring_byte_range *range)
54 if (range->cardinality == 0)
55 return RSTRING_ZERO_CARDINALITY;
57 memset(set, 0, sizeof(set));
59 c = range->offset & 0xFF;
60 for (i = 0; i < range->cardinality; i++) {
62 return RSTRING_RANGE_OVERLAP;
64 c += range->multiplier;
72 * Generate a pseudorandom string of the given length,
73 * writing it into a user-supplied buffer.
75 static uint8_t *random_string_into(uint8_t *str, uint32_t size, const struct rstring_byte_range *range)
81 for (i = 0; size - i >= 4; ) {
100 for (i = 0; i < size; )
101 str[i++] = ((rand32() % range->cardinality) * range->multiplier + range->offset) & 0xFF;
108 * Generate a pseudorandom string of the given length.
110 static uint8_t *random_string(uint32_t size, const struct rstring_byte_range *range)
114 if (check_range(range) != RSTRING_OK) {
115 fprintf(stderr, "Invalid byte range for random string generation\n");
123 return random_string_into(str, size, range);
127 * Generate two byte strings:
129 * An "old" string, of length @old_size
130 * A "new" string, differing from "old" by at most @diff_size bytes
131 * (where modifying a character is considered one change).
133 * Returns RSTRING_OK on success, RSTRING_MEMORY if memory allocation fails.
135 static int random_string_pair(
136 uint32_t old_size, uint32_t diff_size, const struct rstring_byte_range *range,
137 uint8_t **old_out, uint8_t **new_out, uint32_t *new_size_out)
146 /* insertions[i] is the number of characters to insert before position i. */
147 uint32_t *insertions;
150 * changes[i] indicates what to do to the character at position i:
154 * 2: Change it to another byte (possibly the same byte).
158 /* String of new bytes to use for insertions and changes. */
160 uint8_t *new_bytes_ptr;
161 uint32_t new_bytes_size;
163 old = random_string(old_size, range);
167 insertions = calloc(old_size + 1, sizeof(*insertions));
168 if (insertions == NULL)
171 changes = calloc(old_size, sizeof(*changes));
176 * Generate a collection of edits, which will be
177 * applied to the old string "simultaneously".
181 for (i = 0; i < diff_size; i++) {
184 switch (rand32() % 3) {
185 case 0: /* Insert a byte. */
186 pos = rand32() % (old_size + 1);
192 case 1: /* Delete a byte. */
193 pos = rand32() % old_size;
196 * This character is already deleted or changed.
197 * Do something else instead.
199 * For the observative: i will overflow if it's 0.
200 * However, overflow of unsigned integers is well-defined
201 * by the C standard. i will wrap around to UINT32_MAX,
202 * then the for-loop increment above will wrap it back to 0.
211 default: /* Change a byte. */
212 pos = rand32() % old_size;
215 * This character is already deleted or changed.
216 * Do something else instead.
227 new_bytes = malloc(new_bytes_size);
228 if (new_bytes == NULL)
230 random_string_into(new_bytes, new_bytes_size, range);
232 new_ = malloc(new_size);
236 /* Apply the insertions and changes generated above. */
238 new_bytes_ptr = new_bytes;
239 for (i = 0; i < old_size; i++) {
240 for (j = 0; j < insertions[i]; j++)
241 *nptr++ = *new_bytes_ptr++;
243 switch (changes[i]) {
244 case 0: /* No change */
251 default: /* Change value */
252 *nptr++ = *new_bytes_ptr++;
256 for (j = 0; j < insertions[i]; j++)
257 *nptr++ = *new_bytes_ptr++;
258 assert((size_t)(nptr - new_) == new_size);
259 assert((size_t)(new_bytes_ptr - new_bytes) == new_bytes_size);
274 *new_size_out = new_size;
293 return RSTRING_MEMORY;