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 }