Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/extract/src/buffer-test.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 #include "extract/buffer.h" | |
| 2 #include "extract/alloc.h" | |
| 3 | |
| 4 #include "mem.h" | |
| 5 #include "memento.h" | |
| 6 #include "outf.h" | |
| 7 | |
| 8 #include <assert.h> | |
| 9 #include <errno.h> | |
| 10 #include <stdlib.h> | |
| 11 | |
| 12 | |
| 13 static int rand_int(int max) | |
| 14 /* Returns random int from 0..max-1. */ | |
| 15 { | |
| 16 return (int) (rand() / (RAND_MAX+1.0) * max); | |
| 17 } | |
| 18 | |
| 19 | |
| 20 /* Support for an extract_buffer_t that reads from / writes to a fixed block of | |
| 21 memory, with a fn_cache() that returns a randomly-sized cache each time it is | |
| 22 called, and read/write functions that do random short reads and writes. */ | |
| 23 | |
| 24 typedef struct | |
| 25 { | |
| 26 extract_alloc_t* alloc; | |
| 27 char* data; | |
| 28 size_t bytes; /* Size of data[]. */ | |
| 29 size_t pos; /* Current position in data[]. */ | |
| 30 char cache[137]; | |
| 31 int num_calls_cache; | |
| 32 int num_calls_read; | |
| 33 int num_calls_write; | |
| 34 } mem_t; | |
| 35 | |
| 36 static int s_read(void* handle, void* destination, size_t bytes, size_t* o_actual) | |
| 37 /* Does a randomised short read. */ | |
| 38 { | |
| 39 mem_t* r = handle; | |
| 40 size_t n = 91; | |
| 41 assert(bytes > 0); | |
| 42 r->num_calls_read += 1; | |
| 43 assert(r->pos <= r->bytes); | |
| 44 if (n > bytes) n = bytes; | |
| 45 if (n > r->bytes - r->pos) n = r->bytes - r->pos; | |
| 46 if (n) n = rand_int((int) n-1) + 1; | |
| 47 memcpy(destination, r->data + r->pos, n); | |
| 48 r->pos += n; | |
| 49 *o_actual = n; | |
| 50 return 0; | |
| 51 } | |
| 52 | |
| 53 static int s_read_cache(void* handle, void** o_cache, size_t* o_numbytes) | |
| 54 /* Returns a cache with randomised size. */ | |
| 55 { | |
| 56 mem_t* r = handle; | |
| 57 int n; | |
| 58 r->num_calls_cache += 1; | |
| 59 *o_cache = r->cache; | |
| 60 n = (int) (r->bytes - r->pos); | |
| 61 if (n > (int) sizeof(r->cache)) n = sizeof(r->cache); | |
| 62 if (n) n = rand_int( n - 1) + 1; | |
| 63 memcpy(r->cache, r->data + r->pos, n); | |
| 64 r->pos += n; | |
| 65 *o_cache = r->cache; | |
| 66 *o_numbytes = n; | |
| 67 return 0; | |
| 68 } | |
| 69 | |
| 70 static void s_read_buffer_close(void* handle) | |
| 71 { | |
| 72 mem_t* r = handle; | |
| 73 extract_free(r->alloc, &r->data); | |
| 74 } | |
| 75 | |
| 76 static void s_create_read_buffer(extract_alloc_t* alloc, int bytes, mem_t* r, extract_buffer_t** o_buffer) | |
| 77 /* Creates extract_buffer_t that reads from randomised data using randomised | |
| 78 short reads and cache with randomised sizes. */ | |
| 79 { | |
| 80 int i; | |
| 81 int e; | |
| 82 if (extract_malloc(alloc, &r->data, bytes)) abort(); | |
| 83 for (i=0; i<bytes; ++i) { | |
| 84 r->data[i] = (char) rand(); | |
| 85 } | |
| 86 r->alloc = alloc; | |
| 87 r->bytes = bytes; | |
| 88 r->pos = 0; | |
| 89 r->num_calls_cache = 0; | |
| 90 r->num_calls_read = 0; | |
| 91 r->num_calls_write = 0; | |
| 92 e = extract_buffer_open(alloc, r, s_read, NULL /*write*/, s_read_cache, s_read_buffer_close, o_buffer); | |
| 93 assert(!e); | |
| 94 } | |
| 95 | |
| 96 static void test_read(void) | |
| 97 { | |
| 98 /* Create read buffer with randomised content. */ | |
| 99 int len = 12345; | |
| 100 mem_t r; | |
| 101 char* out_buffer; | |
| 102 int out_pos; | |
| 103 int its; | |
| 104 int e; | |
| 105 extract_buffer_t* buffer; | |
| 106 s_create_read_buffer(NULL /*alloc*/, len, &r, &buffer); | |
| 107 | |
| 108 /* Repeatedly read from read-buffer until we get EOF, and check we read the | |
| 109 original content. */ | |
| 110 if (extract_malloc(r.alloc, &out_buffer, len)) abort(); | |
| 111 out_pos = 0; | |
| 112 for (its=0;; ++its) { | |
| 113 size_t actual; | |
| 114 int n = rand_int(120)+1; | |
| 115 int e = extract_buffer_read(buffer, out_buffer + out_pos, n, &actual); | |
| 116 out_pos += (int) actual; | |
| 117 assert(out_pos == (int) extract_buffer_pos(buffer)); | |
| 118 if (e == 1) break; | |
| 119 assert(!e); | |
| 120 assert(!memcmp(out_buffer, r.data, out_pos)); | |
| 121 } | |
| 122 assert(out_pos == len); | |
| 123 assert(!memcmp(out_buffer, r.data, len)); | |
| 124 outf("its=%i num_calls_read=%i num_calls_write=%i num_calls_cache=%i", | |
| 125 its, r.num_calls_read, r.num_calls_write, r.num_calls_cache); | |
| 126 extract_free(r.alloc, &out_buffer); | |
| 127 out_buffer = NULL; | |
| 128 e = extract_buffer_close(&buffer); | |
| 129 assert(!e); | |
| 130 | |
| 131 outf("Read test passed.\n"); | |
| 132 } | |
| 133 | |
| 134 | |
| 135 static int s_write(void* handle, const void* source, size_t bytes, size_t* o_actual) | |
| 136 /* Does a randomised short write. */ | |
| 137 { | |
| 138 mem_t* r = handle; | |
| 139 int n = 61; | |
| 140 r->num_calls_write += 1; | |
| 141 if (n > (int) bytes) n = (int) bytes; | |
| 142 if (n > (int) (r->bytes - r->pos)) n = (int) (r->bytes - r->pos); | |
| 143 assert(n); | |
| 144 n = rand_int((int) n-1) + 1; | |
| 145 memcpy(r->data + r->pos, source, n); | |
| 146 r->data[r->bytes] = 0; | |
| 147 r->pos += n; | |
| 148 *o_actual = n; | |
| 149 return 0; | |
| 150 } | |
| 151 | |
| 152 static int s_write_cache(void* handle, void** o_cache, size_t* o_numbytes) | |
| 153 /* Returns a cache with randomised size. */ | |
| 154 { | |
| 155 mem_t* r = handle; | |
| 156 int n; | |
| 157 r->num_calls_cache += 1; | |
| 158 assert(r->bytes >= r->pos); | |
| 159 *o_cache = r->cache; | |
| 160 n = (int) (r->bytes - r->pos); | |
| 161 if (n > (int) sizeof(r->cache)) n = sizeof(r->cache); | |
| 162 if (n) n = rand_int( n - 1) + 1; | |
| 163 *o_cache = r->cache; | |
| 164 *o_numbytes = n; | |
| 165 /* We will return a zero-length cache at EOF. */ | |
| 166 return 0; | |
| 167 } | |
| 168 | |
| 169 static void s_write_buffer_close(void* handle) | |
| 170 { | |
| 171 mem_t* mem = handle; | |
| 172 outf("*** freeing mem->data=%p", mem->data); | |
| 173 extract_free(mem->alloc, &mem->data); | |
| 174 } | |
| 175 | |
| 176 static void s_create_write_buffer(extract_alloc_t* alloc, size_t bytes, mem_t* r, extract_buffer_t** o_buffer) | |
| 177 /* Creates extract_buffer_t that reads from randomised data using randomised | |
| 178 short reads and cache with randomised sizes. */ | |
| 179 { | |
| 180 int e; | |
| 181 if (extract_malloc(alloc, &r->data, bytes+1)) abort(); | |
| 182 extract_bzero(r->data, bytes); | |
| 183 r->alloc = alloc; | |
| 184 r->bytes = bytes; | |
| 185 r->pos = 0; | |
| 186 r->num_calls_cache = 0; | |
| 187 r->num_calls_read = 0; | |
| 188 r->num_calls_write = 0; | |
| 189 e = extract_buffer_open(r->alloc, r, NULL /*read*/, s_write, s_write_cache, s_write_buffer_close, o_buffer); | |
| 190 assert(!e); | |
| 191 } | |
| 192 | |
| 193 | |
| 194 static void test_write(void) | |
| 195 { | |
| 196 /* Create write buffer. */ | |
| 197 size_t len = 12345; | |
| 198 mem_t r; | |
| 199 extract_buffer_t* buffer; | |
| 200 char* out_buffer; | |
| 201 unsigned i; | |
| 202 size_t out_pos = 0; | |
| 203 int its; | |
| 204 int e; | |
| 205 | |
| 206 s_create_write_buffer(NULL /*alloc*/, len, &r, &buffer); | |
| 207 | |
| 208 /* Write to read-buffer, and check it contains the original content. */ | |
| 209 if (extract_malloc(r.alloc, &out_buffer, len)) abort(); | |
| 210 for (i=0; i<len; ++i) { | |
| 211 out_buffer[i] = (char) ('a' + rand_int(26)); | |
| 212 } | |
| 213 for (its=0;; ++its) { | |
| 214 size_t actual; | |
| 215 size_t n = rand_int(12)+1; | |
| 216 int e = extract_buffer_write(buffer, out_buffer+out_pos, n, &actual); | |
| 217 out_pos += actual; | |
| 218 assert(out_pos == extract_buffer_pos(buffer)); | |
| 219 if (e == 1) break; | |
| 220 assert(!e); | |
| 221 } | |
| 222 assert(out_pos == len); | |
| 223 assert(!memcmp(out_buffer, r.data, len)); | |
| 224 extract_free(r.alloc, &out_buffer); | |
| 225 outf("its=%i num_calls_read=%i num_calls_write=%i num_calls_cache=%i", | |
| 226 its, r.num_calls_read, r.num_calls_write, r.num_calls_cache); | |
| 227 e = extract_buffer_close(&buffer); | |
| 228 assert(!e); | |
| 229 outf("Write test passed.\n"); | |
| 230 } | |
| 231 | |
| 232 static void test_file(void) | |
| 233 { | |
| 234 /* Check we can write 3 bytes to file. */ | |
| 235 extract_buffer_t* file_buffer; | |
| 236 if (extract_buffer_open_file(NULL /*alloc*/, "test/generated/buffer-file", 1 /*writable*/, &file_buffer)) abort(); | |
| 237 | |
| 238 { | |
| 239 size_t n; | |
| 240 int e; | |
| 241 errno = 0; | |
| 242 e = extract_buffer_write(file_buffer, "foo", 3, &n); | |
| 243 if (e == 0 && n == 3) {} | |
| 244 else { | |
| 245 outf("extract_buffer_write() returned e=%i errno=%i n=%zi", e, errno, n); | |
| 246 abort(); | |
| 247 } | |
| 248 } | |
| 249 if (extract_buffer_close(&file_buffer)) abort(); | |
| 250 | |
| 251 /* Check we get back expected short reads and EOF when reading from 3-byte | |
| 252 file created above. */ | |
| 253 if (extract_buffer_open_file(NULL /*alloc*/, "test/generated/buffer-file", 0 /*writable*/, &file_buffer)) abort(); | |
| 254 | |
| 255 { | |
| 256 size_t n; | |
| 257 char buffer[10]; | |
| 258 int e; | |
| 259 errno = 0; | |
| 260 e = extract_buffer_read(file_buffer, buffer, 2, &n); | |
| 261 if (e == 0 && n == 2) {} | |
| 262 else { | |
| 263 outf("extract_buffer_read() returned e=%i errno=%i n=%zi", e, errno, n); | |
| 264 abort(); | |
| 265 } | |
| 266 e = extract_buffer_read(file_buffer, buffer, 3, &n); | |
| 267 if (e == 1 && n == 1) {} | |
| 268 else { | |
| 269 outf("extract_buffer_read() returned e=%i errno=%i n=%zi", e, errno, n); | |
| 270 abort(); | |
| 271 } | |
| 272 e = extract_buffer_read(file_buffer, buffer, 3, &n); | |
| 273 if (e == 1 && n == 0) {} | |
| 274 else { | |
| 275 outf("extract_buffer_read() returned e=%i errno=%i n=%zi", e, errno, n); | |
| 276 abort(); | |
| 277 } | |
| 278 } | |
| 279 if (extract_buffer_close(&file_buffer)) abort(); | |
| 280 | |
| 281 /* Check writing to read-only file buffer fails. */ | |
| 282 { | |
| 283 int e; | |
| 284 char text[] = "hello world"; | |
| 285 size_t actual; | |
| 286 if (extract_buffer_open_file(NULL /*alloc*/, "test/generated/buffer-file", 0 /*writable*/, &file_buffer)) { | |
| 287 abort(); | |
| 288 } | |
| 289 | |
| 290 e = extract_buffer_write(file_buffer, text, sizeof(text)-1, &actual); | |
| 291 outf("extract_buffer_write() on read buffer returned e=%i actual=%zi", e, actual); | |
| 292 if (e != -1 || errno != EINVAL) abort(); | |
| 293 if (extract_buffer_close(&file_buffer)) abort(); | |
| 294 } | |
| 295 | |
| 296 outf("file buffer tests passed.\n"); | |
| 297 } | |
| 298 | |
| 299 int main(void) | |
| 300 { | |
| 301 extract_outf_verbose_set(1); | |
| 302 test_read(); | |
| 303 test_write(); | |
| 304 test_file(); | |
| 305 return 0; | |
| 306 } |
