Tag Parser  10.0.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
mediafileinfo.cpp
Go to the documentation of this file.
1 #include "./helper.h"
2 
3 #include "../abstracttrack.h"
4 #include "../mediafileinfo.h"
5 #include "../progressfeedback.h"
6 #include "../tag.h"
7 
8 #include <c++utilities/tests/testutils.h>
9 using namespace CppUtilities;
10 
11 #include <cppunit/TestFixture.h>
12 #include <cppunit/extensions/HelperMacros.h>
13 
14 #include <cstdio>
15 
16 using namespace std;
17 using namespace CppUtilities::Literals;
18 using namespace TagParser;
19 
20 using namespace CPPUNIT_NS;
21 
26 class MediaFileInfoTests : public TestFixture {
27  CPPUNIT_TEST_SUITE(MediaFileInfoTests);
28  CPPUNIT_TEST(testInitialStatus);
29  CPPUNIT_TEST(testFileSystemMethods);
30  CPPUNIT_TEST(testParsingUnsupportedFile);
31  CPPUNIT_TEST(testFullParseAndFurtherProperties);
32  CPPUNIT_TEST_SUITE_END();
33 
34 public:
35  void setUp() override;
36  void tearDown() override;
37 
38  void testInitialStatus();
39  void testFileSystemMethods();
40  void testParsingUnsupportedFile();
41  void testPartialParsingAndTagCreationOfMp4File();
42 
43  void testFullParseAndFurtherProperties();
44 };
45 
47 
49 {
50 }
51 
53 {
54 }
55 
57 {
58  const MediaFileInfo file;
59  CPPUNIT_ASSERT(!file.areTagsSupported());
60  CPPUNIT_ASSERT(!file.areTracksSupported());
61  CPPUNIT_ASSERT(!file.areChaptersSupported());
62  CPPUNIT_ASSERT(!file.areAttachmentsSupported());
63  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.containerParsingStatus());
64  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tagsParsingStatus());
65  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tracksParsingStatus());
66  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.chaptersParsingStatus());
67  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.attachmentsParsingStatus());
68  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Unknown, file.containerFormat());
69 }
70 
72 {
73  MediaFileInfo file("/usr/bin/unsupported.bin"sv);
74  CPPUNIT_ASSERT_EQUAL("/usr/bin"s, file.containingDirectory());
75  CPPUNIT_ASSERT_EQUAL("unsupported.bin"s, file.fileName());
76  CPPUNIT_ASSERT_EQUAL("unsupported"s, file.fileName(true));
77  CPPUNIT_ASSERT_EQUAL("/usr/bin/unsupported"s, file.pathWithoutExtension());
78  CPPUNIT_ASSERT_EQUAL(".bin"s, file.extension());
79  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(0), file.size());
80  file.reportPathChanged(testFilePath("unsupported.bin"));
81  file.open(true);
82  CPPUNIT_ASSERT(file.isOpen());
83  CPPUNIT_ASSERT(file.isReadOnly());
84  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(41), file.size());
85 }
86 
88 {
89  Diagnostics diag;
91  MediaFileInfo file(testFilePath("unsupported.bin"));
92  file.parseContainerFormat(diag, progress);
93  file.parseTags(diag, progress);
94  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.containerParsingStatus());
95  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.tagsParsingStatus());
96  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tracksParsingStatus());
97  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.chaptersParsingStatus());
98  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.attachmentsParsingStatus());
99  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Unknown, file.containerFormat());
100  file.invalidate();
101 }
102 
104 {
105  Diagnostics diag;
106  AbortableProgressFeedback progress;
107  MediaFileInfo file(testFilePath("mtx-test-data/aac/he-aacv2-ps.m4a"));
108  file.open(true);
109  file.parseContainerFormat(diag, progress);
110  file.parseTags(diag, progress);
111  file.parseAttachments(diag, progress);
112  file.close();
113  CPPUNIT_ASSERT_THROW_MESSAGE("std::ios_base::failure thrown if file closed", file.parseTracks(diag, progress), std::ios_base::failure);
114  CPPUNIT_ASSERT(file.areTagsSupported());
115  CPPUNIT_ASSERT(file.areTracksSupported());
116  CPPUNIT_ASSERT(!file.areChaptersSupported());
117  CPPUNIT_ASSERT(!file.areAttachmentsSupported());
118  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.containerParsingStatus());
119  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tagsParsingStatus());
120  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tracksParsingStatus());
121  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.chaptersParsingStatus());
122  CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.attachmentsParsingStatus());
123  CPPUNIT_ASSERT_EQUAL(0_st, file.trackCount());
124  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, file.containerFormat());
125  CPPUNIT_ASSERT_EQUAL(Diagnostics({ DiagMessage(DiagLevel::Information,
126  "Parsing attachments is not implemented for the container format of the file.", "parsing attachments") }),
127  diag);
128  CPPUNIT_ASSERT_EQUAL(DiagLevel::Information, diag.level());
129 
130  // create/remove tag
131  CPPUNIT_ASSERT_EQUAL(0_st, file.matroskaTags().size());
132  CPPUNIT_ASSERT(!file.id3v1Tag());
133  CPPUNIT_ASSERT_EQUAL(0_st, file.id3v2Tags().size());
134  CPPUNIT_ASSERT(!file.vorbisComment());
135  CPPUNIT_ASSERT(!file.mp4Tag());
136  // NOTE: Maybe it should not be possible to create ID3 tags for MP4 file? It will be ignored anyways.
137  CPPUNIT_ASSERT(file.createId3v1Tag());
138  CPPUNIT_ASSERT(file.id3v1Tag());
139  CPPUNIT_ASSERT(file.createId3v2Tag());
140  CPPUNIT_ASSERT_EQUAL(1_st, file.id3v2Tags().size());
141  CPPUNIT_ASSERT(!file.createVorbisComment());
142  CPPUNIT_ASSERT(!file.vorbisComment());
143  CPPUNIT_ASSERT(!file.removeVorbisComment());
144  file.createAppropriateTags();
145  CPPUNIT_ASSERT(file.mp4Tag());
146 }
147 
149 {
150  Diagnostics diag;
151  AbortableProgressFeedback progress;
152  MediaFileInfo file(testFilePath("matroska_wave1/test1.mkv"));
153  file.open(true);
154  file.parseEverything(diag, progress);
155  // calling parse methods twice should not do anything (and hence can not fail anymore because the file has already been closed)
156  file.close();
157  file.parseEverything(diag, progress);
158  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.containerParsingStatus());
159  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tagsParsingStatus());
160  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tracksParsingStatus());
161  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.chaptersParsingStatus());
162  CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.attachmentsParsingStatus());
163  CPPUNIT_ASSERT_EQUAL(ContainerFormat::Matroska, file.containerFormat());
164 
165  // general info
166  CPPUNIT_ASSERT(file.container());
167  CPPUNIT_ASSERT(file.areTagsSupported());
168  CPPUNIT_ASSERT(file.hasAnyTag());
169  CPPUNIT_ASSERT_EQUAL(1_st, file.tags().size());
170  CPPUNIT_ASSERT_EQUAL(1_st, file.matroskaTags().size());
171  CPPUNIT_ASSERT(!file.mp4Tag());
172  CPPUNIT_ASSERT(!file.vorbisComment());
173  CPPUNIT_ASSERT(file.areTracksSupported());
174  CPPUNIT_ASSERT_EQUAL(2_st, file.trackCount());
175  CPPUNIT_ASSERT(file.areChaptersSupported());
176  CPPUNIT_ASSERT_EQUAL(0_st, file.chapters().size());
177  CPPUNIT_ASSERT(file.areAttachmentsSupported());
178  CPPUNIT_ASSERT_EQUAL(0_st, file.attachments().size());
179 
180  // notifications
181  CPPUNIT_ASSERT_EQUAL(Diagnostics(), diag);
182  CPPUNIT_ASSERT_EQUAL(DiagLevel::None, diag.level());
183  diag.emplace_back(DiagLevel::Warning, "warning", "test");
184  CPPUNIT_ASSERT_EQUAL(DiagLevel::Warning, diag.level());
185  diag.emplace_back(DiagLevel::Critical, "error", "test");
186  CPPUNIT_ASSERT_EQUAL(DiagLevel::Critical, diag.level());
187 
188  // track info / available languages
189  file.tracks().back()->setLocale(Locale("eng"sv, LocaleFormat::ISO_639_2_B));
190  CPPUNIT_ASSERT_EQUAL(unordered_set<string>({ "eng" }), file.availableLanguages());
191  CPPUNIT_ASSERT_EQUAL(unordered_set<string>({}), file.availableLanguages(MediaType::Text));
192  CPPUNIT_ASSERT_EQUAL("ID: 2422994868, type: Video"s, file.tracks()[0]->label());
193  CPPUNIT_ASSERT_EQUAL("ID: 3653291187, type: Audio, language: English"s, file.tracks()[1]->label());
194  CPPUNIT_ASSERT_EQUAL("MS-MPEG-4-480p / MP3-2ch-eng"s, file.technicalSummary());
195 }
The MediaFileInfoTests tests convenience methods provided by TagParser::MediaFileInfo.
void testFullParseAndFurtherProperties()
void testParsingUnsupportedFile()
void setUp() override
void tearDown() override
void testPartialParsingAndTagCreationOfMp4File()
The AbortableProgressFeedback class provides feedback about an ongoing operation via callbacks.
static std::string fileName(std::string_view path, bool cutExtension=false)
Returns the file name of the given file.
static std::string extension(std::string_view path)
Returns the extension of the given file.
void reportPathChanged(std::string_view newPath)
Call this function to report that the path changed.
void invalidate()
Invalidates the file info manually.
bool isReadOnly() const
Indicates whether the last open()/reopen() call was read-only.
Definition: basicfileinfo.h:77
static std::string containingDirectory(std::string_view path)
Returns the path of the directory containing the given file.
std::uint64_t size() const
Returns size of the current file in bytes.
void open(bool readOnly=false)
Opens a std::fstream for the current file.
static std::string pathWithoutExtension(std::string_view fullPath)
Returns a copy of the given path without the extension/suffix.
void close()
A possibly opened std::fstream will be closed.
bool isOpen() const
Indicates whether a std::fstream is open for the current file.
Definition: basicfileinfo.h:69
The DiagMessage class holds an information, warning or error gathered during parsing or making.
Definition: diagnostics.h:41
The Diagnostics class is a container for DiagMessage.
Definition: diagnostics.h:156
DiagLevel level() const
Returns the worst diag level present in the container.
Definition: diagnostics.cpp:55
The MediaFileInfo class allows to read and write tag information providing a container/tag format ind...
Definition: mediafileinfo.h:74
const std::vector< std::unique_ptr< Id3v2Tag > > & id3v2Tags() const
Returns pointers to the assigned ID3v2 tags.
void parseEverything(Diagnostics &diag, AbortableProgressFeedback &progress)
Parses the container format, the tracks and the tag information of the current file.
const std::vector< std::unique_ptr< MatroskaTag > > & matroskaTags() const
Returns pointers to the assigned Matroska tags.
std::vector< AbstractTrack * > tracks() const
Returns the tracks for the current file.
bool areChaptersSupported() const
Returns an indication whether this library supports parsing the chapters of the current file.
ParsingStatus tagsParsingStatus() const
Returns an indication whether tag information has been parsed yet.
VorbisComment * createVorbisComment()
Creates a Vorbis comment for the current file.
VorbisComment * vorbisComment() const
Returns a pointer to the first assigned Vorbis comment or nullptr if none is assigned.
std::size_t trackCount() const
Returns the number of tracks that could be parsed.
void parseAttachments(Diagnostics &diag, AbortableProgressFeedback &progress)
Parses the attachments of the current file.
void parseTracks(Diagnostics &diag, AbortableProgressFeedback &progress)
Parses the tracks of the current file.
bool areAttachmentsSupported() const
Returns an indication whether this library supports attachment format of the current file.
void parseContainerFormat(Diagnostics &diag, AbortableProgressFeedback &progress)
Parses the container format of the current file.
ParsingStatus tracksParsingStatus() const
Returns an indication whether tracks have been parsed yet.
Id3v1Tag * id3v1Tag() const
Returns a pointer to the assigned ID3v1 tag or nullptr if none is assigned.
std::string technicalSummary() const
Generates a short technical summary about the file's tracks.
bool removeVorbisComment()
Removes all assigned Vorbis comment from the current file.
void parseTags(Diagnostics &diag, AbortableProgressFeedback &progress)
Parses the tag(s) of the current file.
Id3v2Tag * createId3v2Tag()
Creates an ID3v2 tag for the current file.
bool areTracksSupported() const
Returns an indication whether this library supports parsing the tracks information of the current fil...
bool createAppropriateTags(const TagCreationSettings &settings=TagCreationSettings())
Ensures appropriate tags are created according the given settings.
void tags(std::vector< Tag * > &tags) const
Stores all tags assigned to the current file in the specified vector.
ParsingStatus attachmentsParsingStatus() const
Returns whether the attachments have been parsed yet.
Id3v1Tag * createId3v1Tag()
Creates an ID3v1 tag for the current file.
std::unordered_set< std::string > availableLanguages(TagParser::MediaType type=TagParser::MediaType::Audio) const
Determines the available languages for specified media type (by default MediaType::Audio).
bool areTagsSupported() const
Returns an indication whether this library supports the tag format of the current file.
AbstractContainer * container() const
Returns the container for the current file.
ContainerFormat containerFormat() const
Returns the container format of the current file.
ParsingStatus containerParsingStatus() const
Returns an indication whether the container format has been parsed yet.
std::vector< AbstractChapter * > chapters() const
Returns all chapters assigned to the current file.
std::vector< AbstractAttachment * > attachments() const
Returns all attachments assigned to the current file.
ParsingStatus chaptersParsingStatus() const
Returns whether the chapters have been parsed yet.
bool hasAnyTag() const
Returns an indication whether a tag of any format is assigned.
Mp4Tag * mp4Tag() const
Returns a pointer to the assigned MP4 tag or nullptr if none is assigned.
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
The Locale struct specifies a language and/or a country using one or more LocaleDetail objects.
Definition: localehelper.h:61
CPPUNIT_TEST_SUITE_REGISTRATION(MediaFileInfoTests)