Merge pull request #31 from RomTholos/test/flac-error-handling

Add FLAC error handling regression tests
This commit is contained in:
2026-04-01 22:40:31 +01:00
committed by GitHub

View File

@@ -19,6 +19,7 @@
#include <climits>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <aaruformat.h>
@@ -57,6 +58,146 @@ protected:
// shared user data
};
// --- Regression tests for fix/flac-error-handling (TEST-R01) ---
// The fix changed decode/encode to return 0 (not -1 or crash) on error,
// added NULL checks, and fixed a decoder leak on init failure.
TEST(flacErrors, decode_garbage_returns_zero)
{
// Random garbage is not valid FLAC — decoder must return 0, not crash or return -1
uint8_t garbage[4096];
memset(garbage, 0xAB, sizeof(garbage));
const size_t out_size = 65536;
auto *out = static_cast<uint8_t *>(malloc(out_size));
ASSERT_NE(out, nullptr);
size_t result = aaruf_flac_decode_redbook_buffer(out, out_size, garbage, sizeof(garbage));
EXPECT_EQ(result, 0U);
free(out);
}
TEST(flacErrors, decode_truncated_flac_returns_zero)
{
// Valid FLAC header but truncated mid-stream
// fLaC magic = 0x664C6143
uint8_t truncated[64];
truncated[0] = 'f';
truncated[1] = 'L';
truncated[2] = 'a';
truncated[3] = 'C';
// Fill rest with zeros (incomplete metadata block)
memset(truncated + 4, 0, sizeof(truncated) - 4);
auto *out = static_cast<uint8_t *>(malloc(4096));
ASSERT_NE(out, nullptr);
size_t result = aaruf_flac_decode_redbook_buffer(out, 4096, truncated, sizeof(truncated));
EXPECT_EQ(result, 0U);
free(out);
}
TEST(flacErrors, decode_empty_input_returns_zero)
{
auto *out = static_cast<uint8_t *>(malloc(4096));
ASSERT_NE(out, nullptr);
size_t result = aaruf_flac_decode_redbook_buffer(out, 4096, NULL, 0);
EXPECT_EQ(result, 0U);
free(out);
}
TEST(flacErrors, decode_zero_length_returns_zero)
{
uint8_t src[1] = {0};
auto *out = static_cast<uint8_t *>(malloc(4096));
ASSERT_NE(out, nullptr);
size_t result = aaruf_flac_decode_redbook_buffer(out, 4096, src, 0);
EXPECT_EQ(result, 0U);
free(out);
}
TEST(flacErrors, encode_zero_length_no_crash)
{
// Zero-length encode with NULL source: FLAC encoder still produces a valid
// stream header (STREAMINFO + footer), so result > 0 is expected.
// The key assertion: no crash, no leak, no ASan error.
uint8_t out[4096];
size_t result = aaruf_flac_encode_redbook_buffer(out, sizeof(out), NULL, 0, 4608, 1, 0,
"partial_tukey(0/1.0/1.0)", 12, 0, 1, false, 0, 8, NULL, 0);
// FLAC emits a valid (empty) stream — header bytes only
EXPECT_GT(result, 0U);
EXPECT_LT(result, 256U); // sanity: just header, no audio data
}
TEST(flacErrors, encode_garbage_roundtrip_fails_cleanly)
{
// Non-PCM data that is technically processable by FLAC (correct length for samples)
// but should still produce a valid FLAC stream that roundtrips.
// The key test here: even random data shouldn't crash or leak.
const size_t src_size = 2352 * 4; // 4 CD sectors worth of "audio"
auto *src = static_cast<uint8_t *>(malloc(src_size));
memset(src, 0xDE, src_size);
auto *cmp = static_cast<uint8_t *>(malloc(src_size * 2));
size_t cmp_result =
aaruf_flac_encode_redbook_buffer(cmp, src_size * 2, src, src_size, 4608, 1, 0,
"partial_tukey(0/1.0/1.0)", 12, 0, 1, false, 0, 8, NULL, 0);
// Encoding random data should succeed (FLAC handles any 16-bit PCM)
EXPECT_GT(cmp_result, 0U);
if(cmp_result > 0)
{
// Verify roundtrip: decode what we just encoded
auto *decoded = static_cast<uint8_t *>(malloc(src_size));
size_t dec_result = aaruf_flac_decode_redbook_buffer(decoded, src_size, cmp, cmp_result);
EXPECT_EQ(dec_result, src_size);
if(dec_result == src_size) EXPECT_EQ(memcmp(src, decoded, src_size), 0);
free(decoded);
}
free(src);
free(cmp);
}
TEST(flacErrors, decode_dst_too_small_returns_zero)
{
// Encode valid audio data, then try to decode into a buffer that's too small.
// This should not crash or overwrite past the buffer.
const size_t src_size = 2352 * 4;
auto *src = static_cast<uint8_t *>(malloc(src_size));
memset(src, 0x00, src_size); // silence — compresses well
auto *cmp = static_cast<uint8_t *>(malloc(src_size));
size_t cmp_result =
aaruf_flac_encode_redbook_buffer(cmp, src_size, src, src_size, 4608, 1, 0, "partial_tukey(0/1.0/1.0)", 12, 0,
1, false, 0, 8, NULL, 0);
ASSERT_GT(cmp_result, 0U) << "Failed to encode test data";
// Decode into a buffer that's way too small
uint8_t tiny[64];
size_t dec_result = aaruf_flac_decode_redbook_buffer(tiny, sizeof(tiny), cmp, cmp_result);
// The decoder writes into the callback buffer capped by dst_len,
// but FLAC may still report success. The important thing is no crash
// and the returned size doesn't exceed our buffer.
EXPECT_LE(dec_result, sizeof(tiny));
free(src);
free(cmp);
}
// --- Original tests below ---
TEST_F(flacFixture, flac)
{
auto *outBuf = static_cast<uint8_t *>(malloc(9633792));