2
* packed-data-test.c: a collection of svn_packed__* tests
4
* ====================================================================
5
* Licensed to the Apache Software Foundation (ASF) under one
6
* or more contributor license agreements. See the NOTICE file
7
* distributed with this work for additional information
8
* regarding copyright ownership. The ASF licenses this file
9
* to you under the Apache License, Version 2.0 (the
10
* "License"); you may not use this file except in compliance
11
* with the License. You may obtain a copy of the License at
13
* http://www.apache.org/licenses/LICENSE-2.0
15
* Unless required by applicable law or agreed to in writing,
16
* software distributed under the License is distributed on an
17
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18
* KIND, either express or implied. See the License for the
19
* specific language governing permissions and limitations
21
* ====================================================================
24
/* ====================================================================
25
To add tests, look toward the bottom of this file.
33
#include <apr_pools.h>
35
#include "../svn_test.h"
37
#include "svn_error.h"
38
#include "svn_string.h" /* This includes <apr_*.h> */
39
#include "private/svn_packed_data.h"
41
/* Take the WRITE_ROOT, serialize its contents, parse it again into a new
42
* data root and return it in *READ_ROOT. Allocate it in POOL.
45
get_read_root(svn_packed__data_root_t **read_root,
46
svn_packed__data_root_t *write_root,
49
svn_stringbuf_t *stream_buffer = svn_stringbuf_create_empty(pool);
52
stream = svn_stream_from_stringbuf(stream_buffer, pool);
53
SVN_ERR(svn_packed__data_write(stream, write_root, pool));
54
SVN_ERR(svn_stream_close(stream));
56
stream = svn_stream_from_stringbuf(stream_buffer, pool);
57
SVN_ERR(svn_packed__data_read(read_root, stream, pool, pool));
58
SVN_ERR(svn_stream_close(stream));
64
test_empty_container(apr_pool_t *pool)
66
/* create an empty, readable container */
67
svn_packed__data_root_t *root = svn_packed__data_create_root(pool);
68
SVN_ERR(get_read_root(&root, root, pool));
70
/* there should be no sub-streams */
71
SVN_TEST_ASSERT(svn_packed__first_int_stream(root) == NULL);
72
SVN_TEST_ASSERT(svn_packed__first_byte_stream(root) == NULL);
77
/* Check that COUNT numbers from VALUES can be written as uints to a
78
* packed data stream and can be read from that stream again. Deltify
79
* data in the stream if DIFF is set. Use POOL for allocations.
82
verify_uint_stream(const apr_uint64_t *values,
87
svn_packed__data_root_t *root = svn_packed__data_create_root(pool);
88
svn_packed__int_stream_t *stream
89
= svn_packed__create_int_stream(root, diff, FALSE);
92
for (i = 0; i < count; ++i)
93
svn_packed__add_uint(stream, values[i]);
95
SVN_ERR(get_read_root(&root, root, pool));
97
/* the container should contain exactly one int stream */
98
stream = svn_packed__first_int_stream(root);
99
SVN_TEST_ASSERT(stream);
100
SVN_TEST_ASSERT(!svn_packed__next_int_stream(stream));
101
SVN_TEST_ASSERT(!svn_packed__first_byte_stream(root));
103
/* the stream shall contain exactly the items we put into it */
104
SVN_TEST_ASSERT(svn_packed__int_count(stream) == count);
105
for (i = 0; i < count; ++i)
106
SVN_TEST_ASSERT(svn_packed__get_uint(stream) == values[i]);
108
/* reading beyond eos should return 0 values */
109
SVN_TEST_ASSERT(svn_packed__get_uint(stream) == 0);
115
test_uint_stream(apr_pool_t *pool)
118
const apr_uint64_t values[COUNT] =
123
APR_UINT64_C(0x8000000000000000),
125
APR_UINT64_C(0x7fffffffffffffff),
126
APR_UINT64_C(0x1234567890abcdef),
127
APR_UINT64_C(0x0fedcba987654321),
130
SVN_ERR(verify_uint_stream(values, COUNT, FALSE, pool));
131
SVN_ERR(verify_uint_stream(values, COUNT, TRUE, pool));
136
/* Check that COUNT numbers from VALUES can be written as signed ints to a
137
* packed data stream and can be read from that stream again. Deltify
138
* data in the stream if DIFF is set. Use POOL for allocations.
141
verify_int_stream(const apr_int64_t *values,
146
svn_packed__data_root_t *root = svn_packed__data_create_root(pool);
147
svn_packed__int_stream_t *stream
148
= svn_packed__create_int_stream(root, diff, TRUE);
151
for (i = 0; i < count; ++i)
152
svn_packed__add_int(stream, values[i]);
154
SVN_ERR(get_read_root(&root, root, pool));
156
/* the container should contain exactly one int stream */
157
stream = svn_packed__first_int_stream(root);
158
SVN_TEST_ASSERT(stream);
159
SVN_TEST_ASSERT(!svn_packed__next_int_stream(stream));
160
SVN_TEST_ASSERT(!svn_packed__first_byte_stream(root));
162
/* the stream shall contain exactly the items we put into it */
163
SVN_TEST_ASSERT(svn_packed__int_count(stream) == count);
164
for (i = 0; i < count; ++i)
165
SVN_TEST_ASSERT(svn_packed__get_int(stream) == values[i]);
167
/* reading beyond eos should return 0 values */
168
SVN_TEST_ASSERT(svn_packed__get_int(stream) == 0);
174
test_int_stream(apr_pool_t *pool)
177
const apr_int64_t values[COUNT] =
179
APR_INT64_MAX, /* extreme value */
180
APR_INT64_MIN, /* other extreme, creating maximum delta to predecessor */
181
0, /* delta to predecessor > APR_INT64_MAX */
182
APR_INT64_MAX, /* max value, again */
183
-APR_INT64_MAX, /* _almost_ min value, almost max delta */
184
APR_INT64_C(0x1234567890abcdef), /* some arbitrary value */
185
-APR_INT64_C(0x0fedcba987654321), /* arbitrary value, different sign */
188
SVN_ERR(verify_int_stream(values, COUNT, FALSE, pool));
189
SVN_ERR(verify_int_stream(values, COUNT, TRUE, pool));
195
test_byte_stream(apr_pool_t *pool)
198
const svn_string_t values[COUNT] =
208
svn_packed__data_root_t *root = svn_packed__data_create_root(pool);
209
svn_packed__byte_stream_t *stream
210
= svn_packed__create_bytes_stream(root);
213
for (i = 0; i < COUNT; ++i)
214
svn_packed__add_bytes(stream, values[i].data, values[i].len);
216
SVN_ERR(get_read_root(&root, root, pool));
218
/* the container should contain exactly one byte stream */
219
stream = svn_packed__first_byte_stream(root);
220
SVN_TEST_ASSERT(stream);
221
SVN_TEST_ASSERT(!svn_packed__next_byte_stream(stream));
223
/* the stream shall contain exactly the items we put into it */
224
SVN_TEST_ASSERT(svn_packed__byte_count(stream) == 20);
225
for (i = 0; i < COUNT; ++i)
228
string.data = svn_packed__get_bytes(stream, &string.len);
230
SVN_TEST_ASSERT(string.len == values[i].len);
231
SVN_TEST_ASSERT(!memcmp(string.data, values[i].data, string.len));
234
/* reading beyond eos should return 0 values */
235
SVN_TEST_ASSERT(svn_packed__byte_count(stream) == 0);
240
/* Some simple structure that we use as sub-structure to BASE_RECORD_T.
241
* Have it contain numbers and strings.
243
typedef struct sub_record_t
249
/* signed / unsigned, 64 bits and shorter, diff-able and not, multiple
250
* strings, multiple sub-records. */
251
typedef struct base_record_t
254
svn_string_t description;
255
apr_uint64_t large_unsigned1;
256
apr_uint64_t large_unsigned2;
257
const sub_record_t *left_subs;
258
apr_int64_t large_signed1;
259
apr_int64_t large_signed2;
261
const sub_record_t *right_subs;
266
enum {SUB_RECORD_COUNT = 7};
267
enum {BASE_RECORD_COUNT = 4};
269
static const sub_record_t sub_records[SUB_RECORD_COUNT] =
271
{ 6, { "this is quite a longish piece of text", 37} },
273
{ 4, { "not empty", 9} },
274
{ 3, { "another bit of text", 19} },
276
{ 1, { "first sub-record", 16} },
280
static const base_record_t test_data[BASE_RECORD_COUNT] =
282
{ 1, { "maximum", 7},
283
APR_UINT64_MAX, APR_UINT64_MAX, sub_records,
284
APR_INT64_MAX, APR_INT64_MAX, 9967, sub_records + 1,
285
{ "\0\1\2\3\4\5\6\7\x8\x9\xa", 11} },
287
{ 2, { "minimum", 7},
288
0, 0, sub_records + 6,
289
APR_INT64_MIN, APR_INT64_MIN, 6029, sub_records + 5,
293
APR_UINT64_C(0x8000000000000000), APR_UINT64_C(0x8000000000000000),
295
0, 0, 653, sub_records + 3,
296
{ "\xff\0\1\2\3\4\5\6\7\x8\x9\xa", 12} },
299
APR_UINT64_C(0x1234567890abcdef), APR_UINT64_C(0xfedcba987654321),
301
APR_INT64_C(0x1234567890abcd), APR_INT64_C(-0xedcba987654321), 7309,
303
{ "\x80\x7f\0\1\6", 5} }
306
/* Serialize RECORDS into INT_STREAM and TEXT_STREAM. Stop when the
307
* current record's SUB_COUNTER is 0.
310
pack_subs(svn_packed__int_stream_t *int_stream,
311
svn_packed__byte_stream_t *text_stream,
312
const sub_record_t *records)
315
for (count = 0; records[count].sub_counter; ++count)
317
svn_packed__add_int(int_stream, records[count].sub_counter);
318
svn_packed__add_bytes(text_stream,
319
records[count].text.data,
320
records[count].text.len);
326
/* Serialize COUNT records starting from DATA into a packed data container
327
* allocated in POOL and return the container root.
329
static svn_packed__data_root_t *
330
pack(const base_record_t *data,
335
svn_packed__data_root_t *root = svn_packed__data_create_root(pool);
336
svn_packed__int_stream_t *base_stream
337
= svn_packed__create_int_stream(root, FALSE, FALSE);
338
svn_packed__int_stream_t *sub_count_stream
339
= svn_packed__create_int_stream(root, TRUE, FALSE);
341
svn_packed__int_stream_t *left_sub_stream
342
= svn_packed__create_int_stream(root, FALSE, TRUE);
343
svn_packed__int_stream_t *right_sub_stream
344
= svn_packed__create_int_stream(root, FALSE, TRUE);
346
svn_packed__byte_stream_t *base_description_stream
347
= svn_packed__create_bytes_stream(root);
348
svn_packed__byte_stream_t *base_binary_stream
349
= svn_packed__create_bytes_stream(root);
350
svn_packed__byte_stream_t *sub_text_stream
351
= svn_packed__create_bytes_stream(root);
353
svn_packed__create_int_substream(base_stream, TRUE, TRUE); /* counter */
354
svn_packed__create_int_substream(base_stream, TRUE, FALSE); /* large_unsigned1 */
355
svn_packed__create_int_substream(base_stream, FALSE, FALSE); /* large_unsigned2 */
356
svn_packed__create_int_substream(base_stream, TRUE, TRUE); /* large_signed1 */
357
svn_packed__create_int_substream(base_stream, FALSE, TRUE); /* large_signed2 */
358
svn_packed__create_int_substream(base_stream, TRUE, FALSE); /* prime */
360
for (i = 0; i < count; ++i)
362
svn_packed__add_int(base_stream, data[i].counter);
363
svn_packed__add_bytes(base_description_stream,
364
data[i].description.data,
365
data[i].description.len);
366
svn_packed__add_uint(base_stream, data[i].large_unsigned1);
367
svn_packed__add_uint(base_stream, data[i].large_unsigned2);
368
svn_packed__add_uint(sub_count_stream,
369
pack_subs(left_sub_stream, sub_text_stream,
372
svn_packed__add_int(base_stream, data[i].large_signed1);
373
svn_packed__add_int(base_stream, data[i].large_signed2);
374
svn_packed__add_uint(base_stream, data[i].prime);
375
svn_packed__add_uint(sub_count_stream,
376
pack_subs(right_sub_stream, sub_text_stream,
377
data[i].right_subs));
379
svn_packed__add_bytes(base_binary_stream,
387
/* Deserialize COUNT records from INT_STREAM and TEXT_STREAM and return
388
* the result allocated in POOL.
390
static sub_record_t *
391
unpack_subs(svn_packed__int_stream_t *int_stream,
392
svn_packed__byte_stream_t *text_stream,
396
sub_record_t *records = apr_pcalloc(pool, (count + 1) * sizeof(*records));
399
for (i = 0; i < count; ++i)
401
records[i].sub_counter = (int) svn_packed__get_int(int_stream);
402
records[i].text.data = svn_packed__get_bytes(text_stream,
403
&records[i].text.len);
409
/* Deserialize all records from the packed data container ROOT, allocate
410
* them in POOL and return them. Set *COUNT to the number of records read.
412
static base_record_t *
413
unpack(apr_size_t *count,
414
svn_packed__data_root_t *root,
417
svn_packed__int_stream_t *base_stream
418
= svn_packed__first_int_stream(root);
419
svn_packed__int_stream_t *sub_count_stream
420
= svn_packed__next_int_stream(base_stream);
421
svn_packed__byte_stream_t *base_description_stream
422
= svn_packed__first_byte_stream(root);
423
svn_packed__byte_stream_t *base_binary_stream
424
= svn_packed__next_byte_stream(base_description_stream);
425
svn_packed__byte_stream_t *sub_text_stream
426
= svn_packed__next_byte_stream(base_binary_stream);
428
svn_packed__int_stream_t *left_sub_stream
429
= svn_packed__next_int_stream(sub_count_stream);
430
svn_packed__int_stream_t *right_sub_stream
431
= svn_packed__next_int_stream(left_sub_stream);
435
*count = svn_packed__int_count(sub_count_stream) / 2;
436
data = apr_pcalloc(pool, *count * sizeof(*data));
438
for (i = 0; i < *count; ++i)
440
data[i].counter = (int) svn_packed__get_int(base_stream);
441
data[i].description.data
442
= svn_packed__get_bytes(base_description_stream,
443
&data[i].description.len);
444
data[i].large_unsigned1 = svn_packed__get_uint(base_stream);
445
data[i].large_unsigned2 = svn_packed__get_uint(base_stream);
446
data[i].left_subs = unpack_subs(left_sub_stream, sub_text_stream,
447
(apr_size_t)svn_packed__get_uint(sub_count_stream),
450
data[i].large_signed1 = svn_packed__get_int(base_stream);
451
data[i].large_signed2 = svn_packed__get_int(base_stream);
452
data[i].prime = (unsigned) svn_packed__get_uint(base_stream);
453
data[i].right_subs = unpack_subs(right_sub_stream, sub_text_stream,
454
(apr_size_t)svn_packed__get_uint(sub_count_stream),
458
= svn_packed__get_bytes(base_binary_stream,
459
&data[i].binary.len);
465
/* Assert that LHS and RHS contain the same binary data (i.e. don't test
466
* for a terminating NUL).
469
compare_binary(const svn_string_t *lhs,
470
const svn_string_t *rhs)
472
SVN_TEST_ASSERT(lhs->len == rhs->len);
473
SVN_TEST_ASSERT(!memcmp(lhs->data, rhs->data, rhs->len));
478
/* Assert that LHS and RHS contain the same number of records with the
482
compare_subs(const sub_record_t *lhs,
483
const sub_record_t *rhs)
485
for (; lhs->sub_counter; ++lhs, ++rhs)
487
SVN_TEST_ASSERT(lhs->sub_counter == rhs->sub_counter);
488
SVN_ERR(compare_binary(&lhs->text, &rhs->text));
491
SVN_TEST_ASSERT(lhs->sub_counter == rhs->sub_counter);
495
/* Assert that the first COUNT records in LHS and RHS have the same contents.
498
compare(const base_record_t *lhs,
499
const base_record_t *rhs,
503
for (i = 0; i < count; ++i)
505
SVN_TEST_ASSERT(lhs[i].counter == rhs[i].counter);
506
SVN_ERR(compare_binary(&lhs[i].description, &rhs[i].description));
507
SVN_TEST_ASSERT(lhs[i].large_unsigned1 == rhs[i].large_unsigned1);
508
SVN_TEST_ASSERT(lhs[i].large_unsigned2 == rhs[i].large_unsigned2);
509
SVN_ERR(compare_subs(lhs[i].left_subs, rhs[i].left_subs));
510
SVN_TEST_ASSERT(lhs[i].counter == rhs[i].counter);
511
SVN_TEST_ASSERT(lhs[i].large_signed1 == rhs[i].large_signed1);
512
SVN_TEST_ASSERT(lhs[i].large_signed2 == rhs[i].large_signed2);
513
SVN_TEST_ASSERT(lhs[i].prime == rhs[i].prime);
514
SVN_ERR(compare_subs(lhs[i].right_subs, rhs[i].right_subs));
515
SVN_ERR(compare_binary(&lhs[i].binary, &rhs[i].binary));
522
test_empty_structure(apr_pool_t *pool)
524
base_record_t *unpacked;
527
/* create an empty, readable container */
528
svn_packed__data_root_t *root = pack(test_data, 0, pool);
530
SVN_ERR(get_read_root(&root, root, pool));
531
unpacked = unpack(&count, root, pool);
532
SVN_TEST_ASSERT(count == 0);
533
SVN_ERR(compare(unpacked, test_data, count));
539
test_full_structure(apr_pool_t *pool)
541
base_record_t *unpacked;
544
/* create an empty, readable container */
545
svn_packed__data_root_t *root = pack(test_data, BASE_RECORD_COUNT, pool);
547
SVN_ERR(get_read_root(&root, root, pool));
548
unpacked = unpack(&count, root, pool);
549
SVN_TEST_ASSERT(count == BASE_RECORD_COUNT);
550
SVN_ERR(compare(unpacked, test_data, count));
555
/* An array of all test functions */
557
static int max_threads = 1;
559
static struct svn_test_descriptor_t test_funcs[] =
562
SVN_TEST_PASS2(test_empty_container,
563
"test empty container"),
564
SVN_TEST_PASS2(test_uint_stream,
565
"test a single uint stream"),
566
SVN_TEST_PASS2(test_int_stream,
567
"test a single int stream"),
568
SVN_TEST_PASS2(test_byte_stream,
569
"test a single bytes stream"),
570
SVN_TEST_PASS2(test_empty_structure,
571
"test empty, nested structure"),
572
SVN_TEST_PASS2(test_full_structure,
573
"test nested structure"),