Home | History | Annotate | Line # | Download | only in tests
      1  1.1  christos // SPDX-License-Identifier: 0BSD
      2  1.1  christos 
      3  1.1  christos ///////////////////////////////////////////////////////////////////////////////
      4  1.1  christos //
      5  1.1  christos /// \file       test_microlzma.c
      6  1.1  christos /// \brief      Tests MicroLZMA encoding and decoding
      7  1.1  christos //
      8  1.1  christos //  Author:     Jia Tan
      9  1.1  christos //
     10  1.1  christos ///////////////////////////////////////////////////////////////////////////////
     11  1.1  christos 
     12  1.1  christos #include "tests.h"
     13  1.1  christos 
     14  1.1  christos #define BUFFER_SIZE 1024
     15  1.1  christos 
     16  1.1  christos 
     17  1.1  christos #ifdef HAVE_ENCODER_LZMA1
     18  1.1  christos 
     19  1.1  christos // MicroLZMA encoded "Hello\nWorld\n" output size in bytes.
     20  1.1  christos #define ENCODED_OUTPUT_SIZE 17
     21  1.1  christos 
     22  1.1  christos // Byte array of "Hello\nWorld\n". This is used for various encoder tests.
     23  1.1  christos static const uint8_t hello_world[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A,
     24  1.1  christos 		0x57, 0x6F, 0x72, 0x6C, 0x64, 0x0A };
     25  1.1  christos 
     26  1.1  christos // This is the CRC32 value of the MicroLZMA encoding of "Hello\nWorld\n".
     27  1.1  christos // The settings used were based on LZMA_PRESET_DEFAULT as of liblzma 5.6.0.
     28  1.1  christos // This assumes MicroLZMA is correct in liblzma 5.6.0, which is safe
     29  1.1  christos // considering the encoded "Hello\nWorld\n" can successfully be decoded at
     30  1.1  christos // this time. This is to test for regressions that cause MicroLZMA output
     31  1.1  christos // to change.
     32  1.1  christos static const uint32_t hello_world_encoded_crc = 0x3CDE40A8;
     33  1.1  christos 
     34  1.1  christos 
     35  1.1  christos // Function implementation borrowed from lzma_decoder.c. It is needed to
     36  1.1  christos // ensure the first byte of a MicroLZMA stream is set correctly with the
     37  1.1  christos // negation of the LZMA properties.
     38  1.1  christos static bool
     39  1.1  christos lzma_lzma_lclppb_decode(lzma_options_lzma *options, uint8_t byte)
     40  1.1  christos {
     41  1.1  christos 	if (byte > (4 * 5 + 4) * 9 + 8)
     42  1.1  christos 		return true;
     43  1.1  christos 
     44  1.1  christos 	// See the file format specification to understand this.
     45  1.1  christos 	options->pb = byte / (9 * 5);
     46  1.1  christos 	byte -= options->pb * 9 * 5;
     47  1.1  christos 	options->lp = byte / 9;
     48  1.1  christos 	options->lc = byte - options->lp * 9;
     49  1.1  christos 
     50  1.1  christos 	return options->lc + options->lp > LZMA_LCLP_MAX;
     51  1.1  christos }
     52  1.1  christos 
     53  1.1  christos 
     54  1.1  christos ///////////////////
     55  1.1  christos // Encoder tests //
     56  1.1  christos ///////////////////
     57  1.1  christos 
     58  1.1  christos // This tests a few of the basic options. These options are not unique to
     59  1.1  christos // MicroLZMA in any way, its mostly ensuring that the options are actually
     60  1.1  christos // being checked before initializing the decoder internals.
     61  1.1  christos static void
     62  1.1  christos test_encode_options(void)
     63  1.1  christos {
     64  1.1  christos 	lzma_stream strm = LZMA_STREAM_INIT;
     65  1.1  christos 	lzma_options_lzma opt_lzma;
     66  1.1  christos 
     67  1.1  christos 	// Initialize with default options.
     68  1.1  christos 	assert_false(lzma_lzma_preset(&opt_lzma, LZMA_PRESET_DEFAULT));
     69  1.1  christos 
     70  1.1  christos 	// NULL stream
     71  1.1  christos 	assert_lzma_ret(lzma_microlzma_encoder(NULL, &opt_lzma),
     72  1.1  christos 			LZMA_PROG_ERROR);
     73  1.1  christos 
     74  1.1  christos 	// lc/lp/pb = 5/0/2 (lc invalid)
     75  1.1  christos 	opt_lzma.lc = 5;
     76  1.1  christos 	opt_lzma.lp = 0;
     77  1.1  christos 	opt_lzma.pb = 2;
     78  1.1  christos 	assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma),
     79  1.1  christos 			LZMA_OPTIONS_ERROR);
     80  1.1  christos 
     81  1.1  christos 	// lc/lp/pb = 0/5/2 (lp invalid)
     82  1.1  christos 	opt_lzma.lc = 0;
     83  1.1  christos 	opt_lzma.lp = 5;
     84  1.1  christos 	opt_lzma.pb = 2;
     85  1.1  christos 	assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma),
     86  1.1  christos 			LZMA_OPTIONS_ERROR);
     87  1.1  christos 
     88  1.1  christos 	// lc/lp/pb = 3/2/2 (lc + lp invalid)
     89  1.1  christos 	opt_lzma.lc = 3;
     90  1.1  christos 	opt_lzma.lp = 2;
     91  1.1  christos 	opt_lzma.pb = 2;
     92  1.1  christos 	assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma),
     93  1.1  christos 			LZMA_OPTIONS_ERROR);
     94  1.1  christos 
     95  1.1  christos 	// lc/lp/pb = 3/0/5 (pb invalid)
     96  1.1  christos 	opt_lzma.lc = 3;
     97  1.1  christos 	opt_lzma.lp = 0;
     98  1.1  christos 	opt_lzma.pb = 5;
     99  1.1  christos 	assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma),
    100  1.1  christos 			LZMA_OPTIONS_ERROR);
    101  1.1  christos 
    102  1.1  christos 	// Zero out lp, pb, lc options to not interfere with later tests.
    103  1.1  christos 	opt_lzma.lp = 0;
    104  1.1  christos 	opt_lzma.pb = 0;
    105  1.1  christos 	opt_lzma.lc = 0;
    106  1.1  christos 
    107  1.1  christos 	// Set invalid dictionary size.
    108  1.1  christos 	opt_lzma.dict_size = LZMA_DICT_SIZE_MIN - 1;
    109  1.1  christos 	assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma),
    110  1.1  christos 			LZMA_OPTIONS_ERROR);
    111  1.1  christos 
    112  1.1  christos 	// Maximum dictionary size for the encoder, as described in lzma12.h
    113  1.1  christos 	// is 1.5 GiB.
    114  1.1  christos 	opt_lzma.dict_size = (UINT32_C(1) << 30) + (UINT32_C(1) << 29) + 1;
    115  1.1  christos 	assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma),
    116  1.1  christos 			LZMA_OPTIONS_ERROR);
    117  1.1  christos 
    118  1.1  christos 	lzma_end(&strm);
    119  1.1  christos }
    120  1.1  christos 
    121  1.1  christos 
    122  1.1  christos static void
    123  1.1  christos test_encode_basic(void)
    124  1.1  christos {
    125  1.1  christos 	lzma_stream strm = LZMA_STREAM_INIT;
    126  1.1  christos 	lzma_options_lzma opt_lzma;
    127  1.1  christos 
    128  1.1  christos 	// The lzma_lzma_preset return value is inverse of what it perhaps
    129  1.1  christos 	// should be, that is, it returns false on success.
    130  1.1  christos 	assert_false(lzma_lzma_preset(&opt_lzma, LZMA_PRESET_DEFAULT));
    131  1.1  christos 
    132  1.1  christos 	// Initialize the encoder using the default options.
    133  1.1  christos 	assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), LZMA_OK);
    134  1.1  christos 
    135  1.1  christos 	uint8_t output[BUFFER_SIZE];
    136  1.1  christos 
    137  1.1  christos 	strm.next_in = hello_world;
    138  1.1  christos 	strm.avail_in = sizeof(hello_world);
    139  1.1  christos 	strm.next_out = output;
    140  1.1  christos 	strm.avail_out = sizeof(output);
    141  1.1  christos 
    142  1.1  christos 	// Everything must be encoded in one lzma_code() call.
    143  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
    144  1.1  christos 
    145  1.1  christos 	// Check that the entire input was consumed.
    146  1.1  christos 	assert_uint_eq(strm.total_in, sizeof(hello_world));
    147  1.1  christos 
    148  1.1  christos 	// Check that the first byte in the output stream is not 0x00.
    149  1.1  christos 	// In a regular raw LZMA stream the first byte is always 0x00.
    150  1.1  christos 	// In MicroLZMA the first byte replaced by the bitwise-negation
    151  1.1  christos 	// of the LZMA properties.
    152  1.1  christos 	assert_uint(output[0], !=, 0x00);
    153  1.1  christos 
    154  1.1  christos 	const uint8_t props = ~output[0];
    155  1.1  christos 
    156  1.1  christos 	lzma_options_lzma test_options;
    157  1.1  christos 	assert_false(lzma_lzma_lclppb_decode(&test_options, props));
    158  1.1  christos 
    159  1.1  christos 	assert_uint_eq(opt_lzma.lc, test_options.lc);
    160  1.1  christos 	assert_uint_eq(opt_lzma.lp, test_options.lp);
    161  1.1  christos 	assert_uint_eq(opt_lzma.pb, test_options.pb);
    162  1.1  christos 
    163  1.1  christos 	// Compute the check over the output data. This is compared to
    164  1.1  christos 	// the expected check value.
    165  1.1  christos 	const uint32_t check_val = lzma_crc32(output, strm.total_out, 0);
    166  1.1  christos 
    167  1.1  christos 	assert_uint_eq(check_val, hello_world_encoded_crc);
    168  1.1  christos 
    169  1.1  christos 	lzma_end(&strm);
    170  1.1  christos }
    171  1.1  christos 
    172  1.1  christos 
    173  1.1  christos // This tests the behavior when strm.avail_out is so small it cannot hold
    174  1.1  christos // the header plus 1 encoded byte (< 6).
    175  1.1  christos static void
    176  1.1  christos test_encode_small_out(void)
    177  1.1  christos {
    178  1.1  christos 	lzma_stream strm = LZMA_STREAM_INIT;
    179  1.1  christos 	lzma_options_lzma opt_lzma;
    180  1.1  christos 
    181  1.1  christos 	assert_false(lzma_lzma_preset(&opt_lzma, LZMA_PRESET_DEFAULT));
    182  1.1  christos 
    183  1.1  christos 	assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), LZMA_OK);
    184  1.1  christos 
    185  1.1  christos 	uint8_t output[BUFFER_SIZE];
    186  1.1  christos 
    187  1.1  christos 	strm.next_in = hello_world;
    188  1.1  christos 	strm.avail_in = sizeof(hello_world);
    189  1.1  christos 	strm.next_out = output;
    190  1.1  christos 	strm.avail_out = 5;
    191  1.1  christos 
    192  1.1  christos 	// LZMA_PROG_ERROR is expected when strm.avail_out < 6
    193  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_PROG_ERROR);
    194  1.1  christos 
    195  1.1  christos 	// The encoder must be reset because coders cannot be used again
    196  1.1  christos 	// after returning LZMA_PROG_ERROR.
    197  1.1  christos 	assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma), LZMA_OK);
    198  1.1  christos 
    199  1.1  christos 	// Reset strm.avail_out to be > 6, but not enough to hold all of the
    200  1.1  christos 	// compressed data.
    201  1.1  christos 	strm.avail_out = ENCODED_OUTPUT_SIZE - 1;
    202  1.1  christos 
    203  1.1  christos 	// Encoding should not return an error now.
    204  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
    205  1.1  christos 	assert_uint(strm.total_in, <, sizeof(hello_world));
    206  1.1  christos 
    207  1.1  christos 	lzma_end(&strm);
    208  1.1  christos }
    209  1.1  christos 
    210  1.1  christos 
    211  1.1  christos // LZMA_FINISH is the only supported action. All others must
    212  1.1  christos // return LZMA_PROG_ERROR.
    213  1.1  christos static void
    214  1.1  christos test_encode_actions(void)
    215  1.1  christos {
    216  1.1  christos 	lzma_stream strm = LZMA_STREAM_INIT;
    217  1.1  christos 	lzma_options_lzma opt_lzma;
    218  1.1  christos 
    219  1.1  christos 	assert_false(lzma_lzma_preset(&opt_lzma, LZMA_PRESET_DEFAULT));
    220  1.1  christos 
    221  1.1  christos 	const lzma_action actions[] = {
    222  1.1  christos 		LZMA_RUN,
    223  1.1  christos 		LZMA_SYNC_FLUSH,
    224  1.1  christos 		LZMA_FULL_FLUSH,
    225  1.1  christos 		LZMA_FULL_BARRIER,
    226  1.1  christos 	};
    227  1.1  christos 
    228  1.1  christos 	for (size_t i = 0; i < ARRAY_SIZE(actions); ++i) {
    229  1.1  christos 		assert_lzma_ret(lzma_microlzma_encoder(&strm, &opt_lzma),
    230  1.1  christos 				LZMA_OK);
    231  1.1  christos 
    232  1.1  christos 		uint8_t output[BUFFER_SIZE];
    233  1.1  christos 
    234  1.1  christos 		strm.next_in = hello_world;
    235  1.1  christos 		strm.avail_in = sizeof(hello_world);
    236  1.1  christos 		strm.next_out = output;
    237  1.1  christos 		strm.avail_out = sizeof(output);
    238  1.1  christos 
    239  1.1  christos 		assert_lzma_ret(lzma_code(&strm, actions[i]),
    240  1.1  christos 				LZMA_PROG_ERROR);
    241  1.1  christos 	}
    242  1.1  christos 
    243  1.1  christos 	lzma_end(&strm);
    244  1.1  christos }
    245  1.1  christos #endif // HAVE_ENCODER_LZMA1
    246  1.1  christos 
    247  1.1  christos 
    248  1.1  christos ///////////////////
    249  1.1  christos // Decoder tests //
    250  1.1  christos ///////////////////
    251  1.1  christos 
    252  1.1  christos #if defined(HAVE_DECODER_LZMA1) && defined(HAVE_ENCODER_LZMA1)
    253  1.1  christos 
    254  1.1  christos // Byte array of "Goodbye World!". This is used for various decoder tests.
    255  1.1  christos static const uint8_t goodbye_world[] = { 0x47, 0x6F, 0x6F, 0x64, 0x62,
    256  1.1  christos 		0x79, 0x65, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21 };
    257  1.1  christos 
    258  1.1  christos static uint8_t *goodbye_world_encoded = NULL;
    259  1.1  christos static size_t goodbye_world_encoded_size = 0;
    260  1.1  christos 
    261  1.1  christos 
    262  1.1  christos // Helper function to encode data and return the compressed size.
    263  1.1  christos static size_t
    264  1.1  christos basic_microlzma_encode(const uint8_t *input, size_t in_size,
    265  1.1  christos 		uint8_t **compressed)
    266  1.1  christos {
    267  1.1  christos 	lzma_stream strm = LZMA_STREAM_INIT;
    268  1.1  christos 	lzma_options_lzma opt_lzma;
    269  1.1  christos 
    270  1.1  christos 	// Lazy way to set the output size since the input should never
    271  1.1  christos 	// inflate by much in these simple test cases. This is tested to
    272  1.1  christos 	// be large enough after encoding to fit the entire input, so if
    273  1.1  christos 	// this assumption does not hold then this will fail.
    274  1.1  christos 	const size_t out_size = in_size << 1;
    275  1.1  christos 
    276  1.1  christos 	*compressed = tuktest_malloc(out_size);
    277  1.1  christos 
    278  1.1  christos 	// Always encode with the default options for simplicity.
    279  1.1  christos 	if (lzma_lzma_preset(&opt_lzma, LZMA_PRESET_DEFAULT))
    280  1.1  christos 		goto decoder_setup_error;
    281  1.1  christos 
    282  1.1  christos 	if (lzma_microlzma_encoder(&strm, &opt_lzma) != LZMA_OK)
    283  1.1  christos 		goto decoder_setup_error;
    284  1.1  christos 
    285  1.1  christos 	strm.next_in = input;
    286  1.1  christos 	strm.avail_in = in_size;
    287  1.1  christos 	strm.next_out = *compressed;
    288  1.1  christos 	strm.avail_out = out_size;
    289  1.1  christos 
    290  1.1  christos 	if (lzma_code(&strm, LZMA_FINISH) != LZMA_STREAM_END)
    291  1.1  christos 		goto decoder_setup_error;
    292  1.1  christos 
    293  1.1  christos 	// Check that the entire input was consumed and that it fit into
    294  1.1  christos 	// the output buffer.
    295  1.1  christos 	if (strm.total_in != in_size)
    296  1.1  christos 		goto decoder_setup_error;
    297  1.1  christos 
    298  1.1  christos 	lzma_end(&strm);
    299  1.1  christos 
    300  1.1  christos 	// lzma_end() doesn't touch other members of lzma_stream than
    301  1.1  christos 	// lzma_stream.internal so using strm.total_out here is fine.
    302  1.1  christos 	return strm.total_out;
    303  1.1  christos 
    304  1.1  christos decoder_setup_error:
    305  1.1  christos 	tuktest_error("Failed to initialize decoder tests");
    306  1.1  christos 	return 0;
    307  1.1  christos }
    308  1.1  christos 
    309  1.1  christos 
    310  1.1  christos static void
    311  1.1  christos test_decode_options(void)
    312  1.1  christos {
    313  1.1  christos 	// NULL stream
    314  1.1  christos 	assert_lzma_ret(lzma_microlzma_decoder(NULL, BUFFER_SIZE,
    315  1.1  christos 			sizeof(hello_world), true,
    316  1.1  christos 			LZMA_DICT_SIZE_DEFAULT), LZMA_PROG_ERROR);
    317  1.1  christos 
    318  1.1  christos 	// Uncompressed size larger than max
    319  1.1  christos 	lzma_stream strm = LZMA_STREAM_INIT;
    320  1.1  christos 	assert_lzma_ret(lzma_microlzma_decoder(&strm, BUFFER_SIZE,
    321  1.1  christos 			LZMA_VLI_MAX + 1, true, LZMA_DICT_SIZE_DEFAULT),
    322  1.1  christos 			LZMA_OPTIONS_ERROR);
    323  1.1  christos }
    324  1.1  christos 
    325  1.1  christos 
    326  1.1  christos // Test that decoding succeeds when uncomp_size is correct regardless of
    327  1.1  christos // the value of uncomp_size_is_exact.
    328  1.1  christos static void
    329  1.1  christos test_decode_uncomp_size_is_exact(void)
    330  1.1  christos {
    331  1.1  christos 	lzma_stream strm = LZMA_STREAM_INIT;
    332  1.1  christos 
    333  1.1  christos 	assert_lzma_ret(lzma_microlzma_decoder(&strm,
    334  1.1  christos 			goodbye_world_encoded_size,
    335  1.1  christos 			sizeof(goodbye_world), true,
    336  1.1  christos 			LZMA_DICT_SIZE_DEFAULT), LZMA_OK);
    337  1.1  christos 
    338  1.1  christos 	uint8_t output[BUFFER_SIZE];
    339  1.1  christos 
    340  1.1  christos 	strm.next_in = goodbye_world_encoded;
    341  1.1  christos 	strm.avail_in = goodbye_world_encoded_size;
    342  1.1  christos 	strm.next_out = output;
    343  1.1  christos 	strm.avail_out = sizeof(output);
    344  1.1  christos 
    345  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
    346  1.1  christos 	assert_uint_eq(strm.total_in, goodbye_world_encoded_size);
    347  1.1  christos 
    348  1.1  christos 	assert_uint_eq(strm.total_out, sizeof(goodbye_world));
    349  1.1  christos 	assert_array_eq(goodbye_world, output, sizeof(goodbye_world));
    350  1.1  christos 
    351  1.1  christos 	// Reset decoder with uncomp_size_is_exact set to false and
    352  1.1  christos 	// uncomp_size set to correct value. Also test using the
    353  1.1  christos 	// uncompressed size as the dictionary size.
    354  1.1  christos 	assert_lzma_ret(lzma_microlzma_decoder(&strm,
    355  1.1  christos 			goodbye_world_encoded_size,
    356  1.1  christos 			sizeof(goodbye_world), false,
    357  1.1  christos 			sizeof(goodbye_world)), LZMA_OK);
    358  1.1  christos 
    359  1.1  christos 	strm.next_in = goodbye_world_encoded;
    360  1.1  christos 	strm.avail_in = goodbye_world_encoded_size;
    361  1.1  christos 	strm.next_out = output;
    362  1.1  christos 	strm.avail_out = sizeof(output);
    363  1.1  christos 
    364  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
    365  1.1  christos 	assert_uint_eq(strm.total_in, goodbye_world_encoded_size);
    366  1.1  christos 
    367  1.1  christos 	assert_uint_eq(strm.total_out, sizeof(goodbye_world));
    368  1.1  christos 	assert_array_eq(goodbye_world, output, sizeof(goodbye_world));
    369  1.1  christos 
    370  1.1  christos 	lzma_end(&strm);
    371  1.1  christos }
    372  1.1  christos 
    373  1.1  christos 
    374  1.1  christos // This tests decoding when MicroLZMA decoder is called with
    375  1.1  christos // an incorrect uncompressed size.
    376  1.1  christos static void
    377  1.1  christos test_decode_uncomp_size_wrong(void)
    378  1.1  christos {
    379  1.1  christos 	lzma_stream strm = LZMA_STREAM_INIT;
    380  1.1  christos 	assert_lzma_ret(lzma_microlzma_decoder(&strm,
    381  1.1  christos 			goodbye_world_encoded_size,
    382  1.1  christos 			sizeof(goodbye_world) + 1, false,
    383  1.1  christos 			LZMA_DICT_SIZE_DEFAULT), LZMA_OK);
    384  1.1  christos 
    385  1.1  christos 	uint8_t output[BUFFER_SIZE];
    386  1.1  christos 
    387  1.1  christos 	strm.next_in = goodbye_world_encoded;
    388  1.1  christos 	strm.avail_in = goodbye_world_encoded_size;
    389  1.1  christos 	strm.next_out = output;
    390  1.1  christos 	strm.avail_out = sizeof(output);
    391  1.1  christos 
    392  1.1  christos 	// LZMA_OK should be returned because the input size given was
    393  1.1  christos 	// larger than the actual encoded size. The decoder is expecting
    394  1.1  christos 	// more input to possibly fill the uncompressed size that was set.
    395  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_OK);
    396  1.1  christos 
    397  1.1  christos 	assert_uint_eq(strm.total_out, sizeof(goodbye_world));
    398  1.1  christos 
    399  1.1  christos 	assert_array_eq(goodbye_world, output, sizeof(goodbye_world));
    400  1.1  christos 
    401  1.1  christos 	// Next, test with uncomp_size_is_exact set.
    402  1.1  christos 	assert_lzma_ret(lzma_microlzma_decoder(&strm,
    403  1.1  christos 			goodbye_world_encoded_size,
    404  1.1  christos 			sizeof(goodbye_world) + 1, true,
    405  1.1  christos 			LZMA_DICT_SIZE_DEFAULT), LZMA_OK);
    406  1.1  christos 
    407  1.1  christos 	strm.next_in = goodbye_world_encoded;
    408  1.1  christos 	strm.avail_in = goodbye_world_encoded_size;
    409  1.1  christos 	strm.next_out = output;
    410  1.1  christos 	strm.avail_out = sizeof(output);
    411  1.1  christos 
    412  1.1  christos 	// No error detected, even though all input was consumed and there
    413  1.1  christos 	// is more room in the output buffer.
    414  1.1  christos 	//
    415  1.1  christos 	// FIXME? LZMA_FINISH tells that no more input is coming and
    416  1.1  christos 	// the MicroLZMA decoder knows the exact compressed size from
    417  1.1  christos 	// the initialization as well. So should it return LZMA_DATA_ERROR
    418  1.1  christos 	// on the first call instead of relying on the generic lzma_code()
    419  1.1  christos 	// logic to eventually get LZMA_BUF_ERROR?
    420  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_OK);
    421  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_OK);
    422  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_BUF_ERROR);
    423  1.1  christos 
    424  1.1  christos 	assert_uint_eq(strm.total_out, sizeof(goodbye_world));
    425  1.1  christos 	assert_array_eq(goodbye_world, output, sizeof(goodbye_world));
    426  1.1  christos 
    427  1.1  christos 	// Reset stream with uncomp_size smaller than the real
    428  1.1  christos 	// uncompressed size.
    429  1.1  christos 	assert_lzma_ret(lzma_microlzma_decoder(&strm,
    430  1.1  christos 			goodbye_world_encoded_size,
    431  1.1  christos 			ARRAY_SIZE(hello_world) - 1, true,
    432  1.1  christos 			LZMA_DICT_SIZE_DEFAULT), LZMA_OK);
    433  1.1  christos 
    434  1.1  christos 	strm.next_in = goodbye_world_encoded;
    435  1.1  christos 	strm.avail_in = goodbye_world_encoded_size;
    436  1.1  christos 	strm.next_out = output;
    437  1.1  christos 	strm.avail_out = sizeof(output);
    438  1.1  christos 
    439  1.1  christos 	// This case actually results in an error since it decodes the full
    440  1.1  christos 	// uncompressed size but the range coder is not in the proper state
    441  1.1  christos 	// for the stream to end.
    442  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_DATA_ERROR);
    443  1.1  christos 
    444  1.1  christos 	lzma_end(&strm);
    445  1.1  christos }
    446  1.1  christos 
    447  1.1  christos 
    448  1.1  christos static void
    449  1.1  christos test_decode_comp_size_wrong(void)
    450  1.1  christos {
    451  1.1  christos 	lzma_stream strm = LZMA_STREAM_INIT;
    452  1.1  christos 
    453  1.1  christos 	// goodbye_world_encoded_size + 1 is safe because extra space was
    454  1.1  christos 	// allocated for goodbye_world_encoded. The extra space isn't
    455  1.1  christos 	// initialized but it shouldn't be read either, thus Valgrind
    456  1.1  christos 	// has to remain happy with this code.
    457  1.1  christos 	assert_lzma_ret(lzma_microlzma_decoder(&strm,
    458  1.1  christos 			goodbye_world_encoded_size + 1,
    459  1.1  christos 			sizeof(goodbye_world), true,
    460  1.1  christos 			LZMA_DICT_SIZE_DEFAULT), LZMA_OK);
    461  1.1  christos 
    462  1.1  christos 	uint8_t output[BUFFER_SIZE];
    463  1.1  christos 
    464  1.1  christos 	strm.next_in = goodbye_world_encoded;
    465  1.1  christos 	strm.avail_in = goodbye_world_encoded_size;
    466  1.1  christos 	strm.next_out = output;
    467  1.1  christos 	strm.avail_out = sizeof(output);
    468  1.1  christos 
    469  1.1  christos 	// When uncomp_size_is_exact is set, the compressed size must be
    470  1.1  christos 	// correct or else LZMA_DATA_ERROR is returned.
    471  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_DATA_ERROR);
    472  1.1  christos 
    473  1.1  christos 	assert_lzma_ret(lzma_microlzma_decoder(&strm,
    474  1.1  christos 			goodbye_world_encoded_size + 1,
    475  1.1  christos 			sizeof(goodbye_world), false,
    476  1.1  christos 			LZMA_DICT_SIZE_DEFAULT), LZMA_OK);
    477  1.1  christos 
    478  1.1  christos 	strm.next_in = goodbye_world_encoded;
    479  1.1  christos 	strm.avail_in = goodbye_world_encoded_size;
    480  1.1  christos 	strm.next_out = output;
    481  1.1  christos 	strm.avail_out = sizeof(output);
    482  1.1  christos 
    483  1.1  christos 	// When uncomp_size_is_exact is not set, the decoder does not
    484  1.1  christos 	// detect when the compressed size is wrong as long as all of the
    485  1.1  christos 	// expected output has been decoded. This is because the decoder
    486  1.1  christos 	// assumes that the real uncompressed size might be bigger than
    487  1.1  christos 	// the specified value and in that case more input might be needed
    488  1.1  christos 	// as well.
    489  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
    490  1.1  christos 
    491  1.1  christos 	lzma_end(&strm);
    492  1.1  christos }
    493  1.1  christos 
    494  1.1  christos 
    495  1.1  christos static void
    496  1.1  christos test_decode_bad_lzma_properties(void)
    497  1.1  christos {
    498  1.1  christos 	// Alter first byte to encode invalid LZMA properties.
    499  1.1  christos 	uint8_t *compressed = tuktest_malloc(goodbye_world_encoded_size);
    500  1.1  christos 	memcpy(compressed, goodbye_world_encoded, goodbye_world_encoded_size);
    501  1.1  christos 
    502  1.1  christos 	// lc=3, lp=2, pb=2
    503  1.1  christos 	compressed[0] = (uint8_t)~0x6FU;
    504  1.1  christos 
    505  1.1  christos 	lzma_stream strm = LZMA_STREAM_INIT;
    506  1.1  christos 	assert_lzma_ret(lzma_microlzma_decoder(&strm,
    507  1.1  christos 			goodbye_world_encoded_size,
    508  1.1  christos 			sizeof(goodbye_world), false,
    509  1.1  christos 			LZMA_DICT_SIZE_DEFAULT), LZMA_OK);
    510  1.1  christos 
    511  1.1  christos 	uint8_t output[BUFFER_SIZE];
    512  1.1  christos 
    513  1.1  christos 	strm.next_in = compressed;
    514  1.1  christos 	strm.avail_in = goodbye_world_encoded_size;
    515  1.1  christos 	strm.next_out = output;
    516  1.1  christos 	strm.avail_out = sizeof(output);
    517  1.1  christos 
    518  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_OPTIONS_ERROR);
    519  1.1  christos 
    520  1.1  christos 	// Use valid, but incorrect LZMA properties.
    521  1.1  christos 	// lc=3, lp=1, pb=2
    522  1.1  christos 	compressed[0] = (uint8_t)~0x66;
    523  1.1  christos 
    524  1.1  christos 	assert_lzma_ret(lzma_microlzma_decoder(&strm,
    525  1.1  christos 			goodbye_world_encoded_size,
    526  1.1  christos 			ARRAY_SIZE(goodbye_world), true,
    527  1.1  christos 			LZMA_DICT_SIZE_DEFAULT), LZMA_OK);
    528  1.1  christos 
    529  1.1  christos 	strm.next_in = compressed;
    530  1.1  christos 	strm.avail_in = goodbye_world_encoded_size;
    531  1.1  christos 	strm.next_out = output;
    532  1.1  christos 	strm.avail_out = sizeof(output);
    533  1.1  christos 
    534  1.1  christos 	assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_DATA_ERROR);
    535  1.1  christos 
    536  1.1  christos 	lzma_end(&strm);
    537  1.1  christos }
    538  1.1  christos #endif
    539  1.1  christos 
    540  1.1  christos 
    541  1.1  christos extern int
    542  1.1  christos main(int argc, char **argv)
    543  1.1  christos {
    544  1.1  christos 	tuktest_start(argc, argv);
    545  1.1  christos 
    546  1.1  christos #ifndef HAVE_ENCODER_LZMA1
    547  1.1  christos 	tuktest_early_skip("LZMA1 encoder disabled");
    548  1.1  christos #else
    549  1.1  christos 	tuktest_run(test_encode_options);
    550  1.1  christos 	tuktest_run(test_encode_basic);
    551  1.1  christos 	tuktest_run(test_encode_small_out);
    552  1.1  christos 	tuktest_run(test_encode_actions);
    553  1.1  christos 
    554  1.1  christos 	// MicroLZMA decoder tests require the basic encoder functionality.
    555  1.1  christos #	ifdef HAVE_DECODER_LZMA1
    556  1.1  christos 	goodbye_world_encoded_size = basic_microlzma_encode(goodbye_world,
    557  1.1  christos 			sizeof(goodbye_world), &goodbye_world_encoded);
    558  1.1  christos 
    559  1.1  christos 	tuktest_run(test_decode_options);
    560  1.1  christos 	tuktest_run(test_decode_uncomp_size_is_exact);
    561  1.1  christos 	tuktest_run(test_decode_uncomp_size_wrong);
    562  1.1  christos 	tuktest_run(test_decode_comp_size_wrong);
    563  1.1  christos 	tuktest_run(test_decode_bad_lzma_properties);
    564  1.1  christos #	endif
    565  1.1  christos 
    566  1.1  christos 	return tuktest_end();
    567  1.1  christos #endif
    568  1.1  christos }
    569