From 5121d1aed8107a113d7665b6d4f26b6187949f3d Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Mon, 31 Aug 2026 20:35:04 +0300 Subject: [PATCH] Tests: Add tests for single-call .xz encoding Thanks-to: GitHub user androvonx95 Closes: https://github.com/tukaani-project/xz/pull/231 --- tests/Makefile.am | 2 + tests/test_stream_buffer_encode.c | 264 ++++++++++++++++++++++++++++++ tests/tests.cmake | 1 + 3 files changed, 267 insertions(+) create mode 100644 tests/test_stream_buffer_encode.c diff --git a/tests/Makefile.am b/tests/Makefile.am index dd1d4056..d5e63e7f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -40,6 +40,7 @@ check_PROGRAMS = \ test_check \ test_hardware \ test_stream_buffer_decode \ + test_stream_buffer_encode \ test_stream_flags \ test_filter_flags \ test_filter_str \ @@ -55,6 +56,7 @@ TESTS = \ test_check \ test_hardware \ test_stream_buffer_decode \ + test_stream_buffer_encode \ test_stream_flags \ test_filter_flags \ test_filter_str \ diff --git a/tests/test_stream_buffer_encode.c b/tests/test_stream_buffer_encode.c new file mode 100644 index 00000000..019115fc --- /dev/null +++ b/tests/test_stream_buffer_encode.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: 0BSD + +/////////////////////////////////////////////////////////////////////////////// +// +/// \file test_stream_buffer_encode.c +/// \brief Test single-call .xz encoding +// +// Author: Lasse Collin +// +/////////////////////////////////////////////////////////////////////////////// + +#include "tests.h" + + +/// LZMA2 preset to use +#define PRESET 1 + +/// Memory usage limit for decompression +#define MEMLIMIT (2U << 20) + + +#ifdef HAVE_ENCODERS +/// Compressible data (also with delta:dist=1) +static const uint8_t compressible[] + = { 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4 }; + +// Incompressible data (also with delta:dist=1) +static const uint8_t incompressible[] = { 1, 3, 7 }; +#endif + + +static void +test_stream_buffer_bound(void) +{ +#ifndef HAVE_ENCODERS + assert_skip("Encoder support is disabled"); +#else + size_t bound; + + bound = lzma_stream_buffer_bound(0); + assert_uint(bound, >, 2 * LZMA_STREAM_HEADER_SIZE); + assert_uint(bound, <, 222); + + bound = lzma_stream_buffer_bound(123); + assert_uint(bound, >, 2 * LZMA_STREAM_HEADER_SIZE + 123); + assert_uint(bound, <, 333); + + bound = lzma_stream_buffer_bound(SIZE_MAX - 123); + assert_uint_eq(bound, 0); + + bound = lzma_stream_buffer_bound(SIZE_MAX); + assert_uint_eq(bound, 0); +#endif +} + + +#ifdef HAVE_ENCODERS +static void +decompress_and_compare(const uint8_t *in, size_t in_size, + const uint8_t *uncomp, size_t uncomp_size) +{ +#ifndef HAVE_DECODERS + (void)in; + (void)in_size; + (void)uncomp; + (void)uncomp_size; +#else + uint8_t out[512] = { 0 }; + assert_uint(uncomp_size, <=, sizeof(out)); + + uint64_t memlimit = MEMLIMIT; + size_t in_pos = 0; + size_t out_pos = 0; + assert_lzma_ret(lzma_stream_buffer_decode(&memlimit, 0, NULL, + in, &in_pos, in_size, out, &out_pos, sizeof(out)), + LZMA_OK); + assert_uint_eq(in_pos, in_size); + assert_uint_eq(out_pos, uncomp_size); + assert_array_eq(out, uncomp, uncomp_size); +#endif +} +#endif + + +static void +test_easy_buffer_encode(void) +{ +#ifndef HAVE_ENCODERS + assert_skip("Encoder support is disabled"); +#else + uint8_t out[512] = { 0 }; + size_t out_pos; + size_t bound; + + // Test with compressible data. + bound = lzma_stream_buffer_bound(sizeof(compressible)); + assert_uint(bound, >, 2 * LZMA_STREAM_HEADER_SIZE); + assert_uint(bound, <, sizeof(out)); + out_pos = 0; + assert_lzma_ret(lzma_easy_buffer_encode( + PRESET, LZMA_CHECK_CRC32, NULL, + compressible, sizeof(compressible), + out, &out_pos, bound), LZMA_OK); + assert_uint(out_pos, >, 2 * LZMA_STREAM_HEADER_SIZE); + // It's compressible, thus <. + assert_uint(out_pos, <, bound); + decompress_and_compare(out, out_pos, + compressible, sizeof(compressible)); + + // Test with incompressible data. + bound = lzma_stream_buffer_bound(sizeof(incompressible)); + assert_uint(bound, >, 2 * LZMA_STREAM_HEADER_SIZE); + assert_uint(bound, <, sizeof(out)); + out_pos = 0; + assert_lzma_ret(lzma_easy_buffer_encode( + PRESET, LZMA_CHECK_CRC32, NULL, + incompressible, sizeof(incompressible), + out, &out_pos, bound), LZMA_OK); + assert_uint(out_pos, >, 2 * LZMA_STREAM_HEADER_SIZE); + assert_uint(out_pos, <=, bound); + decompress_and_compare(out, out_pos, + incompressible, sizeof(incompressible)); + + // Test with too little output space. + bound = out_pos; + out_pos = 1; + assert_lzma_ret(lzma_easy_buffer_encode( + PRESET, LZMA_CHECK_CRC32, NULL, + incompressible, sizeof(incompressible), + out, &out_pos, bound), LZMA_BUF_ERROR); + assert_uint_eq(out_pos, 1); + + // Test with unsupported or invalid arguments. + assert_lzma_ret(lzma_easy_buffer_encode( + 555, LZMA_CHECK_CRC32, NULL, + incompressible, sizeof(incompressible), + out, &out_pos, bound), LZMA_OPTIONS_ERROR); + assert_uint_eq(out_pos, 1); + + assert_lzma_ret(lzma_easy_buffer_encode( + PRESET, INVALID_LZMA_CHECK_ID, NULL, + incompressible, sizeof(incompressible), + out, &out_pos, bound), LZMA_PROG_ERROR); + assert_uint_eq(out_pos, 1); + + assert_lzma_ret(lzma_easy_buffer_encode( + PRESET, (lzma_check)15, NULL, + incompressible, sizeof(incompressible), + out, &out_pos, bound), LZMA_UNSUPPORTED_CHECK); + assert_uint_eq(out_pos, 1); + + assert_lzma_ret(lzma_easy_buffer_encode( + PRESET, LZMA_CHECK_CRC32, NULL, + NULL, sizeof(incompressible), + out, &out_pos, bound), LZMA_PROG_ERROR); + assert_uint_eq(out_pos, 1); + + assert_lzma_ret(lzma_easy_buffer_encode( + PRESET, LZMA_CHECK_CRC32, NULL, + incompressible, sizeof(incompressible), + NULL, &out_pos, bound), LZMA_PROG_ERROR); + assert_uint_eq(out_pos, 1); + + assert_lzma_ret(lzma_easy_buffer_encode( + PRESET, LZMA_CHECK_CRC32, NULL, + incompressible, sizeof(incompressible), + out, NULL, bound), LZMA_PROG_ERROR); + assert_uint_eq(out_pos, 1); + + out_pos = bound + 1; + assert_lzma_ret(lzma_easy_buffer_encode( + PRESET, LZMA_CHECK_CRC32, NULL, + incompressible, sizeof(incompressible), + out, &out_pos, bound), LZMA_PROG_ERROR); + assert_uint_eq(out_pos, bound + 1); +#endif +} + + +static void +test_stream_buffer_encode(void) +{ +#if !defined(HAVE_ENCODER_DELTA) || !defined(HAVE_DECODER_DELTA) + assert_skip("Delta encoder or decoder support is disabled"); +#else + uint8_t out[512] = { 0 }; + size_t out_pos; + size_t bound; + + lzma_options_delta opt_delta = { .dist = 1 }; + lzma_options_lzma opt_lzma2; + assert_uint_eq(lzma_lzma_preset(&opt_lzma2, PRESET), false); + lzma_filter filters[] = { + { LZMA_FILTER_DELTA, &opt_delta }, + { LZMA_FILTER_LZMA2, &opt_lzma2 }, + { LZMA_VLI_UNKNOWN, NULL } + }; + + // Test with compressible data. + bound = lzma_stream_buffer_bound(sizeof(compressible)); + assert_uint(bound, >, 2 * LZMA_STREAM_HEADER_SIZE); + assert_uint(bound, <, sizeof(out)); + out_pos = 0; + assert_lzma_ret(lzma_stream_buffer_encode( + filters, LZMA_CHECK_CRC32, NULL, + compressible, sizeof(compressible), + out, &out_pos, bound), LZMA_OK); + assert_uint(out_pos, >, 2 * LZMA_STREAM_HEADER_SIZE); + // It's compressible even with the Delta filter, thus <. + assert_uint(out_pos, <, bound); + decompress_and_compare(out, out_pos, + compressible, sizeof(compressible)); + + // Test with incompressible data. + bound = lzma_stream_buffer_bound(sizeof(incompressible)); + assert_uint(bound, >, 2 * LZMA_STREAM_HEADER_SIZE); + assert_uint(bound, <, sizeof(out)); + out_pos = 0; + assert_lzma_ret(lzma_stream_buffer_encode( + filters, LZMA_CHECK_CRC32, NULL, + incompressible, sizeof(incompressible), + out, &out_pos, bound), LZMA_OK); + assert_uint(out_pos, >, 2 * LZMA_STREAM_HEADER_SIZE); + assert_uint(out_pos, <=, bound); + decompress_and_compare(out, out_pos, + incompressible, sizeof(incompressible)); + + // Test with too little output space. + bound = out_pos; + out_pos = 1; + assert_lzma_ret(lzma_stream_buffer_encode( + filters, LZMA_CHECK_CRC32, NULL, + incompressible, sizeof(incompressible), + out, &out_pos, bound), LZMA_BUF_ERROR); + assert_uint_eq(out_pos, 1); + + // Test with unsupported or invalid arguments. + assert_lzma_ret(lzma_stream_buffer_encode( + NULL, LZMA_CHECK_CRC32, NULL, + incompressible, sizeof(incompressible), + out, &out_pos, bound), LZMA_PROG_ERROR); + assert_uint_eq(out_pos, 1); + + filters[0].id = 5555; + assert_lzma_ret(lzma_stream_buffer_encode( + filters, LZMA_CHECK_CRC32, NULL, + incompressible, sizeof(incompressible), + out, &out_pos, bound), LZMA_OPTIONS_ERROR); + assert_uint_eq(out_pos, 1); +#endif +} + + +extern int +main(int argc, char **argv) +{ + tuktest_start(argc, argv); + + tuktest_run(test_stream_buffer_bound); + tuktest_run(test_easy_buffer_encode); + tuktest_run(test_stream_buffer_encode); + + return tuktest_end(); +} diff --git a/tests/tests.cmake b/tests/tests.cmake index e60d1a2d..d67fbc39 100644 --- a/tests/tests.cmake +++ b/tests/tests.cmake @@ -62,6 +62,7 @@ if(BUILD_TESTING) test_lzip_decoder test_memlimit test_stream_buffer_decode + test_stream_buffer_encode test_stream_flags test_vli )