// Copyright (C) 2003 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #include #include #include #include #include #include #include "tester.h" namespace { using namespace test; using namespace std; using namespace dlib; logger dlog("test.entropy_coder"); namespace entropy_coder_kernel_test_helpers { template < typename encoder, typename decoder > std::string test ( const std::string& input ) /*! ensures - encodes the data from in and then tries to decode it and returns "" if it was successfully decoded else it returns the decoded string !*/ { ostringstream sout; istringstream sin; istringstream in; in.str(input); const unsigned long max_total = 65535; unsigned long counts[256]; for (int i = 0; i < 256; ++i) { counts[i] = 1; } encoder e; DLIB_TEST(e.stream_is_set() == false); e.set_stream(sout); DLIB_TEST(e.stream_is_set() == true); DLIB_TEST(&e.get_stream() == &sout); unsigned char ch; unsigned long total = 256; while (in.read((char*)&ch,1)) { if (total > max_total) { total = 0; for (int j = 0; j<256; ++j) { counts[j] >>= 1; if (counts[j] == 0) counts[j] = 1; total += counts[j]; } } unsigned long low_count = 0; unsigned long high_count; for (int i = 0; i < ch; ++i) low_count += counts[i]; high_count = low_count + counts[ch]; e.encode(low_count,high_count,total); ++total; counts[ch] += 1; } DLIB_TEST(e.stream_is_set() == true); DLIB_TEST(&e.get_stream() == &sout); e.clear(); DLIB_TEST(e.stream_is_set() == false); // ***************************************** decoder d; DLIB_TEST(d.stream_is_set() == false); DLIB_TEST(d.get_target_called() == false); sin.str(sout.str()); sout.str(""); d.set_stream(sin); DLIB_TEST(d.get_target_called() == false); DLIB_TEST(d.stream_is_set() == true); DLIB_TEST(&d.get_stream() == &sin); for (int i = 0; i < 256; ++i) { counts[i] = 1; } total = 256; for (string::size_type i = 0; i < input.size() ; ++i) { if (total > max_total) { total = 0; for (int j = 0; j<256; ++j) { counts[j] >>= 1; if (counts[j] == 0) counts[j] = 1; total += counts[j]; } } DLIB_TEST(d.get_target_called() == false); unsigned long target = d.get_target(total); DLIB_TEST(target < total); DLIB_TEST(d.get_target_called() == true); unsigned long low_count; unsigned long high_count = 0; unsigned long j; for (j = 0; high_count <= target; ++j) { high_count += counts[j]; } --j; low_count = high_count - counts[j]; ch = static_cast(j); sout.rdbuf()->sputn((char*)&ch,1); d.decode(low_count,high_count); DLIB_TEST(d.get_target_called() == false); ++total; counts[ch] += 1; } DLIB_TEST(d.stream_is_set() == true); DLIB_TEST(&d.get_stream() == &sin); d.clear(); DLIB_TEST(d.stream_is_set() == false); DLIB_TEST_MSG(sout.str().size() == input.size(),"the test script is buggy"); if (sout.str() == input) return ""; else return sout.str(); } } template < typename encoder, typename decoder > void entropy_coder_kernel_test ( ) /*! requires - encoder is an implementation of entropy_encoder/entropy_encoder_kernel_abstract.h - decoder is an implementation of entropy_decoder/entropy_decoder_kernel_abstract.h ensures - runs tests on encoder and decoder for compliance with the specs !*/ { using namespace entropy_coder_kernel_test_helpers; dlog << LTRACE << 1; print_spinner(); string temp, temp2; srand(static_cast(time(0))); for (int k = 0; k < 10000; ++k) { string temp; istringstream sin; ostringstream sout; decoder d; encoder e; e.set_stream(sout); int num = ::rand() %200; unsigned long total[200]; unsigned long high_count[200]; unsigned long low_count[200]; for (int i = 0; i < num; ++i) { total[i] = ::rand()%256 + 20; high_count[i] = ::rand()%total[i] + 1; low_count[i] = ::rand()%high_count[i]; e.encode(low_count[i],high_count[i],total[i]); } e.clear(); sout.rdbuf()->sputc('a'); sin.str(sout.str()); d.set_stream(sin); for (int i = 0; i < num; ++i) { unsigned long N = d.get_target(total[i]); DLIB_TEST(low_count[i] <= N && N < high_count[i]); d.decode(low_count[i],high_count[i]); } DLIB_TEST_MSG(sin.rdbuf()->sgetc() != EOF,"num: " << num); DLIB_TEST_MSG(sin.rdbuf()->sgetc() == 'a', "sin.rdbuf()->sgetc() == " << (char)sin.rdbuf()->sgetc() << "\nnum: " << num ); DLIB_TEST(sin.rdbuf()->sbumpc() == 'a'); DLIB_TEST(sin.rdbuf()->sgetc() == EOF); } // for (int k = 0; k < 10000; ++k) dlog << LTRACE << 2; print_spinner(); // the point of this block is to make sure that the return value // from decoder.get_target(total) is a always less than total for (int k = 0; k < 20; ++k) { string temp; temp.push_back(static_cast(::rand()&0xff)); istringstream sin(temp); decoder d; d.set_stream(sin); unsigned long total = ::rand()%256 + 20; unsigned long target = d.get_target(total); DLIB_TEST(target target) low_count = target; d.decode(low_count,high_count); target = d.get_target(total); DLIB_TEST_MSG(target(time(0)); srand(seed1 ); int array[65536]; for (int i = 0; i < 65536; ++i) { array[i] = ::rand()%256; } for (int i = 0; i < 60; ++i) { int idx = ::rand()%65536; int radius = 35; if (idx > radius && idx <65536-radius) { for (int j = idx-radius; j < idx+radius; ++j) array[j] = array[idx]; } } // test with 3 random strings of length 10000 // but use the above array to bias the random numbers for (int j = 0; j < 3; ++j) { print_spinner(); temp = ""; //seed2 = static_cast(time(0)); srand(seed2 ); for ( int i = 0; i < 10000; ++i) { int a = array[::rand()%65536]; temp += (unsigned char)a; } string temp2; temp2 = test(temp); if (temp2 != "") { int k = 0; DLIB_TEST(temp != temp2); while (temp[k] == temp2[k])++k; } DLIB_TEST_MSG(temp2 == "","") } } print_spinner(); dlog << LTRACE << 4; // test with a large string which contains all the same character temp = "eeeeeeeeee"; for (int i = 0; i < 13; ++i) { temp = temp + temp; } temp = test(temp); if (temp != "") { // crop off all the e's until we find the part that is messed up string::size_type pos = temp.find_first_not_of("e"); temp = temp.substr(pos); } DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") /**/ dlog << LTRACE << 5; print_spinner(); temp = "davis"; temp = test(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") temp = ""; temp = test(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") // test for each single character for ( int i = 0; i <= 255; ++i) { temp = (unsigned char)i; temp = test(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") } dlog << LTRACE << 6; // test with a long string with the same thing repeated many times temp = "davis "; for (int i = 0; i < 10; ++i) { temp = temp + temp; } temp = test(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") dlog << LTRACE << 7; // test with 10 random strings of length 1000 for (int j = 0; j < 10; ++j) { temp = ""; srand(static_cast(time(0))); for ( int i = 0; i < 1000; ++i) { int a = ::rand()%256; temp += (unsigned char)a; } temp = test(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") } dlog << LTRACE << 8; print_spinner(); // test with 15 random strings of length 30000 for (int j = 0; j < 15; ++j) { print_spinner(); temp = ""; unsigned long seed = static_cast(time(0)); srand(seed); for ( int i = 0; i < 30000; ++i) { int a = ::rand()%256; temp += (unsigned char)a; } temp = test(temp); DLIB_TEST_MSG(temp == "","seed: " << seed) } dlog << LTRACE << 9; print_spinner(); // test with a large string which contains all the same character temp = " "; for (int i = 0; i < 10; ++i) { temp = temp + temp; } temp = test(temp); if (temp != "") { // crop off all the spacess until we find the part that is messed up string::size_type pos = temp.find_first_not_of(" "); temp = temp.substr(pos); } DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"")/**/ dlog << LTRACE << 10; // test with a large string which contains a bunch of a's followed by a // bunch of z's temp = "aaaaaaaa"; temp2 = "zzzzzzzz"; for (int i = 0; i < 12; ++i) { temp = temp + temp; temp2 = temp2 + temp2; } temp += temp2; print_spinner(); temp = test(temp); DLIB_TEST(temp == ""); dlog << LTRACE << 11; } class entropy_coder_tester : public tester { public: entropy_coder_tester ( ) : tester ("test_entropy_coder", "Runs tests on the entropy_coder component.") {} void perform_test ( ) { dlog << LINFO << "testing kernel_1a 1"; entropy_coder_kernel_test< entropy_encoder::kernel_1a, entropy_decoder::kernel_1a >(); dlog << LINFO << "testing kernel_1a_c 2"; entropy_coder_kernel_test< entropy_encoder::kernel_1a_c, entropy_decoder::kernel_1a_c >(); dlog << LINFO << "testing kernel_1a 3"; entropy_coder_kernel_test< entropy_encoder::kernel_2a, entropy_decoder::kernel_2a >(); dlog << LINFO << "testing kernel_1a_c 4"; entropy_coder_kernel_test< entropy_encoder::kernel_2a_c, entropy_decoder::kernel_2a_c >(); dlog << LINFO << "testing kernel_1a 5"; entropy_coder_kernel_test< entropy_encoder::kernel_1a, entropy_decoder::kernel_1a_c >(); dlog << LINFO << "testing kernel_1a_c 6"; entropy_coder_kernel_test< entropy_encoder::kernel_1a_c, entropy_decoder::kernel_1a >(); dlog << LINFO << "testing kernel_1a 7"; entropy_coder_kernel_test< entropy_encoder::kernel_2a, entropy_decoder::kernel_2a_c >(); dlog << LINFO << "testing kernel_1a_c 8"; entropy_coder_kernel_test< entropy_encoder::kernel_2a_c, entropy_decoder::kernel_2a >(); } } a; }