aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/test_stream_flags.c533
1 files changed, 416 insertions, 117 deletions
diff --git a/tests/test_stream_flags.c b/tests/test_stream_flags.c
index 39304cd4..b8ec546d 100644
--- a/tests/test_stream_flags.c
+++ b/tests/test_stream_flags.c
@@ -3,7 +3,8 @@
/// \file test_stream_flags.c
/// \brief Tests Stream Header and Stream Footer coders
//
-// Author: Lasse Collin
+// Authors: Jia Tan
+// Lasse Collin
//
// This file has been put into the public domain.
// You can do whatever you want with this file.
@@ -13,168 +14,466 @@
#include "tests.h"
-static lzma_stream_flags known_flags;
-static lzma_stream_flags decoded_flags;
-static uint8_t buffer[LZMA_STREAM_HEADER_SIZE];
+// Size of the Stream Flags field
+// (taken from src/liblzma/common/stream_flags_common.h)
+#define XZ_STREAM_FLAGS_SIZE 2
+#ifdef HAVE_ENCODERS
+// Header and footer magic bytes for .xz file format
+// (taken from src/liblzma/common/stream_flags_common.c)
+static const uint8_t xz_header_magic[6]
+ = { 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00 };
+static const uint8_t xz_footer_magic[2] = { 0x59, 0x5A };
+#endif
-static bool
-validate(void)
+
+#ifdef HAVE_ENCODERS
+static void
+stream_header_encode_helper(lzma_check check)
{
- // TODO: This could require the specific error type as an argument.
- // We could also test that lzma_stream_flags_compare() gives
- // the correct return values in different situations.
- return lzma_stream_flags_compare(&known_flags, &decoded_flags)
- != LZMA_OK;
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = check,
+ };
+
+ uint8_t header[LZMA_STREAM_HEADER_SIZE];
+
+ // Encode Stream Header
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
+
+ // Stream Header must start with Header Magic Bytes
+ const uint32_t magic_size = sizeof(xz_header_magic);
+ assert_array_eq(header, xz_header_magic, magic_size);
+
+ // Next must come Stream Flags
+ const uint8_t *encoded_stream_flags = header + magic_size;
+
+ // First byte is always null-byte.
+ // Second byte must have the Check ID in the lowest four bits
+ // and the highest four bits zero.
+ const uint8_t expected_stream_flags[] = { 0, check };
+ assert_array_eq(encoded_stream_flags, expected_stream_flags,
+ XZ_STREAM_FLAGS_SIZE);
+
+ // Last part is the CRC32 of the Stream Flags
+ const uint8_t *crc_ptr = encoded_stream_flags + XZ_STREAM_FLAGS_SIZE;
+ const uint32_t expected_crc = lzma_crc32(expected_stream_flags,
+ XZ_STREAM_FLAGS_SIZE, 0);
+ assert_uint_eq(read32le(crc_ptr), expected_crc);
}
+#endif
-static bool
-test_header_decoder(lzma_ret expected_ret)
+static void
+test_lzma_stream_header_encode(void)
{
- memcrap(&decoded_flags, sizeof(decoded_flags));
-
- if (lzma_stream_header_decode(&decoded_flags, buffer) != expected_ret)
- return true;
+#ifndef HAVE_ENCODERS
+ assert_skip("Encoder support disabled");
+#else
+ for (int i = 0; i < LZMA_CHECK_ID_MAX; i++)
+ stream_header_encode_helper(i);
+
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = LZMA_CHECK_CRC32
+ };
+
+ uint8_t header[LZMA_STREAM_HEADER_SIZE];
+
+ // Should fail if version > 0
+ flags.version = 1;
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header),
+ LZMA_OPTIONS_ERROR);
+ flags.version = 0;
+
+ // Should fail if Check ID is invalid
+ flags.check = LZMA_CHECK_ID_MAX + 1;
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header),
+ LZMA_PROG_ERROR);
+ flags.check = LZMA_CHECK_CRC32;
+
+ // Should pass even if Backward Size is invalid
+ // because Stream Header doesn't have that field.
+ flags.backward_size = LZMA_VLI_MAX + 1;
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
+#endif
+}
- if (expected_ret != LZMA_OK)
- return false;
- // Header doesn't have Backward Size, so make
- // lzma_stream_flags_compare() ignore it.
- decoded_flags.backward_size = LZMA_VLI_UNKNOWN;
- return validate();
+#if defined(HAVE_ENCODERS)
+static void
+stream_footer_encode_helper(lzma_check check)
+{
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = check,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ };
+
+ uint8_t footer[LZMA_STREAM_HEADER_SIZE];
+
+ // Encode Stream Footer
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer), LZMA_OK);
+
+ // Stream Footer must start with CRC32
+ const uint32_t crc = read32le(footer);
+ const uint32_t expected_crc = lzma_crc32(footer + sizeof(uint32_t),
+ LZMA_STREAM_HEADER_SIZE - (sizeof(uint32_t) +
+ sizeof(xz_footer_magic)), 0);
+ assert_uint_eq(crc, expected_crc);
+
+ // Next the Backward Size
+ const uint32_t backwards_size = read32le(footer + sizeof(uint32_t));
+ const uint32_t expected_backwards_size = flags.backward_size / 4 - 1;
+ assert_uint_eq(backwards_size, expected_backwards_size);
+
+ // Next the Stream Flags
+ const uint8_t *stream_flags = footer + sizeof(uint32_t) * 2;
+
+ // First byte must be null
+ assert_uint_eq(stream_flags[0], 0);
+
+ // Second byte must have the Check ID in the lowest four bits
+ // and the highest four bits zero.
+ assert_uint_eq(stream_flags[1], check);
+
+ // And ends with Footer Magic Bytes
+ const uint8_t *expected_footer_magic = stream_flags +
+ XZ_STREAM_FLAGS_SIZE;
+ assert_array_eq(expected_footer_magic, xz_footer_magic,
+ sizeof(xz_footer_magic));
}
+#endif
static void
-test_header(void)
+test_lzma_stream_footer_encode(void)
{
- memcrap(buffer, sizeof(buffer));
- expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_OK);
- succeed(test_header_decoder(LZMA_OK));
+#ifndef HAVE_ENCODERS
+ assert_skip("Encoder support disabled");
+#else
+ for (int i = 0; i < LZMA_CHECK_ID_MAX; i++)
+ stream_footer_encode_helper(i);
+
+ lzma_stream_flags flags = {
+ .version = 0,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = LZMA_CHECK_CRC32
+ };
+
+ uint8_t footer[LZMA_STREAM_HEADER_SIZE];
+
+ // Should fail if version > 0
+ flags.version = 1;
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
+ LZMA_OPTIONS_ERROR);
+ flags.version = 0;
+
+ // Should fail if Check ID is invalid
+ flags.check = LZMA_CHECK_ID_MAX + 1;
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
+ LZMA_PROG_ERROR);
+
+ // Should fail if Backward Size is invalid
+ flags.backward_size -= 1;
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
+ LZMA_PROG_ERROR);
+ flags.backward_size += 2;
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
+ LZMA_PROG_ERROR);
+ flags.backward_size = LZMA_BACKWARD_SIZE_MAX + 4;
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
+ LZMA_PROG_ERROR);
+#endif
}
-static bool
-test_footer_decoder(lzma_ret expected_ret)
+#if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
+static void
+stream_header_decode_helper(lzma_check check)
{
- memcrap(&decoded_flags, sizeof(decoded_flags));
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = check
+ };
+
+ uint8_t header[LZMA_STREAM_HEADER_SIZE];
+
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
- if (lzma_stream_footer_decode(&decoded_flags, buffer) != expected_ret)
- return true;
+ lzma_stream_flags dest_flags;
+ assert_lzma_ret(lzma_stream_header_decode(&dest_flags, header),
+ LZMA_OK);
- if (expected_ret != LZMA_OK)
- return false;
+ // Version should be 0
+ assert_uint_eq(dest_flags.version, 0);
- return validate();
+ // Backward Size should be LZMA_VLI_UNKNOWN
+ assert_uint_eq(dest_flags.backward_size, LZMA_VLI_UNKNOWN);
+
+ // Check ID must equal the argument given to this function.
+ assert_uint_eq(dest_flags.check, check);
}
+#endif
static void
-test_footer(void)
+test_lzma_stream_header_decode(void)
{
- memcrap(buffer, sizeof(buffer));
- expect(lzma_stream_footer_encode(&known_flags, buffer) == LZMA_OK);
- succeed(test_footer_decoder(LZMA_OK));
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+ for (int i = 0; i < LZMA_CHECK_ID_MAX; i++)
+ stream_header_decode_helper(i);
+
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = LZMA_CHECK_CRC32
+ };
+
+ uint8_t header[LZMA_STREAM_HEADER_SIZE];
+ lzma_stream_flags dest;
+
+ // First encode known flags to header buffer
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
+
+ // Should fail if magic bytes do not match
+ header[0] ^= 1;
+ assert_lzma_ret(lzma_stream_header_decode(&dest, header),
+ LZMA_FORMAT_ERROR);
+ header[0] ^= 1;
+
+ // Should fail if a reserved bit is set
+ uint8_t *stream_flags = header + sizeof(xz_header_magic);
+ stream_flags[0] = 1;
+
+ // Need to adjust CRC32 after making a change since the CRC32
+ // is verified before decoding the Stream Flags field.
+ uint8_t *crc32_ptr = header + sizeof(xz_header_magic)
+ + XZ_STREAM_FLAGS_SIZE;
+ const uint32_t crc_orig = read32le(crc32_ptr);
+ uint32_t new_crc32 = lzma_crc32(
+ stream_flags, XZ_STREAM_FLAGS_SIZE, 0);
+ write32le(crc32_ptr, new_crc32);
+ assert_lzma_ret(lzma_stream_header_decode(&dest, header),
+ LZMA_OPTIONS_ERROR);
+ stream_flags[0] = 0;
+ write32le(crc32_ptr, crc_orig);
+
+ // Should fail if upper bits of check ID are set
+ stream_flags[1] |= 0xF0;
+ new_crc32 = lzma_crc32(stream_flags, XZ_STREAM_FLAGS_SIZE, 0);
+ write32le(crc32_ptr, new_crc32);
+ assert_lzma_ret(lzma_stream_header_decode(&dest, header),
+ LZMA_OPTIONS_ERROR);
+ stream_flags[1] = flags.check;
+ write32le(crc32_ptr, crc_orig);
+
+ // Should fail if CRC32 does not match.
+ // First, alter a byte in the Stream Flags.
+ stream_flags[0] = 1;
+ assert_lzma_ret(lzma_stream_header_decode(&dest, header),
+ LZMA_DATA_ERROR);
+ stream_flags[0] = 0;
+
+ // Next, change the CRC32.
+ *crc32_ptr ^= 1;
+ assert_lzma_ret(lzma_stream_header_decode(&dest, header),
+ LZMA_DATA_ERROR);
+#endif
}
+#if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
static void
-test_encode_invalid(void)
+stream_footer_decode_helper(lzma_check check)
{
- known_flags.check = (lzma_check)(LZMA_CHECK_ID_MAX + 1);
- known_flags.backward_size = 1024;
-
- expect(lzma_stream_header_encode(&known_flags, buffer)
- == LZMA_PROG_ERROR);
-
- expect(lzma_stream_footer_encode(&known_flags, buffer)
- == LZMA_PROG_ERROR);
-
- known_flags.check = (lzma_check)(-1);
-
- expect(lzma_stream_header_encode(&known_flags, buffer)
- == LZMA_PROG_ERROR);
+ lzma_stream_flags flags = {
+ .version = 0,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = check,
+ };
- expect(lzma_stream_footer_encode(&known_flags, buffer)
- == LZMA_PROG_ERROR);
+ uint8_t footer[LZMA_STREAM_HEADER_SIZE];
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer), LZMA_OK);
- known_flags.check = LZMA_CHECK_NONE;
- known_flags.backward_size = 0;
+ lzma_stream_flags dest_flags;
+ assert_lzma_ret(lzma_stream_footer_decode(&dest_flags, footer),
+ LZMA_OK);
- // Header encoder ignores backward_size.
- expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_OK);
+ // Version should be 0.
+ assert_uint_eq(dest_flags.version, 0);
- expect(lzma_stream_footer_encode(&known_flags, buffer)
- == LZMA_PROG_ERROR);
+ // Backward Size should equal the value from the flags.
+ assert_uint_eq(dest_flags.backward_size, flags.backward_size);
- known_flags.backward_size = LZMA_VLI_MAX;
-
- expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_OK);
-
- expect(lzma_stream_footer_encode(&known_flags, buffer)
- == LZMA_PROG_ERROR);
+ // Check ID must equal argument given to this function.
+ assert_uint_eq(dest_flags.check, check);
}
+#endif
static void
-test_decode_invalid(void)
+test_lzma_stream_footer_decode(void)
{
- known_flags.check = LZMA_CHECK_NONE;
- known_flags.backward_size = 1024;
-
- expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_OK);
-
- // Test 1 (invalid Magic Bytes)
- buffer[5] ^= 1;
- succeed(test_header_decoder(LZMA_FORMAT_ERROR));
- buffer[5] ^= 1;
-
- // Test 2a (valid CRC32)
- uint32_t crc = lzma_crc32(buffer + 6, 2, 0);
- write32le(buffer + 8, crc);
- succeed(test_header_decoder(LZMA_OK));
-
- // Test 2b (invalid Stream Flags with valid CRC32)
- buffer[6] ^= 0x20;
- crc = lzma_crc32(buffer + 6, 2, 0);
- write32le(buffer + 8, crc);
- succeed(test_header_decoder(LZMA_OPTIONS_ERROR));
-
- // Test 3 (invalid CRC32)
- expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_OK);
- buffer[9] ^= 1;
- succeed(test_header_decoder(LZMA_DATA_ERROR));
-
- // Test 4 (invalid Stream Flags with valid CRC32)
- expect(lzma_stream_footer_encode(&known_flags, buffer) == LZMA_OK);
- buffer[9] ^= 0x40;
- crc = lzma_crc32(buffer + 4, 6, 0);
- write32le(buffer, crc);
- succeed(test_footer_decoder(LZMA_OPTIONS_ERROR));
-
- // Test 5 (invalid Magic Bytes)
- expect(lzma_stream_footer_encode(&known_flags, buffer) == LZMA_OK);
- buffer[11] ^= 1;
- succeed(test_footer_decoder(LZMA_FORMAT_ERROR));
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+ for (int i = 0; i < LZMA_CHECK_ID_MAX; i++)
+ stream_footer_decode_helper(i);
+
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = LZMA_CHECK_CRC32,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN
+ };
+
+ uint8_t footer[LZMA_STREAM_HEADER_SIZE];
+ lzma_stream_flags dest;
+
+ // First encode known flags to the footer buffer
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer), LZMA_OK);
+
+ // Should fail if magic bytes do not match
+ footer[LZMA_STREAM_HEADER_SIZE - 1] ^= 1;
+ assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
+ LZMA_FORMAT_ERROR);
+ footer[LZMA_STREAM_HEADER_SIZE - 1] ^= 1;
+
+ // Should fail if a reserved bit is set.
+ // In the Stream Footer, the Stream Flags follow the CRC32 (4 bytes)
+ // and the Backward Size (4 bytes)
+ uint8_t *stream_flags = footer + sizeof(uint32_t) * 2;
+ stream_flags[0] = 1;
+
+ // Need to adjust the CRC32 so it will not fail that check instead
+ uint8_t *crc32_ptr = footer;
+ const uint32_t crc_orig = read32le(crc32_ptr);
+ uint8_t *backward_size = footer + sizeof(uint32_t);
+ uint32_t new_crc32 = lzma_crc32(backward_size, sizeof(uint32_t) +
+ XZ_STREAM_FLAGS_SIZE, 0);
+ write32le(crc32_ptr, new_crc32);
+ assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
+ LZMA_OPTIONS_ERROR);
+ stream_flags[0] = 0;
+ write32le(crc32_ptr, crc_orig);
+
+ // Should fail if upper bits of check ID are set
+ stream_flags[1] |= 0xF0;
+ new_crc32 = lzma_crc32(backward_size, sizeof(uint32_t) +
+ XZ_STREAM_FLAGS_SIZE, 0);
+ write32le(crc32_ptr, new_crc32);
+ assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
+ LZMA_OPTIONS_ERROR);
+ stream_flags[1] = flags.check;
+ write32le(crc32_ptr, crc_orig);
+
+ // Should fail if CRC32 does not match.
+ // First, alter a byte in the Stream Flags.
+ stream_flags[0] = 1;
+ assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
+ LZMA_DATA_ERROR);
+ stream_flags[0] = 0;
+
+ // Next, change the CRC32
+ *crc32_ptr ^= 1;
+ assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
+ LZMA_DATA_ERROR);
+#endif
}
-int
-main(void)
+static void
+test_lzma_stream_flags_compare(void)
{
- // Valid headers
- known_flags.backward_size = 1024;
- for (lzma_check check = LZMA_CHECK_NONE;
- check <= LZMA_CHECK_ID_MAX; ++check) {
- test_header();
- test_footer();
+ lzma_stream_flags first = {
+ .version = 0,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = LZMA_CHECK_CRC32,
+ };
+
+ lzma_stream_flags second = first;
+
+ // First test should pass
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second), LZMA_OK);
+
+ // Altering either version should cause an error
+ first.version = 1;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_OPTIONS_ERROR);
+ second.version = 1;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_OPTIONS_ERROR);
+ first.version = 0;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_OPTIONS_ERROR);
+ second.version = 0;
+
+ // Check types must be under the maximum
+ first.check = LZMA_CHECK_ID_MAX + 1;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ second.check = LZMA_CHECK_ID_MAX + 1;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ first.check = LZMA_CHECK_CRC32;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ second.check = LZMA_CHECK_CRC32;
+
+ // Check types must be equal
+ for (uint32_t i = 0; i < LZMA_CHECK_ID_MAX; i++) {
+ first.check = i;
+ if (i == second.check)
+ assert_lzma_ret(lzma_stream_flags_compare(&first,
+ &second), LZMA_OK);
+ else
+ assert_lzma_ret(lzma_stream_flags_compare(&first,
+ &second), LZMA_DATA_ERROR);
}
+ first.check = LZMA_CHECK_CRC32;
+
+ // Backward Size comparison is skipped if either are LZMA_VLI_UNKNOWN
+ first.backward_size = LZMA_VLI_UNKNOWN;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second), LZMA_OK);
+ second.backward_size = LZMA_VLI_MAX + 1;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second), LZMA_OK);
+ second.backward_size = LZMA_BACKWARD_SIZE_MIN;
+
+ // Backward Sizes need to be valid
+ first.backward_size = LZMA_VLI_MAX + 4;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ second.backward_size = LZMA_VLI_MAX + 4;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ first.backward_size = LZMA_BACKWARD_SIZE_MIN;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ second.backward_size = LZMA_BACKWARD_SIZE_MIN;
+
+ // Backward Sizes must be equal
+ second.backward_size = first.backward_size + 4;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_DATA_ERROR);
+
+ // Should fail if Backward Sizes are > LZMA_BACKWARD_SIZE_MAX
+ // even though they are equal
+ first.backward_size = LZMA_BACKWARD_SIZE_MAX + 1;
+ second.backward_size = LZMA_BACKWARD_SIZE_MAX + 1;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+}
- // Invalid headers
- test_encode_invalid();
- test_decode_invalid();
- return 0;
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+ tuktest_run(test_lzma_stream_header_encode);
+ tuktest_run(test_lzma_stream_footer_encode);
+ tuktest_run(test_lzma_stream_header_decode);
+ tuktest_run(test_lzma_stream_footer_decode);
+ tuktest_run(test_lzma_stream_flags_compare);
+ return tuktest_end();
}