From 9a94d5480f17a0d79ff6216d426b61c7116cb0d0 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 8 Apr 2017 18:40:27 +0200 Subject: [PATCH] Add test to verify testfiles via SHA-256 checksum --- CMakeLists.txt | 15 +++- tests/testfilecheck.cpp | 162 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 tests/testfilecheck.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c618da8..eb364d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,7 @@ set(TEST_HEADER_FILES ) set(TEST_SRC_FILES tests/cppunit.cpp + tests/testfilecheck.cpp tests/overall.cpp ) @@ -166,7 +167,7 @@ set(META_PUBLIC_STATIC_LIB_DEPENDS c++utilities_static) set(META_PRIVATE_COMPILE_DEFINITIONS LEGACY_API) # find c++utilities -find_package(c++utilities 4.6.0 REQUIRED) +find_package(c++utilities 4.7.0 REQUIRED) use_cpp_utilities() # find 3rd party libraries @@ -180,6 +181,18 @@ use_external_library_from_package( AUTO_LINKAGE REQUIRED ) +# crypto (for tests) +find_external_library_from_package( + crypto + OpenSSL ANY_VERSION + OPENSSL_INCLUDE_DIR + OPENSSL_CRYPTO_LIBRARY + AUTO_LINKAGE + REQUIRED +) +link_tests_against_library( + crypto AUTO_LINKAGE REQUIRED +) # include modules to apply configuration include(BasicConfig) diff --git a/tests/testfilecheck.cpp b/tests/testfilecheck.cpp new file mode 100644 index 0000000..42e1f32 --- /dev/null +++ b/tests/testfilecheck.cpp @@ -0,0 +1,162 @@ +#include "../caseinsensitivecomparer.h" + +#include +#include +#include + +#include +#include + +#include + +#include + +using namespace std; +using namespace ConversionUtilities; +using namespace IoUtilities; +using namespace TestUtilities; +using namespace Media; + +using namespace CPPUNIT_NS; + +/*! + * \brief The Sha256Checksum struct holds the "hex string representation" of a SHA-256 checksum. + */ +struct Sha256Checksum +{ + char checksum[65]; + bool operator ==(const Sha256Checksum &other) const; +}; + +/*! + * \brief Returns whether the current instance equals \a other ignoring the case. + */ +bool Sha256Checksum::operator ==(const Sha256Checksum &other) const +{ + for(const char *i1 = checksum, *i2 = other.checksum, *end = checksum + sizeof(checksum); i1 != end; ++i1, ++i2) { + if(CaseInsensitiveCharComparer::toLower(static_cast(*i1)) + != CaseInsensitiveCharComparer::toLower(static_cast(*i2))) { + return false; + } + } + return true; +} + +ostream &operator<<(ostream &os, const Sha256Checksum &checksum) +{ + os << checksum.checksum; + return os; +} + +/*! + * \brief The TestFile struct holds the path (relative to testfile dir) and checksum of a test file. + */ +struct TestFile +{ + const char *path; + Sha256Checksum expectedSha256sum; + Sha256Checksum computeSha256Sum() const; + void verifyChecksum() const; +} const testFiles[] = { + {"flac/test.flac", {"0414965fae95b6c1191b7924f39fadafee68826ace0dc1ab7e0b5f539ee47fd3"}}, + {"flac/test.ogg", {"9f99b02fc373c37ce89da47ba0e23147a145e47bad4047f8c2e005808baed085"}}, + {"matroska_wave1/logo3_256x256.png", {"810b9172607e281d9a3969018c7d6521de240cc3688fecf598444e666aa6b4dc"}}, + {"matroska_wave1/test1.mkv", {"0996a309ff2095910b9d30d5253b044d637154297ddf7d0bda7f3adedf5addc1"}}, + {"matroska_wave1/test2.mkv", {"5b53d306e56f9bda6e80c3fbd9f3ccd20cc885770449d1fc0b5bec35c71d61e2"}}, + {"matroska_wave1/test3.mkv", {"1722b0d93a6ef1a14dd513bd031cd5901c233b45aa3e3c87be0b0d7348d7d1b5"}}, + {"matroska_wave1/test4.mkv", {"43df750a2a01a37949791b717051b41522081a266b71d113be4b713063843699"}}, + {"matroska_wave1/test5.mkv", {"92acdc33bb0b5d7a4d9b0d6ca792230a78c786a30179dc9999cee41c28642842"}}, + {"matroska_wave1/test6.mkv", {"7cad84b434116e023d340dd584ac833b93f03fb1bd7ea2727fa45de50af0abb9"}}, + {"matroska_wave1/test7.mkv", {"95b21c92ad5a4fe00914ff5009e2a64f12fd4c5fb9cb1c3c888ab50bf0ffe483"}}, + {"matroska_wave1/test8.mkv", {"9dddcd1550b814dae44d62e2b9f27c0eca31d5e190df2220cbf7492e3d6c63da"}}, + {"mp4/test1.m4a", {"4f16e0a22525bd13ba859431406d7f5991e0b4f155c51e10e5f32b0c97034b36"}}, + {"mtx-test-data/aac/he-aacv2-ps.m4a", {"be54be0ae45b0184583ced8a84a881a1652a449feb7f6a917e11f60efabb68ac"}}, + {"mtx-test-data/alac/othertest-itunes.m4a", {"5e9c64cde00902211533fbe38aaa67ef5f79a945e1d717951b78b4bbf9ff84e8"}}, + {"mtx-test-data/mp3/id3-tag-and-xing-header.mp3", {"4a9187b05dc74d32e5a3de53494fde9db8c6c25d46082f86de6f424ad28daacf"}}, + {"mtx-test-data/mp4/10-DanseMacabreOp.40.m4a", {"30c915d5656de049d66fd70b0966a33faf038af42365a2bb973e5c2fc0ba2038"}}, + {"mtx-test-data/mp4/1080p-DTS-HD-7.1.mp4", {"fbf929bf8300fc6e53c5c5b7fde4ed2a427fef2d4fd093511c672083039abbf1"}}, + {"mtx-test-data/mp4/dash/dragon-age-inquisition-H1LkM6IVlm4-video.mp4", {"864891f4510f3fa9c49c19e671171cec08ceb331362cf7161419b957be090d47"}}, + {"mtx-test-data/ogg/qt4dance_medium.ogg", {"0b5429da9713be171c6ae0da69621261e8d5ddc9db3da872e5ade1a1c883decd"}}, + {"mtx-test-data/opus/v-opus.ogg", {"e12adece4dbcccf2471b61c3ebd7c6576dee351d85809ab6f01d6f324d65b417"}}, +}; + +/*! + * \brief Computes the SHA-256 checksums for the file using OpenSSL. + */ +Sha256Checksum TestFile::computeSha256Sum() const +{ + // init sha256 hashing + SHA256_CTX sha256; + SHA256_Init(&sha256); + + // read and hash file + { + ifstream file; + file.exceptions(ios_base::eofbit | ios_base::failbit | ios_base::badbit); + file.open(testFilePath(path), ios_base::in | ios_base::binary); + + char readBuffer[4096]; + try { + for(;;) { + file.read(readBuffer, sizeof(readBuffer)); + SHA256_Update(&sha256, readBuffer, static_cast(file.gcount())); + } + } catch(...) { + catchIoFailure(); + if(file.eof() && !file.bad()) { + SHA256_Update(&sha256, readBuffer, static_cast(file.gcount())); + } else { + throw; + } + } + } + + // compute final hash + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256_Final(hash, &sha256); + + // convert to "hex string" + Sha256Checksum hexString; + char *hexStringIterator = hexString.checksum; + for(unsigned char hashNumber : hash) { + const string digits = numberToString(hashNumber, 16); + *(hexStringIterator++) = digits.size() < 2 ? '0' : digits.front(); + *(hexStringIterator++) = digits.back(); + } + *hexStringIterator = '\0'; + return hexString; +} + +/*! + * \brief Checks whether the expected SHA-256 checksum matches the actual checksum. + */ +void TestFile::verifyChecksum() const +{ + CPPUNIT_ASSERT_EQUAL_MESSAGE(argsToString("integrity of testfile \"", path, '\"'), + expectedSha256sum, + computeSha256Sum()); +} + +/*! + * \brief The TestFileCheck class verifies integrity of all testfiles used in the testsuite of + * tagparser or tageditor. + */ +class TestFileCheck : public TestFixture +{ + CPPUNIT_TEST_SUITE(TestFileCheck); + CPPUNIT_TEST(verifyChecksums); + CPPUNIT_TEST_SUITE_END(); + +private: + void verifyChecksums(); + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestFileCheck); + +void TestFileCheck::verifyChecksums() +{ + for(const TestFile &testFile : testFiles) { + testFile.verifyChecksum(); + } +}