Home | History | Annotate | Line # | Download | only in tests
test_index_hash.c revision 1.1.1.1
      1 // SPDX-License-Identifier: 0BSD
      2 
      3 ///////////////////////////////////////////////////////////////////////////////
      4 //
      5 /// \file       test_index_hash.c
      6 /// \brief      Tests src/liblzma/common/index_hash.c API functions
      7 ///
      8 /// \note       No test included for lzma_index_hash_end since it
      9 ///             would be trivial unless tested for memory leaks
     10 ///             with something like valgrind
     11 //
     12 //  Author:     Jia Tan
     13 //
     14 ///////////////////////////////////////////////////////////////////////////////
     15 
     16 #include "tests.h"
     17 
     18 // Needed for UNPADDED_SIZE_MIN and UNPADDED_SIZE_MAX macro definitions
     19 // and index_size and vli_ceil4 helper functions
     20 #include "common/index.h"
     21 
     22 
     23 static void
     24 test_lzma_index_hash_init(void)
     25 {
     26 #ifndef HAVE_DECODERS
     27 	assert_skip("Decoder support disabled");
     28 #else
     29 	// First test with NULL index_hash.
     30 	// This should create a fresh index_hash.
     31 	lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
     32 	assert_true(index_hash != NULL);
     33 
     34 	// Next test with non-NULL index_hash.
     35 	lzma_index_hash *second_hash = lzma_index_hash_init(index_hash, NULL);
     36 
     37 	// It should not create a new index_hash pointer.
     38 	// Instead it must just re-init the first index_hash.
     39 	assert_true(index_hash == second_hash);
     40 
     41 	lzma_index_hash_end(index_hash, NULL);
     42 #endif
     43 }
     44 
     45 
     46 static void
     47 test_lzma_index_hash_append(void)
     48 {
     49 #ifndef HAVE_DECODERS
     50 	assert_skip("Decoder support disabled");
     51 #else
     52 	// Test all invalid parameters
     53 	assert_lzma_ret(lzma_index_hash_append(NULL, 0, 0),
     54 			LZMA_PROG_ERROR);
     55 
     56 	// Test NULL index_hash
     57 	assert_lzma_ret(lzma_index_hash_append(NULL, UNPADDED_SIZE_MIN,
     58 			LZMA_VLI_MAX), LZMA_PROG_ERROR);
     59 
     60 	// Test with invalid Unpadded Size
     61 	lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
     62 	assert_true(index_hash != NULL);
     63 	assert_lzma_ret(lzma_index_hash_append(index_hash,
     64 			UNPADDED_SIZE_MIN - 1, LZMA_VLI_MAX),
     65 			LZMA_PROG_ERROR);
     66 
     67 	// Test with invalid Uncompressed Size
     68 	assert_lzma_ret(lzma_index_hash_append(index_hash,
     69 			UNPADDED_SIZE_MIN, LZMA_VLI_MAX + 1),
     70 			LZMA_PROG_ERROR);
     71 
     72 	// First append a Record describing a small Block.
     73 	// This should succeed.
     74 	assert_lzma_ret(lzma_index_hash_append(index_hash,
     75 			UNPADDED_SIZE_MIN, 1), LZMA_OK);
     76 
     77 	// Append another small Record.
     78 	assert_lzma_ret(lzma_index_hash_append(index_hash,
     79 			UNPADDED_SIZE_MIN, 1), LZMA_OK);
     80 
     81 	// Append a Record that would cause the compressed size to grow
     82 	// too big
     83 	assert_lzma_ret(lzma_index_hash_append(index_hash,
     84 			UNPADDED_SIZE_MAX, 1), LZMA_DATA_ERROR);
     85 
     86 	lzma_index_hash_end(index_hash, NULL);
     87 #endif
     88 }
     89 
     90 
     91 #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
     92 // Fill an index_hash with unpadded and uncompressed VLIs
     93 // by calling lzma_index_hash_append
     94 static void
     95 fill_index_hash(lzma_index_hash *index_hash, const lzma_vli *unpadded_sizes,
     96 		const lzma_vli *uncomp_sizes, uint32_t block_count)
     97 {
     98 	for (uint32_t i = 0; i < block_count; ++i)
     99 		assert_lzma_ret(lzma_index_hash_append(index_hash,
    100 			unpadded_sizes[i], uncomp_sizes[i]), LZMA_OK);
    101 }
    102 
    103 
    104 // Set the contents of buf to the expected Index based on the
    105 // .xz specification. This needs the unpadded and uncompressed VLIs
    106 // to correctly create the Index.
    107 static void
    108 generate_index(uint8_t *buf, const lzma_vli *unpadded_sizes,
    109 		const lzma_vli *uncomp_sizes, uint32_t block_count,
    110 		size_t index_max_size)
    111 {
    112 	size_t in_pos = 0;
    113 	size_t out_pos = 0;
    114 
    115 	// First set Index Indicator
    116 	buf[out_pos++] = INDEX_INDICATOR;
    117 
    118 	// Next write out Number of Records
    119 	assert_lzma_ret(lzma_vli_encode(block_count, &in_pos, buf,
    120 			&out_pos, index_max_size), LZMA_STREAM_END);
    121 
    122 	// Next write out each Record.
    123 	// A Record consists of Unpadded Size and Uncompressed Size
    124 	// written next to each other as VLIs.
    125 	for (uint32_t i = 0; i < block_count; ++i) {
    126 		in_pos = 0;
    127 		assert_lzma_ret(lzma_vli_encode(unpadded_sizes[i], &in_pos,
    128 			buf, &out_pos, index_max_size), LZMA_STREAM_END);
    129 		in_pos = 0;
    130 		assert_lzma_ret(lzma_vli_encode(uncomp_sizes[i], &in_pos,
    131 			buf, &out_pos, index_max_size), LZMA_STREAM_END);
    132 	}
    133 
    134 	// Add Index Padding
    135 	lzma_vli rounded_out_pos = vli_ceil4(out_pos);
    136 	memzero(buf + out_pos, rounded_out_pos - out_pos);
    137 	out_pos = rounded_out_pos;
    138 
    139 	// Add the CRC32
    140 	write32le(buf + out_pos, lzma_crc32(buf, out_pos, 0));
    141 	out_pos += 4;
    142 
    143 	assert_uint_eq(out_pos, index_max_size);
    144 }
    145 #endif
    146 
    147 
    148 static void
    149 test_lzma_index_hash_decode(void)
    150 {
    151 #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
    152 	assert_skip("Encoder or decoder support disabled");
    153 #else
    154 	lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
    155 	assert_true(index_hash != NULL);
    156 
    157 	size_t in_pos = 0;
    158 
    159 	// Six valid values for the Unpadded Size fields in an Index
    160 	const lzma_vli unpadded_sizes[6] = {
    161 		UNPADDED_SIZE_MIN,
    162 		1000,
    163 		4000,
    164 		8000,
    165 		16000,
    166 		32000
    167 	};
    168 
    169 	// Six valid values for the Uncompressed Size fields in an Index
    170 	const lzma_vli uncomp_sizes[6] = {
    171 		1,
    172 		500,
    173 		8000,
    174 		20,
    175 		1,
    176 		500
    177 	};
    178 
    179 	// Add two Records to an index_hash
    180 	fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2);
    181 
    182 	const lzma_vli size_two_records = lzma_index_hash_size(index_hash);
    183 	assert_uint(size_two_records, >, 0);
    184 	uint8_t *index_two_records = tuktest_malloc(size_two_records);
    185 
    186 	generate_index(index_two_records, unpadded_sizes, uncomp_sizes, 2,
    187 			size_two_records);
    188 
    189 	// First test for basic buffer size error
    190 	in_pos = size_two_records + 1;
    191 	assert_lzma_ret(lzma_index_hash_decode(index_hash,
    192 			index_two_records, &in_pos,
    193 			size_two_records), LZMA_BUF_ERROR);
    194 
    195 	// Next test for invalid Index Indicator
    196 	in_pos = 0;
    197 	index_two_records[0] ^= 1;
    198 	assert_lzma_ret(lzma_index_hash_decode(index_hash,
    199 			index_two_records, &in_pos,
    200 			size_two_records), LZMA_DATA_ERROR);
    201 	index_two_records[0] ^= 1;
    202 
    203 	// Next verify the index_hash as expected
    204 	in_pos = 0;
    205 	assert_lzma_ret(lzma_index_hash_decode(index_hash,
    206 			index_two_records, &in_pos,
    207 			size_two_records), LZMA_STREAM_END);
    208 
    209 	// Next test an index_hash with three Records
    210 	index_hash = lzma_index_hash_init(index_hash, NULL);
    211 	fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 3);
    212 
    213 	const lzma_vli size_three_records = lzma_index_hash_size(
    214 			index_hash);
    215 	assert_uint(size_three_records, >, 0);
    216 	uint8_t *index_three_records = tuktest_malloc(size_three_records);
    217 
    218 	generate_index(index_three_records, unpadded_sizes, uncomp_sizes,
    219 			3, size_three_records);
    220 
    221 	in_pos = 0;
    222 	assert_lzma_ret(lzma_index_hash_decode(index_hash,
    223 			index_three_records, &in_pos,
    224 			size_three_records), LZMA_STREAM_END);
    225 
    226 	// Next test an index_hash with five Records
    227 	index_hash = lzma_index_hash_init(index_hash, NULL);
    228 	fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 5);
    229 
    230 	const lzma_vli size_five_records = lzma_index_hash_size(
    231 			index_hash);
    232 	assert_uint(size_five_records, >, 0);
    233 	uint8_t *index_five_records = tuktest_malloc(size_five_records);
    234 
    235 	generate_index(index_five_records, unpadded_sizes, uncomp_sizes, 5,
    236 			size_five_records);
    237 
    238 	// Instead of testing all input at once, give input
    239 	// one byte at a time
    240 	in_pos = 0;
    241 	for (lzma_vli i = 0; i < size_five_records - 1; ++i) {
    242 		assert_lzma_ret(lzma_index_hash_decode(index_hash,
    243 				index_five_records, &in_pos, in_pos + 1),
    244 				LZMA_OK);
    245 	}
    246 
    247 	// Last byte should return LZMA_STREAM_END
    248 	assert_lzma_ret(lzma_index_hash_decode(index_hash,
    249 			index_five_records, &in_pos,
    250 			in_pos + 1), LZMA_STREAM_END);
    251 
    252 	// Next test if the index_hash is given an incorrect Unpadded
    253 	// Size. Should detect and report LZMA_DATA_ERROR
    254 	index_hash = lzma_index_hash_init(index_hash, NULL);
    255 	fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 5);
    256 	// The sixth Record will have an invalid Unpadded Size
    257 	assert_lzma_ret(lzma_index_hash_append(index_hash,
    258 			unpadded_sizes[5] + 1,
    259 			uncomp_sizes[5]), LZMA_OK);
    260 
    261 	const lzma_vli size_six_records = lzma_index_hash_size(
    262 			index_hash);
    263 
    264 	assert_uint(size_six_records, >, 0);
    265 	uint8_t *index_six_records = tuktest_malloc(size_six_records);
    266 
    267 	generate_index(index_six_records, unpadded_sizes, uncomp_sizes, 6,
    268 			size_six_records);
    269 	in_pos = 0;
    270 	assert_lzma_ret(lzma_index_hash_decode(index_hash,
    271 			index_six_records, &in_pos,
    272 			size_six_records), LZMA_DATA_ERROR);
    273 
    274 	// Next test if the Index is corrupt (invalid CRC32).
    275 	// Should detect and report LZMA_DATA_ERROR
    276 	index_hash = lzma_index_hash_init(index_hash, NULL);
    277 	fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2);
    278 
    279 	index_two_records[size_two_records - 1] ^= 1;
    280 
    281 	in_pos = 0;
    282 	assert_lzma_ret(lzma_index_hash_decode(index_hash,
    283 			index_two_records, &in_pos,
    284 			size_two_records), LZMA_DATA_ERROR);
    285 
    286 	// Next test with Index and index_hash struct not matching
    287 	// a Record
    288 	index_hash = lzma_index_hash_init(index_hash, NULL);
    289 	fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2);
    290 	// Recalculate Index with invalid Unpadded Size
    291 	const lzma_vli unpadded_sizes_invalid[2] = {
    292 		unpadded_sizes[0],
    293 		unpadded_sizes[1] + 1
    294 	};
    295 
    296 	generate_index(index_two_records, unpadded_sizes_invalid,
    297 			uncomp_sizes, 2, size_two_records);
    298 
    299 	in_pos = 0;
    300 	assert_lzma_ret(lzma_index_hash_decode(index_hash,
    301 			index_two_records, &in_pos,
    302 			size_two_records), LZMA_DATA_ERROR);
    303 
    304 	lzma_index_hash_end(index_hash, NULL);
    305 #endif
    306 }
    307 
    308 
    309 static void
    310 test_lzma_index_hash_size(void)
    311 {
    312 #ifndef HAVE_DECODERS
    313 	assert_skip("Decoder support disabled");
    314 #else
    315 	lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
    316 	assert_true(index_hash != NULL);
    317 
    318 	// First test empty index_hash
    319 	// Expected size should be:
    320 	// Index Indicator - 1 byte
    321 	// Number of Records - 1 byte
    322 	// List of Records - 0 bytes
    323 	// Index Padding - 2 bytes
    324 	// CRC32 - 4 bytes
    325 	// Total - 8 bytes
    326 	assert_uint_eq(lzma_index_hash_size(index_hash), 8);
    327 
    328 	// Append a Record describing a small Block to the index_hash
    329 	assert_lzma_ret(lzma_index_hash_append(index_hash,
    330 			UNPADDED_SIZE_MIN, 1), LZMA_OK);
    331 
    332 	// Expected size should be:
    333 	// Index Indicator - 1 byte
    334 	// Number of Records - 1 byte
    335 	// List of Records - 2 bytes
    336 	// Index Padding - 0 bytes
    337 	// CRC32 - 4 bytes
    338 	// Total - 8 bytes
    339 	lzma_vli expected_size = 8;
    340 	assert_uint_eq(lzma_index_hash_size(index_hash), expected_size);
    341 
    342 	// Append additional small Record
    343 	assert_lzma_ret(lzma_index_hash_append(index_hash,
    344 			UNPADDED_SIZE_MIN, 1), LZMA_OK);
    345 
    346 	// Expected size should be:
    347 	// Index Indicator - 1 byte
    348 	// Number of Records - 1 byte
    349 	// List of Records - 4 bytes
    350 	// Index Padding - 2 bytes
    351 	// CRC32 - 4 bytes
    352 	// Total - 12 bytes
    353 	expected_size = 12;
    354 	assert_uint_eq(lzma_index_hash_size(index_hash), expected_size);
    355 
    356 	// Append a larger Record to the index_hash (3 bytes for each VLI)
    357 	const lzma_vli three_byte_vli = 0x10000;
    358 	assert_lzma_ret(lzma_index_hash_append(index_hash,
    359 			three_byte_vli, three_byte_vli), LZMA_OK);
    360 
    361 	// Expected size should be:
    362 	// Index Indicator - 1 byte
    363 	// Number of Records - 1 byte
    364 	// List of Records - 10 bytes
    365 	// Index Padding - 0 bytes
    366 	// CRC32 - 4 bytes
    367 	// Total - 16 bytes
    368 	expected_size = 16;
    369 	assert_uint_eq(lzma_index_hash_size(index_hash), expected_size);
    370 
    371 	lzma_index_hash_end(index_hash, NULL);
    372 #endif
    373 }
    374 
    375 
    376 extern int
    377 main(int argc, char **argv)
    378 {
    379 	tuktest_start(argc, argv);
    380 	tuktest_run(test_lzma_index_hash_init);
    381 	tuktest_run(test_lzma_index_hash_append);
    382 	tuktest_run(test_lzma_index_hash_decode);
    383 	tuktest_run(test_lzma_index_hash_size);
    384 	return tuktest_end();
    385 }
    386