Add tests for decoding of chained streams

This commit is contained in:
Martijn van Beurden 2024-08-23 20:04:06 +02:00
parent 08cf8a194a
commit f02c6dbfae
4 changed files with 314 additions and 109 deletions

View File

@ -29,8 +29,9 @@
#include <sys/types.h> /* for off_t */
#include "share/compat.h"
extern const long file_utils__ogg_serial_number;
extern long file_utils__ogg_serial_number;
FLAC__bool file_utils__generate_flacfile(FLAC__bool is_ogg, const char *output_filename, FLAC__off_t *output_filesize, uint32_t length, const FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata **metadata, uint32_t num_metadata);
FLAC__bool file_utils__append_file(const char *output_filename, const char *input_filename);
#endif

View File

@ -60,8 +60,9 @@ static ::FLAC__StreamMetadata *expected_metadata_sequence_[9];
static uint32_t num_expected_;
static FLAC__off_t flacfilesize_;
static const char *flacfilename(bool is_ogg)
static const char *flacfilename(bool is_ogg, bool is_chained_ogg)
{
if(is_chained_ogg) return "metadata_chained.oga";
return is_ogg? "metadata.oga" : "metadata.flac";
}
@ -95,9 +96,17 @@ static void free_metadata_blocks_()
mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
}
static bool generate_file_(FLAC__bool is_ogg)
static FLAC__bool generate_file_(FLAC__bool is_ogg, FLAC__bool is_chained_ogg)
{
printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_ogg? "Ogg ":"");
printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_chained_ogg? "chained Ogg " : is_ogg? "Ogg " : "");
if(is_chained_ogg) {
/* Create a different file as the first link */
expected_metadata_sequence_[0] = &picture_;
if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg,true), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, 1))
return die_("creating the encoded file");
file_utils__ogg_serial_number++;
}
num_expected_ = 0;
expected_metadata_sequence_[num_expected_++] = &padding_;
@ -110,9 +119,13 @@ static bool generate_file_(FLAC__bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
/* WATCHOUT: for Ogg FLAC the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */
if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg,false), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
return die_("creating the encoded file");
if(is_chained_ogg) {
file_utils__append_file(flacfilename(is_ogg, true), flacfilename(is_ogg, false));
}
return true;
}
@ -123,8 +136,9 @@ public:
uint32_t current_metadata_number_;
bool ignore_errors_;
bool error_occurred_;
bool mute_test_;
DecoderCommon(Layer layer): layer_(layer), current_metadata_number_(0), ignore_errors_(false), error_occurred_(false) { }
DecoderCommon(Layer layer): layer_(layer), current_metadata_number_(0), ignore_errors_(false), error_occurred_(false), mute_test_(false) { }
virtual ~DecoderCommon(void) { }
::FLAC__StreamDecoderWriteStatus common_write_callback_(const ::FLAC__Frame *frame);
void common_metadata_callback_(const ::FLAC__StreamMetadata *metadata);
@ -155,17 +169,19 @@ void DecoderCommon::common_metadata_callback_(const ::FLAC__StreamMetadata *meta
printf("%u... ", current_metadata_number_);
fflush(stdout);
if(current_metadata_number_ >= num_expected_) {
(void)die_("got more metadata blocks than expected");
error_occurred_ = true;
}
else {
if(!::FLAC__metadata_object_is_equal(expected_metadata_sequence_[current_metadata_number_], metadata)) {
(void)die_("metadata block mismatch");
if(!mute_test_) {
if(current_metadata_number_ >= num_expected_) {
(void)die_("got more metadata blocks than expected");
error_occurred_ = true;
}
else {
if(!::FLAC__metadata_object_is_equal(expected_metadata_sequence_[current_metadata_number_], metadata)) {
(void)die_("metadata block mismatch");
error_occurred_ = true;
}
}
current_metadata_number_++;
}
current_metadata_number_++;
}
void DecoderCommon::common_error_callback_(::FLAC__StreamDecoderErrorStatus status)
@ -193,7 +209,7 @@ public:
void metadata_callback(const ::FLAC__StreamMetadata *metadata);
void error_callback(::FLAC__StreamDecoderErrorStatus status);
bool test_respond(bool is_ogg);
bool test_respond(bool is_ogg, bool is_chained_ogg);
private:
StreamDecoder(const StreamDecoder&);
StreamDecoder&operator=(const StreamDecoder&);
@ -301,7 +317,7 @@ void StreamDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
common_error_callback_(status);
}
bool StreamDecoder::test_respond(bool is_ogg)
bool StreamDecoder::test_respond(bool is_ogg, bool is_chained_ogg)
{
::FLAC__StreamDecoderInitStatus init_status;
@ -310,6 +326,13 @@ bool StreamDecoder::test_respond(bool is_ogg)
return false;
}
if(is_chained_ogg) {
printf("testing set_decode_chained_stream()... ");
if(!set_decode_chained_stream(true))
return die_s_("returned false", this);
printf("OK\n");
}
printf("testing init%s()... ", is_ogg? "_ogg":"");
init_status = is_ogg? init_ogg() : init();
if(init_status != ::FLAC__STREAM_DECODER_INIT_STATUS_OK)
@ -323,6 +346,20 @@ bool StreamDecoder::test_respond(bool is_ogg)
return false;
}
if(is_chained_ogg) {
mute_test_ = true;
printf("skip first chain link with process_until_end_of_link()... ");
if(!process_until_end_of_link())
return die_s_("returned false", this);
printf("OK\n");
mute_test_ = false;
printf("progress to next chain link with finish_link()... ");
if(!finish_link())
return die_s_("returned false", this);
printf("OK\n");
}
printf("testing process_until_end_of_stream()... ");
if(!process_until_end_of_stream()) {
State state = get_state();
@ -352,7 +389,7 @@ public:
void metadata_callback(const ::FLAC__StreamMetadata *metadata);
void error_callback(::FLAC__StreamDecoderErrorStatus status);
bool test_respond(bool is_ogg);
bool test_respond(bool is_ogg, bool is_chained_ogg);
};
::FLAC__StreamDecoderWriteStatus FileDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
@ -371,7 +408,7 @@ void FileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
common_error_callback_(status);
}
bool FileDecoder::test_respond(bool is_ogg)
bool FileDecoder::test_respond(bool is_ogg, bool is_chained_ogg)
{
::FLAC__StreamDecoderInitStatus init_status;
@ -380,11 +417,18 @@ bool FileDecoder::test_respond(bool is_ogg)
return false;
}
if(is_chained_ogg) {
printf("testing set_decode_chained_stream()... ");
if(!set_decode_chained_stream(true))
return die_s_("returned false", this);
printf("OK\n");
}
switch(layer_) {
case LAYER_FILE:
{
printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
FILE *file = ::flac_fopen(flacfilename(is_ogg), "rb");
FILE *file = ::flac_fopen(flacfilename(is_ogg, is_chained_ogg), "rb");
if(0 == file) {
printf("ERROR (%s)\n", strerror(errno));
return false;
@ -397,7 +441,7 @@ bool FileDecoder::test_respond(bool is_ogg)
break;
case LAYER_FILENAME:
printf("testing init%s()... ", is_ogg? "_ogg":"");
init_status = is_ogg? init_ogg(flacfilename(is_ogg)) : init(flacfilename(is_ogg));
init_status = is_ogg? init_ogg(flacfilename(is_ogg, is_chained_ogg)) : init(flacfilename(is_ogg, is_chained_ogg));
break;
default:
die_("internal error 001");
@ -409,6 +453,20 @@ bool FileDecoder::test_respond(bool is_ogg)
current_metadata_number_ = 0;
if(is_chained_ogg) {
mute_test_ = true;
printf("skip first chain link with process_until_end_of_link()... ");
if(!process_until_end_of_link())
return die_s_("returned false", this);
printf("OK\n");
mute_test_ = false;
printf("progress to next chain link with finish_link()... ");
if(!finish_link())
return die_s_("returned false", this);
printf("OK\n");
}
printf("testing process_until_end_of_stream()... ");
if(!process_until_end_of_stream()) {
State state = get_state();
@ -437,13 +495,13 @@ static FLAC::Decoder::Stream *new_by_layer(Layer layer)
return new FileDecoder(layer);
}
static bool test_stream_decoder(Layer layer, bool is_ogg)
static bool test_stream_decoder(Layer layer, bool is_ogg, bool is_chained_ogg)
{
FLAC::Decoder::Stream *decoder;
::FLAC__StreamDecoderInitStatus init_status;
bool expect;
printf("\n+++ libFLAC++ unit test: FLAC::Decoder::%s (layer: %s, format: %s)\n\n", layer<LAYER_FILE? "Stream":"File", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC");
printf("\n+++ libFLAC++ unit test: FLAC::Decoder::%s (layer: %s, format: %s)\n\n", layer<LAYER_FILE? "Stream":"File", LayerString[layer], is_chained_ogg? "chained Ogg FLAC" : is_ogg? "Ogg FLAC" : "FLAC");
//
// test new -> delete
@ -501,8 +559,8 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
break;
case LAYER_FILENAME:
init_status = is_ogg?
dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(flacfilename(is_ogg)) :
dynamic_cast<FLAC::Decoder::File*>(decoder)->init(flacfilename(is_ogg));
dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(flacfilename(is_ogg, is_chained_ogg)) :
dynamic_cast<FLAC::Decoder::File*>(decoder)->init(flacfilename(is_ogg, is_chained_ogg));
break;
default:
die_("internal error 006");
@ -551,11 +609,18 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
return false;
}
if(is_chained_ogg) {
printf("testing set_decode_chained_stream()... ");
if(!decoder->set_decode_chained_stream(true))
return die_s_("returned false", decoder);
printf("OK\n");
}
switch(layer) {
case LAYER_STREAM:
case LAYER_SEEKABLE_STREAM:
printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
dynamic_cast<StreamDecoder*>(decoder)->file_ = ::flac_fopen(flacfilename(is_ogg), "rb");
dynamic_cast<StreamDecoder*>(decoder)->file_ = ::flac_fopen(flacfilename(is_ogg, is_chained_ogg), "rb");
if(0 == dynamic_cast<StreamDecoder*>(decoder)->file_) {
printf("ERROR (%s)\n", strerror(errno));
return false;
@ -568,7 +633,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
case LAYER_FILE:
{
printf("opening FLAC file... ");
FILE *file = ::flac_fopen(flacfilename(is_ogg), "rb");
FILE *file = ::flac_fopen(flacfilename(is_ogg, is_chained_ogg), "rb");
if(0 == file) {
printf("ERROR (%s)\n", strerror(errno));
return false;
@ -584,8 +649,8 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
case LAYER_FILENAME:
printf("testing init%s()... ", is_ogg? "_ogg":"");
init_status = is_ogg?
dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(flacfilename(is_ogg)) :
dynamic_cast<FLAC::Decoder::File*>(decoder)->init(flacfilename(is_ogg));
dynamic_cast<FLAC::Decoder::File*>(decoder)->init_ogg(flacfilename(is_ogg, is_chained_ogg)) :
dynamic_cast<FLAC::Decoder::File*>(decoder)->init(flacfilename(is_ogg, is_chained_ogg));
break;
default:
die_("internal error 009");
@ -595,14 +660,32 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
return die_s_(0, decoder);
printf("OK\n");
printf("testing get_state()... ");
FLAC::Decoder::Stream::State state = decoder->get_state();
printf("returned state = %u (%s)... OK\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring());
dynamic_cast<DecoderCommon*>(decoder)->current_metadata_number_ = 0;
dynamic_cast<DecoderCommon*>(decoder)->ignore_errors_ = false;
dynamic_cast<DecoderCommon*>(decoder)->error_occurred_ = false;
if(is_chained_ogg) {
dynamic_cast<DecoderCommon*>(decoder)->mute_test_ = true;
printf("skip first chain link with process_until_end_of_link()... ");
if(!decoder->process_until_end_of_link())
return die_s_("returned false", decoder);
printf("OK\n");
dynamic_cast<DecoderCommon*>(decoder)->mute_test_ = false;
printf("testing get_state()... ");
FLAC::Decoder::Stream::State state = decoder->get_state();
printf("returned state = %u (%s)... OK\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring());
printf("progress to next chain link with finish_link()... ");
if(!decoder->finish_link())
return die_s_("returned false", decoder);
printf("OK\n");
}
printf("testing get_state()... ");
FLAC::Decoder::Stream::State state = decoder->get_state();
printf("returned state = %u (%s)... OK\n", (uint32_t)((::FLAC__StreamDecoderState)state), state.as_cstring());
printf("testing get_md5_checking()... ");
if(!decoder->get_md5_checking()) {
printf("FAILED, returned false, expected true\n");
@ -719,6 +802,20 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
dynamic_cast<DecoderCommon*>(decoder)->current_metadata_number_ = 0;
if(is_chained_ogg) {
dynamic_cast<DecoderCommon*>(decoder)->mute_test_ = true;
printf("skip first chain link with process_until_end_of_link()... ");
if(!decoder->process_until_end_of_link())
return die_s_("returned false", decoder);
printf("OK\n");
dynamic_cast<DecoderCommon*>(decoder)->mute_test_ = false;
printf("progress to next chain link with finish_link()... ");
if(!decoder->finish_link())
return die_s_("returned false", decoder);
printf("OK\n");
}
printf("testing process_until_end_of_stream()... ");
if(!decoder->process_until_end_of_stream())
return die_s_("returned false", decoder);
@ -767,7 +864,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
}
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
/*
@ -783,7 +880,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
num_expected_ = 0;
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
/*
@ -815,7 +912,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &picture_;
expected_metadata_sequence_[num_expected_++] = &unknown_;
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
/*
@ -855,7 +952,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
}
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
/*
@ -897,7 +994,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
}
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
/*
@ -944,7 +1041,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
}
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
/*
@ -968,7 +1065,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
num_expected_ = 0;
expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
/*
@ -993,7 +1090,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &application1_;
expected_metadata_sequence_[num_expected_++] = &application2_;
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
/*
@ -1017,7 +1114,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
num_expected_ = 0;
expected_metadata_sequence_[num_expected_++] = &application1_;
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
/*
@ -1049,7 +1146,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &application1_;
expected_metadata_sequence_[num_expected_++] = &application2_;
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
/*
@ -1098,7 +1195,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
}
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
/*
@ -1129,7 +1226,7 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
num_expected_ = 0;
expected_metadata_sequence_[num_expected_++] = &application2_;
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg)))
if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg) : dynamic_cast<FileDecoder*>(decoder)->test_respond(is_ogg, is_chained_ogg)))
return false;
if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */
@ -1147,31 +1244,34 @@ static bool test_stream_decoder(Layer layer, bool is_ogg)
bool test_decoders()
{
FLAC__bool is_ogg = false;
FLAC__bool is_chained_ogg = false;
while(1) {
init_metadata_blocks_();
if(!generate_file_(is_ogg))
if(!generate_file_(is_ogg, is_chained_ogg))
return false;
if(!test_stream_decoder(LAYER_STREAM, is_ogg))
if(!test_stream_decoder(LAYER_STREAM, is_ogg, is_chained_ogg))
return false;
if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg))
if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg, is_chained_ogg))
return false;
if(!test_stream_decoder(LAYER_FILE, is_ogg))
if(!test_stream_decoder(LAYER_FILE, is_ogg, is_chained_ogg))
return false;
if(!test_stream_decoder(LAYER_FILENAME, is_ogg))
if(!test_stream_decoder(LAYER_FILENAME, is_ogg, is_chained_ogg))
return false;
(void) grabbag__file_remove_file(flacfilename(is_ogg));
(void) grabbag__file_remove_file(flacfilename(is_ogg, is_chained_ogg));
free_metadata_blocks_();
if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
if(!FLAC_API_SUPPORTS_OGG_FLAC || is_chained_ogg)
break;
if(is_ogg)
is_chained_ogg = true;
is_ogg = true;
}

View File

@ -55,6 +55,7 @@ typedef struct {
uint32_t current_metadata_number;
FLAC__bool ignore_errors;
FLAC__bool error_occurred;
FLAC__bool mute_test;
} StreamDecoderClientData;
static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
@ -62,8 +63,9 @@ static FLAC__StreamMetadata *expected_metadata_sequence_[9];
static uint32_t num_expected_;
static FLAC__off_t flacfilesize_;
static const char *flacfilename(FLAC__bool is_ogg)
static const char *flacfilename(FLAC__bool is_ogg, FLAC__bool is_chained_ogg)
{
if(is_chained_ogg) return "metadata_chained.oga";
return is_ogg? "metadata.oga" : "metadata.flac";
}
@ -87,10 +89,10 @@ static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder)
return false;
}
static void open_test_file(StreamDecoderClientData * pdcd, int is_ogg, const char * mode)
static void open_test_file(StreamDecoderClientData * pdcd, int is_ogg, int is_chained_ogg, const char * mode)
{
pdcd->file = flac_fopen(flacfilename(is_ogg), mode);
safe_strncpy(pdcd->filename, flacfilename(is_ogg), sizeof (pdcd->filename));
pdcd->file = flac_fopen(flacfilename(is_ogg,is_chained_ogg), mode);
safe_strncpy(pdcd->filename, flacfilename(is_ogg,is_chained_ogg), sizeof (pdcd->filename));
}
static void init_metadata_blocks_(void)
@ -103,9 +105,17 @@ static void free_metadata_blocks_(void)
mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
}
static FLAC__bool generate_file_(FLAC__bool is_ogg)
static FLAC__bool generate_file_(FLAC__bool is_ogg, FLAC__bool is_chained_ogg)
{
printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_ogg? "Ogg ":"");
printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_chained_ogg? "chained Ogg " : is_ogg? "Ogg " : "");
if(is_chained_ogg) {
/* Create a different file as the first link */
expected_metadata_sequence_[0] = &picture_;
if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg,true), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, 1))
return die_("creating the encoded file");
file_utils__ogg_serial_number++;
}
num_expected_ = 0;
expected_metadata_sequence_[num_expected_++] = &padding_;
@ -118,9 +128,13 @@ static FLAC__bool generate_file_(FLAC__bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
/* WATCHOUT: for Ogg FLAC the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */
if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg,false), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
return die_("creating the encoded file");
if(is_chained_ogg) {
file_utils__append_file(flacfilename(is_ogg, true), flacfilename(is_ogg, false));
}
return true;
}
@ -281,26 +295,27 @@ static void stream_decoder_metadata_callback_(const FLAC__StreamDecoder *decoder
if(dcd->error_occurred)
return;
if (metadata->type == FLAC__METADATA_TYPE_APPLICATION) {
printf ("%u ('%c%c%c%c')... ", dcd->current_metadata_number, metadata->data.application.id [0], metadata->data.application.id [1], metadata->data.application.id [2], metadata->data.application.id [3]);
}
else {
printf("%u... ", dcd->current_metadata_number);
}
fflush(stdout);
if(!dcd->mute_test) {
if (metadata->type == FLAC__METADATA_TYPE_APPLICATION) {
printf ("%u ('%c%c%c%c')... ", dcd->current_metadata_number, metadata->data.application.id [0], metadata->data.application.id [1], metadata->data.application.id [2], metadata->data.application.id [3]);
}
else {
printf("%u... ", dcd->current_metadata_number);
}
fflush(stdout);
if(dcd->current_metadata_number >= num_expected_) {
(void)die_("got more metadata blocks than expected");
dcd->error_occurred = true;
}
else {
if(!mutils__compare_block(expected_metadata_sequence_[dcd->current_metadata_number], metadata)) {
(void)die_("metadata block mismatch");
if(dcd->current_metadata_number >= num_expected_) {
(void)die_("got more metadata blocks than expected");
dcd->error_occurred = true;
}
else {
if(!mutils__compare_block(expected_metadata_sequence_[dcd->current_metadata_number], metadata)) {
(void)die_("metadata block mismatch");
dcd->error_occurred = true;
}
}
dcd->current_metadata_number++;
}
dcd->current_metadata_number++;
}
static void stream_decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
@ -320,7 +335,7 @@ static void stream_decoder_error_callback_(const FLAC__StreamDecoder *decoder, F
}
}
static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, StreamDecoderClientData *dcd, FLAC__bool is_ogg)
static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, StreamDecoderClientData *dcd, FLAC__bool is_ogg, FLAC__bool is_chained_ogg)
{
FLAC__StreamDecoderInitStatus init_status;
@ -330,7 +345,7 @@ static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, Str
/* for FLAC__stream_encoder_init_FILE(), the FLAC__stream_encoder_finish() closes the file so we have to keep re-opening: */
if(dcd->layer == LAYER_FILE) {
printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
open_test_file(dcd, is_ogg, "rb");
open_test_file(dcd, is_ogg, is_chained_ogg, "rb");
if(0 == dcd->file) {
printf("ERROR (%s)\n", strerror(errno));
return false;
@ -338,6 +353,13 @@ static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, Str
printf("OK\n");
}
if(is_chained_ogg) {
printf("testing FLAC__stream_decoder_set_decode_chained_stream()... ");
if(!FLAC__stream_decoder_set_decode_chained_stream(decoder, true))
return die_s_("returned false", decoder);
printf("OK\n");
}
switch(dcd->layer) {
case LAYER_STREAM:
printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
@ -361,8 +383,8 @@ static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, Str
case LAYER_FILENAME:
printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
init_status = is_ogg?
FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg,is_chained_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg,is_chained_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
break;
default:
die_("internal error 000");
@ -379,6 +401,21 @@ static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, Str
return false;
}
if(is_chained_ogg) {
dcd->mute_test = true;
printf("skip first chain link with FLAC__stream_decoder_process_until_end_of_link()... ");
if(!FLAC__stream_decoder_process_until_end_of_link(decoder))
return die_s_("returned false", decoder);
printf("OK\n");
dcd->mute_test = false;
printf("progress to next chain link with FLAC__stream_decoder_finish_link()... ");
if(!FLAC__stream_decoder_finish_link(decoder))
return die_s_("returned false", decoder);
printf("OK\n");
}
printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
return die_s_("returned false", decoder);
@ -392,7 +429,7 @@ static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, Str
return true;
}
static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg, FLAC__bool is_chained_ogg)
{
FLAC__StreamDecoder *decoder;
FLAC__StreamDecoderInitStatus init_status;
@ -401,8 +438,9 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
FLAC__bool expect;
decoder_client_data.layer = layer;
decoder_client_data.mute_test = false;
printf("\n+++ libFLAC unit test: FLAC__StreamDecoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC");
printf("\n+++ libFLAC unit test: FLAC__StreamDecoder (layer: %s, format: %s)\n\n", LayerString[layer], is_chained_ogg? "chained Ogg FLAC" : is_ogg? "Ogg FLAC" : "FLAC");
printf("testing FLAC__stream_decoder_new()... ");
decoder = FLAC__stream_decoder_new();
@ -441,8 +479,8 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
case LAYER_FILENAME:
printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
init_status = is_ogg?
FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0) :
FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0);
FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg,is_chained_ogg), 0, 0, 0, 0) :
FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg,is_chained_ogg), 0, 0, 0, 0);
break;
default:
die_("internal error 003");
@ -479,9 +517,16 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
return die_s_("returned false", decoder);
printf("OK\n");
if(is_chained_ogg) {
printf("testing FLAC__stream_decoder_set_decode_chained_stream()... ");
if(!FLAC__stream_decoder_set_decode_chained_stream(decoder, true))
return die_s_("returned false", decoder);
printf("OK\n");
}
if(layer < LAYER_FILENAME) {
printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
open_test_file(&decoder_client_data, is_ogg, "rb");
open_test_file(&decoder_client_data, is_ogg, is_chained_ogg, "rb");
if(0 == decoder_client_data.file) {
printf("ERROR (%s)\n", strerror(errno));
return false;
@ -511,8 +556,8 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
case LAYER_FILENAME:
printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
init_status = is_ogg?
FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg,is_chained_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg,is_chained_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
break;
default:
die_("internal error 009");
@ -522,14 +567,33 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
return die_s_(0, decoder);
printf("OK\n");
printf("testing FLAC__stream_decoder_get_state()... ");
state = FLAC__stream_decoder_get_state(decoder);
printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]);
decoder_client_data.current_metadata_number = 0;
decoder_client_data.ignore_errors = false;
decoder_client_data.error_occurred = false;
if(is_chained_ogg) {
decoder_client_data.mute_test = true;
printf("skip first chain link with FLAC__stream_decoder_process_until_end_of_link()... ");
if(!FLAC__stream_decoder_process_until_end_of_link(decoder))
return die_s_("returned false", decoder);
printf("OK\n");
decoder_client_data.mute_test = false;
printf("testing FLAC__stream_decoder_get_state()... ");
state = FLAC__stream_decoder_get_state(decoder);
printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]);
printf("progress to next chain link with FLAC__stream_decoder_finish_link()... ");
if(!FLAC__stream_decoder_finish_link(decoder))
return die_s_("returned false", decoder);
printf("OK\n");
}
printf("testing FLAC__stream_decoder_get_state()... ");
state = FLAC__stream_decoder_get_state(decoder);
printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]);
printf("testing FLAC__stream_decoder_get_md5_checking()... ");
if(!FLAC__stream_decoder_get_md5_checking(decoder)) {
printf("FAILED, returned false, expected true\n");
@ -649,6 +713,24 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
decoder_client_data.current_metadata_number = 0;
if(is_chained_ogg) {
decoder_client_data.mute_test = true;
printf("skip first chain link with FLAC__stream_decoder_process_until_end_of_link()... ");
if(!FLAC__stream_decoder_process_until_end_of_link(decoder))
return die_s_("returned false", decoder);
printf("OK\n");
decoder_client_data.mute_test = false;
printf("testing FLAC__stream_decoder_get_state()... ");
state = FLAC__stream_decoder_get_state(decoder);
printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]);
printf("progress to next chain link with FLAC__stream_decoder_finish_link()... ");
if(!FLAC__stream_decoder_finish_link(decoder))
return die_s_("returned false", decoder);
printf("OK\n");
}
printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
return die_s_("returned false", decoder);
@ -692,7 +774,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
}
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
/*
@ -706,7 +788,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
num_expected_ = 0;
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
/*
@ -734,7 +816,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &picture_;
expected_metadata_sequence_[num_expected_++] = &unknown_;
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
/*
@ -770,7 +852,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
}
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
/*
@ -808,7 +890,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
}
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
/*
@ -849,7 +931,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
}
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
/*
@ -869,7 +951,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
num_expected_ = 0;
expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
/*
@ -890,7 +972,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &application1_;
expected_metadata_sequence_[num_expected_++] = &application2_;
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
/*
@ -910,7 +992,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
num_expected_ = 0;
expected_metadata_sequence_[num_expected_++] = &application1_;
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
/*
@ -936,7 +1018,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &application1_;
expected_metadata_sequence_[num_expected_++] = &application2_;
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
/*
@ -979,7 +1061,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
expected_metadata_sequence_[num_expected_++] = &unknown_;
}
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
/*
@ -1004,7 +1086,7 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
num_expected_ = 0;
expected_metadata_sequence_[num_expected_++] = &application2_;
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg, is_chained_ogg))
return false;
if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */
@ -1022,31 +1104,34 @@ static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
FLAC__bool test_decoders(void)
{
FLAC__bool is_ogg = false;
FLAC__bool is_chained_ogg = false;
while(1) {
init_metadata_blocks_();
if(!generate_file_(is_ogg))
if(!generate_file_(is_ogg, is_chained_ogg))
return false;
if(!test_stream_decoder(LAYER_STREAM, is_ogg))
if(!test_stream_decoder(LAYER_STREAM, is_ogg, is_chained_ogg))
return false;
if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg))
if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg, is_chained_ogg))
return false;
if(!test_stream_decoder(LAYER_FILE, is_ogg))
if(!test_stream_decoder(LAYER_FILE, is_ogg, is_chained_ogg))
return false;
if(!test_stream_decoder(LAYER_FILENAME, is_ogg))
if(!test_stream_decoder(LAYER_FILENAME, is_ogg, is_chained_ogg))
return false;
(void) grabbag__file_remove_file(flacfilename(is_ogg));
(void) grabbag__file_remove_file(flacfilename(is_ogg, is_chained_ogg));
free_metadata_blocks_();
if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
if(!FLAC_API_SUPPORTS_OGG_FLAC || is_chained_ogg)
break;
if(is_ogg)
is_chained_ogg = true;
is_ogg = true;
}

View File

@ -34,7 +34,7 @@
#endif
#define min(a,b) ((a)<(b)?(a):(b))
const long file_utils__ogg_serial_number = 12345;
long file_utils__ogg_serial_number = 12345;
#ifdef FLAC__VALGRIND_TESTING
static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
@ -153,3 +153,22 @@ FLAC__bool file_utils__generate_flacfile(FLAC__bool is_ogg, const char *output_f
return true;
}
FLAC__bool file_utils__append_file(const char *output_filename, const char *input_filename)
{
FILE *output, *input;
int c;
if(0 == (output = flac_fopen(output_filename, "ab")))
return false;
if(0 == (input = flac_fopen(input_filename, "rb")))
return false;
fseek(output, 0, SEEK_END);
while ((c = fgetc(input)) != EOF) {
fputc(c, output);
}
fclose(input);
fclose(output);
return true;
}