From f903e1ad715aa52c53e1bd29fb6af263933e0995 Mon Sep 17 00:00:00 2001 From: Scott Wheeler Date: Sun, 30 Jul 2023 06:31:48 +0200 Subject: [PATCH] Add checks for the expected sizes of all public classes This ensures that d-pointers exist where they're expected, and that classes are virtual that we expect to be virtual, as well as ensuring that we get a failure if the class size changes when it shouldn't. This also fixes the issues that were discovered by adding these tests. --- taglib/fileref.h | 6 + taglib/mod/modfilebase.h | 3 + taglib/mp4/mp4coverart.h | 2 +- taglib/mp4/mp4item.h | 2 +- taglib/mpeg/id3v1/id3v1tag.h | 4 + taglib/mpeg/id3v2/id3v2tag.h | 4 + taglib/riff/wav/infotag.h | 6 +- taglib/toolkit/tdebuglistener.h | 3 + taglib/toolkit/tiostream.h | 3 + taglib/toolkit/tpropertymap.cpp | 54 ++++--- taglib/toolkit/tpropertymap.h | 19 ++- tests/CMakeLists.txt | 1 + tests/test_sizes.cpp | 256 ++++++++++++++++++++++++++++++++ 13 files changed, 335 insertions(+), 28 deletions(-) create mode 100644 tests/test_sizes.cpp diff --git a/taglib/fileref.h b/taglib/fileref.h index 085c21f2..7f7047a4 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -110,6 +110,9 @@ namespace TagLib { bool readAudioProperties = true, AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average) const = 0; + private: + class FileTypeResolverPrivate; + FileTypeResolverPrivate *d; }; class TAGLIB_EXPORT StreamTypeResolver : public FileTypeResolver @@ -124,6 +127,9 @@ namespace TagLib { bool readAudioProperties = true, AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average) const = 0; + private: + class StreamTypeResolverPrivate; + StreamTypeResolverPrivate *d; }; /*! diff --git a/taglib/mod/modfilebase.h b/taglib/mod/modfilebase.h index d452b2bb..469e8b65 100644 --- a/taglib/mod/modfilebase.h +++ b/taglib/mod/modfilebase.h @@ -55,6 +55,9 @@ namespace TagLib { bool readU32L(unsigned long &number); bool readU16B(unsigned short &number); bool readU32B(unsigned long &number); + private: + class FileBasePrivate; + FileBasePrivate *d; }; } // namespace Mod } // namespace TagLib diff --git a/taglib/mp4/mp4coverart.h b/taglib/mp4/mp4coverart.h index 63684803..19f911e7 100644 --- a/taglib/mp4/mp4coverart.h +++ b/taglib/mp4/mp4coverart.h @@ -48,7 +48,7 @@ namespace TagLib { }; CoverArt(Format format, const ByteVector &data); - ~CoverArt(); + virtual ~CoverArt(); CoverArt(const CoverArt &item); diff --git a/taglib/mp4/mp4item.h b/taglib/mp4/mp4item.h index 526c3a64..8229f6d3 100644 --- a/taglib/mp4/mp4item.h +++ b/taglib/mp4/mp4item.h @@ -52,7 +52,7 @@ namespace TagLib { */ void swap(Item &item); - ~Item(); + virtual ~Item(); Item(int value); Item(unsigned char value); diff --git a/taglib/mpeg/id3v1/id3v1tag.h b/taglib/mpeg/id3v1/id3v1tag.h index 8bbf508b..bf787e8f 100644 --- a/taglib/mpeg/id3v1/id3v1tag.h +++ b/taglib/mpeg/id3v1/id3v1tag.h @@ -80,6 +80,10 @@ namespace TagLib { * ISO-8859-1. */ virtual ByteVector render(const String &s) const; + + private: + class StringHandlerPrivate; + StringHandlerPrivate *d; }; //! The main class in the ID3v1 implementation diff --git a/taglib/mpeg/id3v2/id3v2tag.h b/taglib/mpeg/id3v2/id3v2tag.h index 5893ed40..4a2167b0 100644 --- a/taglib/mpeg/id3v2/id3v2tag.h +++ b/taglib/mpeg/id3v2/id3v2tag.h @@ -77,6 +77,10 @@ namespace TagLib { * \a data is an ISO-8859-1 (Latin1) character array. */ virtual String parse(const ByteVector &data) const; + + private: + class Latin1StringHandlerPrivate; + Latin1StringHandlerPrivate *d; }; //! The main class in the ID3v2 implementation diff --git a/taglib/riff/wav/infotag.h b/taglib/riff/wav/infotag.h index e6265a24..7d28dfbb 100644 --- a/taglib/riff/wav/infotag.h +++ b/taglib/riff/wav/infotag.h @@ -61,7 +61,7 @@ namespace TagLib { { public: StringHandler(); - ~StringHandler(); + virtual ~StringHandler(); /*! * Decode a string from \a data. The default implementation assumes that @@ -74,6 +74,10 @@ namespace TagLib { * assumes that \a s is an UTF-8 string. */ virtual ByteVector render(const String &s) const; + + private: + class StringHandlerPrivate; + StringHandlerPrivate *d; }; //! The main class in the ID3v2 implementation diff --git a/taglib/toolkit/tdebuglistener.h b/taglib/toolkit/tdebuglistener.h index a68a4dc7..dfcf9748 100644 --- a/taglib/toolkit/tdebuglistener.h +++ b/taglib/toolkit/tdebuglistener.h @@ -56,6 +56,9 @@ namespace TagLib // Noncopyable DebugListener(const DebugListener &) = delete; DebugListener &operator=(const DebugListener &) = delete; + + class DebugListenerPrivate; + DebugListenerPrivate *d; }; /*! diff --git a/taglib/toolkit/tiostream.h b/taglib/toolkit/tiostream.h index 13aa93fe..adc9314a 100644 --- a/taglib/toolkit/tiostream.h +++ b/taglib/toolkit/tiostream.h @@ -160,6 +160,9 @@ namespace TagLib { private: IOStream(const IOStream &) = delete; IOStream &operator=(const IOStream &) = delete; + + class IOStreamPrivate; + IOStreamPrivate *d; }; } // namespace TagLib diff --git a/taglib/toolkit/tpropertymap.cpp b/taglib/toolkit/tpropertymap.cpp index c9f32622..183b5ab4 100644 --- a/taglib/toolkit/tpropertymap.cpp +++ b/taglib/toolkit/tpropertymap.cpp @@ -27,22 +27,40 @@ using namespace TagLib; -PropertyMap::PropertyMap() = default; - -PropertyMap::PropertyMap(const PropertyMap &m) = default; - -PropertyMap::PropertyMap(const SimplePropertyMap &m) +class PropertyMap::PropertyMapPrivate { - for(auto it = m.begin(); it != m.end(); ++it){ - String key = it->first.upper(); +public: + StringList unsupported; +}; + +PropertyMap::PropertyMap() : + d(new PropertyMapPrivate) +{ + +} + +PropertyMap::PropertyMap(const PropertyMap &m) : + SimplePropertyMap(m), + d(new PropertyMapPrivate) +{ + *d = *m.d; +} + +PropertyMap::PropertyMap(const SimplePropertyMap &m) : + d(new PropertyMapPrivate) +{ + for(auto [key, value] : m) { if(!key.isEmpty()) - insert(it->first, it->second); + insert(key.upper(), value); else - unsupported.append(it->first); + d->unsupported.append(key.upper()); } } -PropertyMap::~PropertyMap() = default; +PropertyMap::~PropertyMap() +{ + delete d; +} bool PropertyMap::insert(const String &key, const StringList &values) { @@ -106,7 +124,7 @@ PropertyMap &PropertyMap::merge(const PropertyMap &other) { for(auto it = other.begin(); it != other.end(); ++it) insert(it->first, it->second); - unsupported.append(other.unsupported); + d->unsupported.append(other.d->unsupported); return *this; } @@ -138,7 +156,7 @@ bool PropertyMap::operator==(const PropertyMap &other) const if( otherFind == other.end() || (otherFind->second != it->second) ) return false; } - return unsupported == other.unsupported; + return d->unsupported == other.d->unsupported; } bool PropertyMap::operator!=(const PropertyMap &other) const @@ -152,8 +170,8 @@ String PropertyMap::toString() const for(auto it = begin(); it != end(); ++it) ret += it->first+"="+it->second.toString(", ") + "\n"; - if(!unsupported.isEmpty()) - ret += "Unsupported Data: " + unsupported.toString(", ") + "\n"; + if(!d->unsupported.isEmpty()) + ret += "Unsupported Data: " + d->unsupported.toString(", ") + "\n"; return ret; } @@ -169,12 +187,14 @@ void PropertyMap::removeEmpty() StringList &PropertyMap::unsupportedData() { - return unsupported; + return d->unsupported; } -const StringList &PropertyMap::unsupportedData() const +PropertyMap &PropertyMap::operator=(const PropertyMap &other) { - return unsupported; + SimplePropertyMap::operator=(other); + *d = *other.d; + return *this; } #ifdef _MSC_VER diff --git a/taglib/toolkit/tpropertymap.h b/taglib/toolkit/tpropertymap.h index 38cc6053..27992cad 100644 --- a/taglib/toolkit/tpropertymap.h +++ b/taglib/toolkit/tpropertymap.h @@ -23,8 +23,8 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#ifndef TAGLIB_PROPERTYMAP_H_ -#define TAGLIB_PROPERTYMAP_H_ +#ifndef TAGLIB_PROPERTYMAP_H +#define TAGLIB_PROPERTYMAP_H #include "tmap.h" #include "tstringlist.h" @@ -198,7 +198,7 @@ namespace TagLib { * If no defaultValue is specified, it returns an empty string list. */ StringList value(const String &key, - const StringList &defaultValue = StringList()) const; + const StringList &defaultValue = StringList()) const; /*! * Returns a reference to the value associated with \a key. @@ -235,9 +235,11 @@ namespace TagLib { * You can remove items from the returned list, which tells TagLib to remove * those unsupported elements if you call File::setProperties() with the * same PropertyMap as argument. + * + * \deprecated */ + // TODO: Returning mutable references to internal data structures is a bad idea. StringList &unsupportedData(); - const StringList &unsupportedData() const; /*! * Removes all entries which have an empty value list. @@ -246,11 +248,12 @@ namespace TagLib { String toString() const; + PropertyMap &operator=(const PropertyMap &other); + private: - - - StringList unsupported; + class PropertyMapPrivate; + PropertyMapPrivate *d; }; } // namespace TagLib -#endif /* TAGLIB_PROPERTYMAP_H_ */ +#endif /* TAGLIB_PROPERTYMAP_H */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0c258828..56cfeb04 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -66,6 +66,7 @@ SET(test_runner_SRCS test_mpc.cpp test_opus.cpp test_speex.cpp + test_sizes.cpp ) INCLUDE_DIRECTORIES(${CPPUNIT_INCLUDE_DIR}) diff --git a/tests/test_sizes.cpp b/tests/test_sizes.cpp new file mode 100644 index 00000000..313959d0 --- /dev/null +++ b/tests/test_sizes.cpp @@ -0,0 +1,256 @@ +/*************************************************************************** + copyright : (C) 2023 Scott Wheeler + email : wheeler@kde.org +***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#include "aifffile.h" +#include "aiffproperties.h" +#include "apefile.h" +#include "apefooter.h" +#include "apeitem.h" +#include "apeproperties.h" +#include "apetag.h" +#include "asfattribute.h" +#include "asffile.h" +#include "asfpicture.h" +#include "asfproperties.h" +#include "asftag.h" +#include "attachedpictureframe.h" +#include "audioproperties.h" +#include "chapterframe.h" +#include "commentsframe.h" +#include "eventtimingcodesframe.h" +#include "fileref.h" +#include "flacfile.h" +#include "flacmetadatablock.h" +#include "flacunknownmetadatablock.h" +#include "flacpicture.h" +#include "flacproperties.h" +#include "generalencapsulatedobjectframe.h" +#include "id3v1genres.h" +#include "id3v1tag.h" +#include "id3v2.h" +#include "id3v2extendedheader.h" +#include "id3v2footer.h" +#include "id3v2frame.h" +#include "id3v2framefactory.h" +#include "id3v2header.h" +#include "id3v2synchdata.h" +#include "id3v2tag.h" +#include "infotag.h" +#include "itfile.h" +#include "itproperties.h" +#include "modfile.h" +#include "modfilebase.h" +#include "modproperties.h" +#include "modtag.h" +#include "mp4atom.h" +#include "mp4coverart.h" +#include "mp4file.h" +#include "mp4item.h" +#include "mp4properties.h" +#include "mp4tag.h" +#include "mpcfile.h" +#include "mpcproperties.h" +#include "mpegfile.h" +#include "mpegheader.h" +#include "mpegproperties.h" +#include "oggfile.h" +#include "oggflacfile.h" +#include "oggpage.h" +#include "oggpageheader.h" +#include "opusfile.h" +#include "opusproperties.h" +#include "ownershipframe.h" +#include "podcastframe.h" +#include "popularimeterframe.h" +#include "privateframe.h" +#include "relativevolumeframe.h" +#include "rifffile.h" +#include "s3mfile.h" +#include "s3mproperties.h" +#include "speexfile.h" +#include "speexproperties.h" +#include "synchronizedlyricsframe.h" +#include "tableofcontentsframe.h" +#include "tag.h" +#include "tbytevector.h" +#include "tbytevectorlist.h" +#include "tbytevectorstream.h" +#include "tdebuglistener.h" +#include "textidentificationframe.h" +#include "tfile.h" +#include "tfilestream.h" +#include "tiostream.h" +#include "tlist.h" +#include "tmap.h" +#include "tpropertymap.h" +#include "trefcounter.h" +#include "trueaudiofile.h" +#include "trueaudioproperties.h" +#include "tstring.h" +#include "tstringlist.h" +#include "uniquefileidentifierframe.h" +#include "unknownframe.h" +#include "unsynchronizedlyricsframe.h" +#include "urllinkframe.h" +#include "vorbisfile.h" +#include "vorbisproperties.h" +#include "wavfile.h" +#include "wavpackfile.h" +#include "wavpackproperties.h" +#include "wavproperties.h" +#include "xingheader.h" +#include "xiphcomment.h" +#include "xmfile.h" +#include "xmproperties.h" + +#include +#include + +using namespace std; +using namespace TagLib; + +class TestSizes : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(TestSizes); + CPPUNIT_TEST(testSizes); + CPPUNIT_TEST_SUITE_END(); + +public: + void testSizes() + { + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::APE::File)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::APE::Footer)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::APE::Item)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::APE::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::APE::Tag)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::ASF::Attribute)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ASF::File)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::ASF::Picture)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ASF::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ASF::Tag)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::AudioProperties)); + CPPUNIT_ASSERT_EQUAL(classSize(0, false), sizeof(TagLib::ByteVector)); + CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::ByteVectorList)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ByteVectorStream)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::DebugListener)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::File)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::FLAC::MetadataBlock)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::Picture)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::UnknownMetadataBlock)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::File)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::FileRef)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::FileRef::FileTypeResolver)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FileRef::StreamTypeResolver)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FileStream)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::ID3v1::StringHandler)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v1::Tag)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::AttachedPictureFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::AttachedPictureFrameV22)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::ChapterFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::CommentsFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::EventTimingCodesFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::ID3v2::ExtendedHeader)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::ID3v2::Footer)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::ID3v2::Frame)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::ID3v2::FrameFactory)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::GeneralEncapsulatedObjectFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::ID3v2::Header)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::ID3v2::Latin1StringHandler)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::OwnershipFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::PodcastFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::PopularimeterFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::PrivateFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::RelativeVolumeFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::SynchronizedLyricsFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::TableOfContentsFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::Tag)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::TextIdentificationFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::UniqueFileIdentifierFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::UnknownFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::UnsynchronizedLyricsFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ID3v2::UrlLinkFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::ID3v2::UserTextIdentificationFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::ID3v2::UserUrlLinkFrame)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::IOStream)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::IT::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::IT::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(0, false), sizeof(TagLib::List)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::MP4::CoverArt)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MP4::File)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::MP4::Item)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MP4::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MP4::Tag)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MPC::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MPC::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MPEG::File)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::MPEG::Header)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MPEG::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::MPEG::XingHeader)); + CPPUNIT_ASSERT_EQUAL(classSize(0, false), sizeof(TagLib::Map)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::Mod::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Mod::FileBase)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Mod::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Mod::Tag)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::Ogg::FLAC::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Ogg::File)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::Ogg::Opus::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Ogg::Opus::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::Ogg::Page)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::Ogg::PageHeader)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::Ogg::Speex::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Ogg::Speex::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::Ogg::Vorbis::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Ogg::Vorbis::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Ogg::XiphComment)); + CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::PropertyMap)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::RIFF::AIFF::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::RIFF::AIFF::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::RIFF::File)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::RIFF::Info::StringHandler)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::RIFF::Info::Tag)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::RIFF::WAV::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::RIFF::WAV::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::S3M::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::S3M::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(0, false), sizeof(TagLib::String)); + CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::StringList)); + CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::Tag)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::TrueAudio::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::TrueAudio::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::WavPack::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::WavPack::Properties)); + CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::XM::File)); + CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::XM::Properties)); + } + +private: + constexpr size_t classSize(int baseClasses, bool isVirtual) + { + return sizeof(void *) * (baseClasses + static_cast(isVirtual) + 1); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestSizes);