Repository: sz3/libcimbar
File: src/lib/encoder/test/EncoderRoundTripTest.cpp (C++)

Code before:

	{
		std::ofstream f(inputFile);
		f << "hello"; // 5 bytes!
	}

	// will be padded so the fountain encoding is happy. The encoded image looks suspiciously non-random!
	Encoder enc(30, 4, 2);
	assertEquals( 1, enc.encode_fountain(inputFile, outPrefix) );

	uint64_t hash = 0xeecc8800efce8c48;
	std::string path = fmt::format("{}_0.png", outPrefix);
	cv::Mat encodedImg = cv::imread(path);
	cv::cvtColor(encodedImg, encodedImg, cv::COLOR_BGR2RGB);
	assertEquals( hash, image_hash::average_hash(encodedImg) );

	// decoder
	Decoder dec(30);
	// sink with a mismatched fountain_chunk_size
	// importantly, the sink expects a *larger* chunk than we'll give it...
	fountain_decoder_sink<cimbar::zstd_decompressor<std::ofstream>> fds(tempdir.path(), cimbar::Config::fountain_chunk_size(30, 6, true));

	unsigned bytesDecoded = dec.decode_fountain(encodedImg, fds, 1);
	assertEquals( 7500, bytesDecoded );

	assertEquals( 0, fds.num_done() );
}

TEST_CASE( "EncoderRoundTripTest/testStreaming", "[unit]" )
{
	MakeTempDirectory tempdir;

	//input
	std::ifstream infile(TestCimbar::getProjectDir() + "/LICENSE");

	// create encoder
	Encoder enc(30, 4, 2);
	fountain_encoder_stream::ptr fes = enc.create_fountain_encoder(infile);
	assertTrue( fes );
	assertTrue( fes->good() );

	// create decoder
	Decoder dec(30);
	fountain_decoder_sink<cimbar::zstd_decompressor<std::ofstream>> fds(tempdir.path(), cimbar::Config::fountain_chunk_size(30, 6, false));

	// encode frames, then pass to decoder
	for (int i = 0; i < 100; ++i)
	{
		std::optional<cv::Mat> frame = enc.encode_next(*fes);
		assertTrue( frame );


Review comment (bug):
The key here is that the fountain decode actually *succeeds*, the aggregator (the fountain_decoder_sink) just isn't prepared for it. This is a sanity check that (1) it doesn't decode, because it shouldn't work, (2) it doesn't crash.

Code after:

	{
		std::ofstream f(inputFile);
		f << "hello"; // 5 bytes!
	}

	// will be padded so the fountain encoding is happy. The encoded image looks suspiciously non-random!
	Encoder enc(30, 4, 2);
	enc.set_legacy_mode();
	assertEquals( 1, enc.encode_fountain(inputFile, outPrefix) );

	uint64_t hash = 0xaecc8c00efce8c28;
	std::string path = fmt::format("{}_0.png", outPrefix);
	cv::Mat encodedImg = cv::imread(path);
	cv::cvtColor(encodedImg, encodedImg, cv::COLOR_BGR2RGB);
	assertEquals( hash, image_hash::average_hash(encodedImg) );

	// decoder
	Decoder dec(30);
	// sink with a mismatched fountain_chunk_size
	// importantly, the sink expects a *smaller* chunk than we'll give it...
	// because that's a more interesting test...
	fountain_decoder_sink<cimbar::zstd_decompressor<std::ofstream>> fds(tempdir.path(), cimbar::Config::fountain_chunk_size(30, 6, false));

	unsigned bytesDecoded = dec.decode_fountain(encodedImg, fds, 0);
	assertEquals( 7500, bytesDecoded );

	assertEquals( 0, fds.num_done() );
}

TEST_CASE( "EncoderRoundTripTest/testStreaming", "[unit]" )
{
	MakeTempDirectory tempdir;

	//input
	std::ifstream infile(TestCimbar::getProjectDir() + "/LICENSE");

	// create encoder
	Encoder enc(30, 4, 2);
	fountain_encoder_stream::ptr fes = enc.create_fountain_encoder(infile);
	assertTrue( fes );
	assertTrue( fes->good() );

	// create decoder
	Decoder dec(30);
	fountain_decoder_sink<cimbar::zstd_decompressor<std::ofstream>> fds(tempdir.path(), cimbar::Config::fountain_chunk_size(30, 6, false));

	// encode frames, then pass to decoder
	for (int i = 0; i < 100; ++i)
	{
		std::optional<cv::Mat> frame = enc.encode_next(*fes);