Tag Parser: tests/testfilecheck.cpp Source File

Tag Parser 12.5.3 C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags

Loading...
Searching...
No Matches
testfilecheck.cpp
Go to the documentation of this file.
1#include "../caseinsensitivecomparer.h"
2
3#include <c++utilities/conversion/stringbuilder.h>
4#include <c++utilities/tests/testutils.h>
5
6#include <cppunit/TestFixture.h>
7#include <cppunit/extensions/HelperMacros.h>
8
9#include <openssl/evp.h>
10#include <openssl/sha.h>
11
12#include <fstream>
13
14using namespace std;
15using namespace CppUtilities;
16using namespace TagParser;
17using namespace CPPUNIT_NS;
18
22 struct Sha256Checksum {
23 char checksum[65];
24 bool operator==(const Sha256Checksum &other) const;
25};
26
30 bool Sha256Checksum::operator==(const Sha256Checksum &other) const
31{
32 for (const char *i1 = checksum, *i2 = other.checksum, *end = checksum + sizeof(checksum); i1 != end; ++i1, ++i2) {
33 if (CaseInsensitiveCharComparer::toLower(static_cast<unsigned char>(*i1))
34 != CaseInsensitiveCharComparer::toLower(static_cast<unsigned char>(*i2))) {
35 return false;
36 }
37 }
38 return true;
39}
40
41ostream &operator<<(ostream &os, const Sha256Checksum &checksum)
42{
43 os << checksum.checksum;
44 return os;
45}
46
51 struct TestFile {
52 const char *path;
53 Sha256Checksum expectedSha256sum;
54 Sha256Checksum computeSha256Sum() const;
55 void verifyChecksum() const;
56} const testFiles[] = {
57 { "matroska_wave1/logo3_256x256.png", { "810b9172607e281d9a3969018c7d6521de240cc3688fecf598444e666aa6b4dc" } },
58 { "matroska_wave1/test1.mkv", { "0996a309ff2095910b9d30d5253b044d637154297ddf7d0bda7f3adedf5addc1" } },
59 { "matroska_wave1/test2.mkv", { "5b53d306e56f9bda6e80c3fbd9f3ccd20cc885770449d1fc0b5bec35c71d61e2" } },
60 { "matroska_wave1/test3.mkv", { "1722b0d93a6ef1a14dd513bd031cd5901c233b45aa3e3c87be0b0d7348d7d1b5" } },
61 { "matroska_wave1/test4.mkv", { "43df750a2a01a37949791b717051b41522081a266b71d113be4b713063843699" } },
62 { "matroska_wave1/test5.mkv", { "92acdc33bb0b5d7a4d9b0d6ca792230a78c786a30179dc9999cee41c28642842" } },
63 { "matroska_wave1/test6.mkv", { "7cad84b434116e023d340dd584ac833b93f03fb1bd7ea2727fa45de50af0abb9" } },
64 { "matroska_wave1/test7.mkv", { "95b21c92ad5a4fe00914ff5009e2a64f12fd4c5fb9cb1c3c888ab50bf0ffe483" } },
65 { "matroska_wave1/test8.mkv", { "9dddcd1550b814dae44d62e2b9f27c0eca31d5e190df2220cbf7492e3d6c63da" } },
66 { "mtx-test-data/mkv/handbrake-chapters-2.mkv", { "eccc55f3b59a77086b3ffb914525d312c7886eae34e3933352dea2f6f6a1974c" } },
67 { "mtx-test-data/mkv/tags.mkv", { "4330019afc3d846600c1ded38158fcac081297f4e56c749251c236f4871e0287" } },
68 { "mkv/nested-tags.xml", { "85cfcc94920f114e52fd1aa3df24706cd2710626e065a2c8c55dd209ec8dc8ce" } },
69 { "mp4/test1.m4a", { "4f16e0a22525bd13ba859431406d7f5991e0b4f155c51e10e5f32b0c97034b36" } },
70 { "mp4/android-8.1-camera-recoding.mp4", { "e7c5624872de1c9c2fb52dd954cef53adc337a6ba88342ff516dde5d4ef374dc" } },
71 { "mtx-test-data/aac/he-aacv2-ps.m4a", { "be54be0ae45b0184583ced8a84a881a1652a449feb7f6a917e11f60efabb68ac" } },
72 { "mtx-test-data/alac/othertest-itunes.m4a", { "5e9c64cde00902211533fbe38aaa67ef5f79a945e1d717951b78b4bbf9ff84e8" } },
73 { "mtx-test-data/mp3/id3-tag-and-xing-header.mp3", { "4a9187b05dc74d32e5a3de53494fde9db8c6c25d46082f86de6f424ad28daacf" } },
74 { "mtx-test-data/mp4/10-DanseMacabreOp.40.m4a", { "30c915d5656de049d66fd70b0966a33faf038af42365a2bb973e5c2fc0ba2038" } },
75 { "mtx-test-data/mp4/1080p-DTS-HD-7.1.mp4", { "fbf929bf8300fc6e53c5c5b7fde4ed2a427fef2d4fd093511c672083039abbf1" } },
76 { "mtx-test-data/mp4/dash/dragon-age-inquisition-H1LkM6IVlm4-video.mp4", { "864891f4510f3fa9c49c19e671171cec08ceb331362cf7161419b957be090d47" } },
77 { "mtx-test-data/ogg/qt4dance_medium.ogg", { "0b5429da9713be171c6ae0da69621261e8d5ddc9db3da872e5ade1a1c883decd" } },
78 { "mtx-test-data/opus/v-opus.ogg", { "e12adece4dbcccf2471b61c3ebd7c6576dee351d85809ab6f01d6f324d65b417" } },
79 { "misc/multiple_id3v2_4_values.mp3", { "da012a41213cdc49b2afe1457625d8baced1a64e2351f17b520bf82c6bfe4e03" } },
80 { "ogg/noise-without-cover.opus", { "ff578894c0c47aed4cc41ae94dee2886fe2c556593e44f731135f47bca870464" } },
81 { "ogg/noise-broken-segment-termination.opus", { "12835cf12b5b9fa70c239ae05e9d5bb768e715a2d61ef6301ed4af673088de45" } },
82 { "ogg/example-cover.png", { "897e1a2d0cfb79c1fe5068108bb34610c3758bd0b9a7e90c1702c4e6972e0801" } },
83};
84
86struct EvpMdCtx {
87 EvpMdCtx()
88 : handle(EVP_MD_CTX_new())
89 {
90 }
91 ~EvpMdCtx()
92 {
93 if (handle) {
94 EVP_MD_CTX_free(handle);
95 }
96 }
97 EVP_MD_CTX *handle;
98};
100
104 Sha256Checksum TestFile::computeSha256Sum() const
105{
106 // init sha256 hashing
107 const auto mdctx = EvpMdCtx();
108 if (!mdctx.handle) {
109 throw std::runtime_error("Unable to create EVP context.");
110 }
111 if (EVP_DigestInit_ex(mdctx.handle, EVP_sha256(), nullptr) != 1) {
112 throw std::runtime_error("Unable to init SHA256-EVP context.");
113 }
114
115 // read and hash file
116 {
117 ifstream file;
118 file.exceptions(ios_base::eofbit | ios_base::failbit | ios_base::badbit);
119 file.open(testFilePath(path), ios_base::in | ios_base::binary);
120
121 char readBuffer[4096];
122 try {
123 for (;;) {
124 file.read(readBuffer, sizeof(readBuffer));
125 if (EVP_DigestUpdate(mdctx.handle, readBuffer, static_cast<std::size_t>(file.gcount())) != 1) {
126 throw std::runtime_error("Unable to update SHA256-EVP.");
127 }
128 }
129 } catch (const std::ios_base::failure &) {
130 if (file.eof() && !file.bad()) {
131 if (EVP_DigestUpdate(mdctx.handle, readBuffer, static_cast<std::size_t>(file.gcount())) != 1) {
132 throw std::runtime_error("Unable to update SHA256-EVP.");
133 }
134 } else {
135 throw;
136 }
137 }
138 }
139
140 // compute final hash
141 unsigned char hash[SHA256_DIGEST_LENGTH];
142 auto length = static_cast<unsigned int>(SHA256_DIGEST_LENGTH);
143 if (EVP_DigestFinal_ex(mdctx.handle, hash, &length) != 1) {
144 throw std::runtime_error("Unable to finalize SHA256-EVP.");
145 }
146
147 // convert to "hex string"
148 Sha256Checksum hexString;
149 char *hexStringIterator = hexString.checksum;
150 for (unsigned char hashNumber : hash) {
151 const string digits = numberToString(hashNumber, static_cast<unsigned char>(16));
152 *(hexStringIterator++) = digits.size() < 2 ? '0' : digits.front();
153 *(hexStringIterator++) = digits.back();
154 }
155 *hexStringIterator = '\0';
156 return hexString;
157}
158
162 void TestFile::verifyChecksum() const
163{
164 CPPUNIT_ASSERT_EQUAL_MESSAGE(argsToString("integrity of testfile \"", path, '\"'), expectedSha256sum, computeSha256Sum());
165}
166
171 class TestFileCheck : public TestFixture {
172 CPPUNIT_TEST_SUITE(TestFileCheck);
173 CPPUNIT_TEST(verifyChecksums);
174 CPPUNIT_TEST_SUITE_END();
175
176private:
177 void verifyChecksums();
178};
179
180CPPUNIT_TEST_SUITE_REGISTRATION(TestFileCheck);
181
182void TestFileCheck::verifyChecksums()
183{
184 for (const TestFile &testFile : testFiles) {
185 testFile.verifyChecksum();
186 }
187}
caseinsensitivecomparer.h
TestFileCheck
The TestFileCheck class verifies integrity of all testfiles used in the testsuite of tagparser or tag...
Definition testfilecheck.cpp:171
CppUtilities
Definition abstractcontainer.h:16
CppUtilities::operator<<
std::ostream & operator<<(std::ostream &os, const TagParser::TagTextEncoding &encoding)
Prints a TagTextEncoding to enable CPPUNIT_ASSERT_EQUAL for tag values.
Definition helper.cpp:8
TagParser
Contains all classes and functions of the TagInfo library.
Definition aaccodebook.h:10
Sha256Checksum
The Sha256Checksum struct holds the "hex string representation" of a SHA-256 checksum.
Definition testfilecheck.cpp:22
Sha256Checksum::checksum
char checksum[65]
Definition testfilecheck.cpp:23
Sha256Checksum::operator==
bool operator==(const Sha256Checksum &other) const
Returns whether the current instance equals other ignoring the case.
Definition testfilecheck.cpp:30
TagParser::CaseInsensitiveCharComparer::toLower
static constexpr unsigned char toLower(const unsigned char c)
Definition caseinsensitivecomparer.h:16
TestFile
The TestFile struct holds the path (relative to testfile dir) and checksum of a test file.
Definition testfilecheck.cpp:51
TestFile::computeSha256Sum
Sha256Checksum computeSha256Sum() const
Computes the SHA-256 checksums for the file using OpenSSL.
Definition testfilecheck.cpp:104
TestFile::path
const char * path
Definition testfilecheck.cpp:52
TestFile::verifyChecksum
void verifyChecksum() const
Checks whether the expected SHA-256 checksum matches the actual checksum.
Definition testfilecheck.cpp:162
TestFile::expectedSha256sum
Sha256Checksum expectedSha256sum
Definition testfilecheck.cpp:53
testFiles
struct TestFile testFiles[]
CPPUNIT_TEST_SUITE_REGISTRATION
CPPUNIT_TEST_SUITE_REGISTRATION(TestFileCheck)