Reworked internal namespaces

This commit is contained in:
emeric
2024-03-12 23:11:29 +01:00
501 changed files with 12675 additions and 12702 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ target_link_libraries(lmsmetadata PRIVATE
)
target_link_libraries(lmsmetadata PUBLIC
lmsutils
lmscore
std::filesystem
)
+7 -8
View File
@@ -24,15 +24,14 @@
#include "av/IAudioFile.hpp"
#include "metadata/Exception.hpp"
#include "utils/ILogger.hpp"
#include "utils/String.hpp"
#include "core/ILogger.hpp"
#include "core/String.hpp"
#include "Utils.hpp"
namespace MetaData
namespace lms::metadata
{
namespace
{
// Mapping to internal avformat names and/or common alternative custom names
static const std::unordered_map<TagType, std::vector<std::string>> tagMapping
{
@@ -144,19 +143,19 @@ namespace MetaData
{
try
{
const auto audioFile{ Av::parseAudioFile(p) };
const auto audioFile{ av::parseAudioFile(p) };
_containerInfo = audioFile->getContainerInfo();
_metaDataMap = audioFile->getMetaData();
_hasEmbeddedCover = audioFile->hasAttachedPictures();
if (debug && Service<ILogger>::get()->isSeverityActive(Severity::DEBUG))
if (debug && core::Service<core::logging::ILogger>::get()->isSeverityActive(core::logging::Severity::DEBUG))
{
for (const auto& [key, value] : _metaDataMap)
LMS_LOG(METADATA, DEBUG, "Key = '" << key << "', value = '" << value << "'");
}
}
catch (Av::Exception& e)
catch (av::Exception& e)
{
throw ParseException{};
}
@@ -199,4 +198,4 @@ namespace MetaData
visitor("", value);
});
}
} // namespace MetaData
} // namespace lms::metadata
+4 -4
View File
@@ -25,7 +25,7 @@
#include "metadata/IParser.hpp"
#include "ITagReader.hpp"
namespace MetaData
namespace lms::metadata
{
class AvFormatTagReader : public ITagReader
{
@@ -46,9 +46,9 @@ namespace MetaData
std::size_t getBitsPerSample() const override { return 0; }
std::size_t getSampleRate() const override { return 0; }
Av::IAudioFile::MetadataMap _metaDataMap;
Av::ContainerInfo _containerInfo;
av::IAudioFile::MetadataMap _metaDataMap;
av::ContainerInfo _containerInfo;
bool _hasEmbeddedCover{};
};
} // namespace MetaData
} // namespace lms::metadata
+2 -2
View File
@@ -22,7 +22,7 @@
#include <chrono>
#include <functional>
namespace MetaData
namespace lms::metadata
{
// using picard internal names
// see https://picard-docs.musicbrainz.org/en/appendices/tag_mapping.html
@@ -159,4 +159,4 @@ namespace MetaData
virtual std::size_t getBitsPerSample() const = 0;
virtual std::size_t getSampleRate() const = 0;
};
} // namespace MetaData
} // namespace lms::metadata
+30 -30
View File
@@ -22,14 +22,14 @@
#include <span>
#include "metadata/Exception.hpp"
#include "utils/ILogger.hpp"
#include "utils/String.hpp"
#include "core/ILogger.hpp"
#include "core/String.hpp"
#include "AvFormatTagReader.hpp"
#include "TagLibTagReader.hpp"
#include "Utils.hpp"
namespace MetaData
namespace lms::metadata
{
namespace
{
@@ -39,7 +39,7 @@ namespace MetaData
{
auto visitTagIfNonEmpty{ [&](std::string_view tag)
{
tag = StringUtils::stringTrim(tag);
tag = core::stringUtils::stringTrim(tag);
if (!tag.empty())
visitor(tag);
} };
@@ -48,7 +48,7 @@ namespace MetaData
{
if (value.find(tagDelimiter) != std::string_view::npos)
{
for (std::string_view splitTag : StringUtils::splitString(value, tagDelimiter))
for (std::string_view splitTag : core::stringUtils::splitString(value, tagDelimiter))
visitTagIfNonEmpty(splitTag);
return;
@@ -69,10 +69,10 @@ namespace MetaData
{
auto addTagIfNonEmpty{ [&res](std::string_view tag)
{
tag = StringUtils::stringTrim(tag);
tag = core::stringUtils::stringTrim(tag);
if (!tag.empty())
{
std::optional<T> val{ StringUtils::readAs<T>(tag) };
std::optional<T> val{ core::stringUtils::readAs<T>(tag) };
if (val)
res.emplace_back(std::move(*val));
}
@@ -84,7 +84,7 @@ namespace MetaData
{
if (value.find(tagDelimiter) != std::string_view::npos)
{
for (std::string_view splitTag : StringUtils::splitString(value, tagDelimiter))
for (std::string_view splitTag : core::stringUtils::splitString(value, tagDelimiter))
addTagIfNonEmpty(splitTag);
return;
@@ -137,7 +137,7 @@ namespace MetaData
return {};
std::vector<std::string> artistSortNames{ getTagValuesFirstMatchAs<std::string>(tagReader, artistSortTagNames, artistTagDelimiters) };
std::vector<UUID> artistMBIDs{ getTagValuesFirstMatchAs<UUID>(tagReader, artistMBIDTagNames, artistTagDelimiters) };
std::vector<core::UUID> artistMBIDs{ getTagValuesFirstMatchAs<core::UUID>(tagReader, artistMBIDTagNames, artistTagDelimiters) };
std::vector<Artist> artists;
artists.reserve(artistNames.size());
@@ -166,15 +166,15 @@ namespace MetaData
if (role.empty())
{
// "PERFORMER" "artist (role)"
Utils::PerformerArtist performer{ Utils::extractPerformerAndRole(name) };
StringUtils::capitalize(performer.role);
utils::PerformerArtist performer{ utils::extractPerformerAndRole(name) };
core::stringUtils::capitalize(performer.role);
performers[performer.role].push_back(std::move(performer.artist));
}
else
{
// "PERFORMER:role", "artist" (MP3)
std::string roleCapitalized{ StringUtils::stringToLower(role) };
StringUtils::capitalize(roleCapitalized);
std::string roleCapitalized{ core::stringUtils::stringToLower(role) };
core::stringUtils::capitalize(roleCapitalized);
performers[roleCapitalized].push_back(Artist{ name });
}
});
@@ -195,7 +195,7 @@ namespace MetaData
switch (_parserBackend)
{
case ParserBackend::TagLib:
LMS_LOG(METADATA, INFO, "Using TagLib parser with read style = " << Utils::readStyleToString(readStyle));
LMS_LOG(METADATA, INFO, "Using TagLib parser with read style = " << utils::readStyleToString(readStyle));
break;
case ParserBackend::AvFormat:
@@ -252,37 +252,37 @@ namespace MetaData
track.hasCover = tagReader.hasEmbeddedCover();
track.title = getTagValueAs<std::string>(tagReader, TagType::TrackTitle).value_or("");
track.mbid = getTagValueAs<UUID>(tagReader, TagType::MusicBrainzTrackID);
track.recordingMBID = getTagValueAs<UUID>(tagReader, TagType::MusicBrainzRecordingID);
track.acoustID = getTagValueAs<UUID>(tagReader, TagType::AcoustID);
track.mbid = getTagValueAs<core::UUID>(tagReader, TagType::MusicBrainzTrackID);
track.recordingMBID = getTagValueAs<core::UUID>(tagReader, TagType::MusicBrainzRecordingID);
track.acoustID = getTagValueAs<core::UUID>(tagReader, TagType::AcoustID);
track.position = getTagValueAs<std::size_t>(tagReader, TagType::TrackNumber); // May parse 'Number/Total', that's fine
if (auto dateStr = getTagValueAs<std::string>(tagReader, TagType::Date))
{
if (const Wt::WDate date{ Utils::parseDate(*dateStr) }; date.isValid())
if (const Wt::WDate date{ utils::parseDate(*dateStr) }; date.isValid())
{
track.date = date;
track.year = date.year();
}
else
{
track.year = Utils::parseYear(*dateStr);
track.year = utils::parseYear(*dateStr);
}
}
if (auto dateStr = getTagValueAs<std::string>(tagReader, TagType::OriginalReleaseDate))
{
if (const Wt::WDate date{ Utils::parseDate(*dateStr) }; date.isValid())
if (const Wt::WDate date{ utils::parseDate(*dateStr) }; date.isValid())
{
track.originalDate = date;
track.originalYear = date.year();
}
else
{
track.originalYear = Utils::parseYear(*dateStr);
track.originalYear = utils::parseYear(*dateStr);
}
}
if (auto dateStr = getTagValueAs<std::string>(tagReader, TagType::OriginalReleaseYear))
{
track.originalYear = Utils::parseYear(*dateStr);
track.originalYear = utils::parseYear(*dateStr);
}
track.copyright = getTagValueAs<std::string>(tagReader, TagType::Copyright).value_or("");
@@ -294,7 +294,7 @@ namespace MetaData
{
visitTagValues(tagReader, userExtraTag, _defaultTagDelimiters, [&](std::string_view value)
{
value = StringUtils::stringTrim(value);
value = core::stringUtils::stringTrim(value);
if (!value.empty())
track.userExtraTags[userExtraTag].push_back(std::string{ value });
});
@@ -342,9 +342,9 @@ namespace MetaData
if (const auto value{ getTagValueAs<std::string>(tagReader, TagType::TrackNumber) })
{
// Expecting 'Number/Total'
const std::vector<std::string_view> strings{ StringUtils::splitString(*value, '/') };
const std::vector<std::string_view> strings{ core::stringUtils::splitString(*value, '/') };
if (strings.size() == 2)
medium->trackCount = StringUtils::readAs<std::size_t>(strings[1]);
medium->trackCount = core::stringUtils::readAs<std::size_t>(strings[1]);
}
}
// Expecting 'Number[/Total]'
@@ -370,8 +370,8 @@ namespace MetaData
release->name = std::move(*releaseName);
release->sortName = getTagValueAs<std::string>(tagReader, TagType::AlbumSortOrder).value_or("");
release->artistDisplayName = getTagValueAs<std::string>(tagReader, TagType::AlbumArtist).value_or(""); // TODO try to join albumartists if present
release->mbid = getTagValueAs<UUID>(tagReader, TagType::MusicBrainzReleaseID);
release->groupMBID = getTagValueAs<UUID>(tagReader, TagType::MusicBrainzReleaseGroupID);
release->mbid = getTagValueAs<core::UUID>(tagReader, TagType::MusicBrainzReleaseID);
release->groupMBID = getTagValueAs<core::UUID>(tagReader, TagType::MusicBrainzReleaseGroupID);
release->artists = getArtists(tagReader, { TagType::AlbumArtists, TagType::AlbumArtist }, { TagType::AlbumArtistsSortOrder, TagType::AlbumArtistSortOrder }, { TagType::MusicBrainzReleaseArtistID }, _artistTagDelimiters);
release->mediumCount = getTagValueAs<std::size_t>(tagReader, TagType::TotalDiscs);
if (!release->mediumCount)
@@ -380,9 +380,9 @@ namespace MetaData
if (const auto value{ getTagValueAs<std::string>(tagReader, TagType::DiscNumber) })
{
// Expecting 'Number/Total'
const std::vector<std::string_view> strings{ StringUtils::splitString(*value, '/') };
const std::vector<std::string_view> strings{ core::stringUtils::splitString(*value, '/') };
if (strings.size() == 2)
release->mediumCount = StringUtils::readAs<std::size_t>(strings[1]);
release->mediumCount = core::stringUtils::readAs<std::size_t>(strings[1]);
}
}
@@ -390,4 +390,4 @@ namespace MetaData
return release;
}
} // namespace MetaData
} // namespace lms::metadata
+2 -2
View File
@@ -22,7 +22,7 @@
#include "metadata/IParser.hpp"
#include "ITagReader.hpp"
namespace MetaData
namespace lms::metadata
{
class Parser : public IParser
{
@@ -50,5 +50,5 @@ namespace MetaData
std::vector<std::string> _artistTagDelimiters;
std::vector<std::string> _defaultTagDelimiters;
};
} // namespace MetaData
} // namespace lms::metadata
+8 -8
View File
@@ -34,11 +34,11 @@
#include <taglib/wavpackfile.h>
#include "metadata/Exception.hpp"
#include "utils/ILogger.hpp"
#include "utils/ITraceLogger.hpp"
#include "utils/String.hpp"
#include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp"
#include "core/String.hpp"
namespace MetaData
namespace lms::metadata
{
namespace
{
@@ -159,7 +159,7 @@ namespace MetaData
case ParserReadStyle::Accurate: return TagLib::AudioProperties::ReadStyle::Accurate;
}
throw LmsException{ "Cannot convert read style" };
throw core::LmsException{ "Cannot convert read style" };
}
void mergeTagMaps(TagLib::PropertyMap& dst, TagLib::PropertyMap&& src)
@@ -223,7 +223,7 @@ namespace MetaData
if (attributeList.isEmpty())
continue;
std::string strName{ StringUtils::stringToUpper(name.to8Bit(true)) };
std::string strName{ core::stringUtils::stringToUpper(name.to8Bit(true)) };
if (strName.find("WM/") == 0 || _propertyMap.find(strName) != std::cend(_propertyMap))
continue;
@@ -290,7 +290,7 @@ namespace MetaData
_hasEmbeddedCover = true;
}
if (debug && Service<ILogger>::get()->isSeverityActive(Severity::DEBUG))
if (debug && core::Service<core::logging::ILogger>::get()->isSeverityActive(core::logging::Severity::DEBUG))
{
for (const auto& [key, values] : _propertyMap)
{
@@ -380,4 +380,4 @@ namespace MetaData
{
return static_cast<std::size_t>(_file.audioProperties()->sampleRate());
}
} // namespace MetaData
} // namespace lms::metadata
+2 -2
View File
@@ -27,7 +27,7 @@
#include "metadata/IParser.hpp"
#include "ITagReader.hpp"
namespace MetaData
namespace lms::metadata
{
class TagLibTagReader : public ITagReader
{
@@ -52,4 +52,4 @@ namespace MetaData
TagLib::PropertyMap _propertyMap; // case-insensitive keys
bool _hasEmbeddedCover{};
};
} // namespace MetaData
} // namespace lms::metadata
+6 -6
View File
@@ -23,9 +23,9 @@
#include <iomanip>
#include <sstream>
#include "utils/Exception.hpp"
#include "core/Exception.hpp"
namespace MetaData::Utils
namespace lms::metadata::utils
{
Wt::WDate parseDate(std::string_view dateStr)
{
@@ -105,7 +105,7 @@ namespace MetaData::Utils
case ParserReadStyle::Accurate: return "accurate";
}
throw LmsException{ "Unknown read style" };
throw core::LmsException{ "Unknown read style" };
}
PerformerArtist extractPerformerAndRole(std::string_view entry)
@@ -138,8 +138,8 @@ namespace MetaData::Utils
if (--count == 0)
{
roleBegin = currentIndex + 1;
role = StringUtils::stringTrim(entry.substr(roleBegin, roleEnd - roleBegin));
artistName = StringUtils::stringTrim(entry.substr(0, currentIndex));
role = core::stringUtils::stringTrim(entry.substr(roleBegin, roleEnd - roleBegin));
artistName = core::stringUtils::stringTrim(entry.substr(0, currentIndex));
break;
}
}
@@ -148,7 +148,7 @@ namespace MetaData::Utils
}
if (!roleEnd || !roleBegin)
artistName = StringUtils::stringTrim(entry);
artistName = core::stringUtils::stringTrim(entry);
return PerformerArtist{ Artist {artistName}, std::string {role} };
}
+1 -1
View File
@@ -26,7 +26,7 @@
#include "metadata/IParser.hpp"
namespace MetaData::Utils
namespace lms::metadata::utils
{
Wt::WDate parseDate(std::string_view dateStr);
std::optional<int> parseYear(std::string_view yearStr);
@@ -19,11 +19,11 @@
#pragma once
#include "utils/Exception.hpp"
#include "core/Exception.hpp"
namespace MetaData
namespace lms::metadata
{
class Exception : public LmsException
class Exception : public core::LmsException
{
public:
using LmsException::LmsException;
+10 -10
View File
@@ -29,9 +29,9 @@
#include <vector>
#include <Wt/WDate.h>
#include "utils/UUID.hpp"
#include "core/UUID.hpp"
namespace MetaData
namespace lms::metadata
{
using Tags = std::map<std::string /* type */, std::vector<std::string> /* values */>;
@@ -39,12 +39,12 @@ namespace MetaData
struct Artist
{
std::optional<UUID> mbid;
std::optional<core::UUID> mbid;
std::string name;
std::optional<std::string> sortName;
Artist(std::string_view _name) : name{ _name } {}
Artist(std::optional<UUID> _mbid, std::string_view _name, std::optional<std::string> _sortName) : mbid{ std::move(_mbid) }, name{ _name }, sortName{ std::move(_sortName) } {}
Artist(std::optional<core::UUID> _mbid, std::string_view _name, std::optional<std::string> _sortName) : mbid{ std::move(_mbid) }, name{ _name }, sortName{ std::move(_sortName) } {}
bool operator<=>(const Artist&) const = default;
};
@@ -53,8 +53,8 @@ namespace MetaData
struct Release
{
std::optional<UUID> mbid;
std::optional<UUID> groupMBID;
std::optional<core::UUID> mbid;
std::optional<core::UUID> groupMBID;
std::string name;
std::string sortName;
std::string artistDisplayName;
@@ -85,8 +85,8 @@ namespace MetaData
struct Track
{
std::optional<UUID> mbid;
std::optional<UUID> recordingMBID;
std::optional<core::UUID> mbid;
std::optional<core::UUID> recordingMBID;
std::string title;
std::optional<Medium> medium;
std::optional<std::size_t> position; // in medium
@@ -103,7 +103,7 @@ namespace MetaData
std::optional<int> originalYear{};
Wt::WDate originalDate;
bool hasCover{};
std::optional<UUID> acoustID;
std::optional<core::UUID> acoustID;
std::string copyright;
std::string copyrightURL;
std::optional<float> replayGain;
@@ -143,4 +143,4 @@ namespace MetaData
Accurate,
};
std::unique_ptr<IParser> createParser(ParserBackend parserBackend, ParserReadStyle parserReadStyle);
} // namespace MetaData
}
+10 -10
View File
@@ -24,7 +24,7 @@
#include "TestTagReader.hpp"
#include "Parser.hpp"
namespace MetaData
namespace lms::metadata
{
TEST(Parser, generalTest)
{
@@ -88,15 +88,15 @@ namespace MetaData
std::unique_ptr<Track> track{ parser.parse(testTags) };
EXPECT_EQ(track->acoustID, UUID::fromString("e987a441-e134-4960-8019-274eddacc418"));
EXPECT_EQ(track->acoustID, core::UUID::fromString("e987a441-e134-4960-8019-274eddacc418"));
EXPECT_EQ(track->artistDisplayName, "MyArtist1 & MyArtist2");
ASSERT_EQ(track->artists.size(), 2);
EXPECT_EQ(track->artists[0].name, "MyArtist1");
EXPECT_EQ(track->artists[0].sortName, "MyArtist1SortName");
EXPECT_EQ(track->artists[0].mbid, UUID::fromString("9d2e0c8c-8c5e-4372-a061-590955eaeaae"));
EXPECT_EQ(track->artists[0].mbid, core::UUID::fromString("9d2e0c8c-8c5e-4372-a061-590955eaeaae"));
EXPECT_EQ(track->artists[1].name, "MyArtist2");
EXPECT_EQ(track->artists[1].sortName, "MyArtist2SortName");
EXPECT_EQ(track->artists[1].mbid, UUID::fromString("5e2cf87f-c8d7-4504-8a86-954dc0840229"));
EXPECT_EQ(track->artists[1].mbid, core::UUID::fromString("5e2cf87f-c8d7-4504-8a86-954dc0840229"));
EXPECT_EQ(track->bitrate, TestTagReader::trackBitrate);
ASSERT_EQ(track->composerArtists.size(), 2);
EXPECT_EQ(track->composerArtists[0].name, "MyComposer1");
@@ -130,7 +130,7 @@ namespace MetaData
EXPECT_EQ(track->lyricistArtists[0].name, "MyLyricist1");
EXPECT_EQ(track->lyricistArtists[1].name, "MyLyricist2");
ASSERT_TRUE(track->mbid.has_value());
EXPECT_EQ(track->mbid.value(), UUID::fromString("0afb190a-6735-46df-a16d-199f48206e4a"));
EXPECT_EQ(track->mbid.value(), core::UUID::fromString("0afb190a-6735-46df-a16d-199f48206e4a"));
ASSERT_EQ(track->mixerArtists.size(), 2);
EXPECT_EQ(track->mixerArtists[0].name, "MyMixer1");
EXPECT_EQ(track->mixerArtists[1].name, "MyMixer2");
@@ -156,7 +156,7 @@ namespace MetaData
EXPECT_EQ(track->producerArtists[0].name, "MyProducer1");
EXPECT_EQ(track->producerArtists[1].name, "MyProducer2");
ASSERT_TRUE(track->recordingMBID.has_value());
EXPECT_EQ(track->recordingMBID.value(), UUID::fromString("bd3fc666-89de-4ac8-93f6-2dbf028ad8d5"));
EXPECT_EQ(track->recordingMBID.value(), core::UUID::fromString("bd3fc666-89de-4ac8-93f6-2dbf028ad8d5"));
ASSERT_TRUE(track->replayGain.has_value());
EXPECT_FLOAT_EQ(track->replayGain.value(), -0.33);
ASSERT_EQ(track->remixerArtists.size(), 2);
@@ -189,13 +189,13 @@ namespace MetaData
ASSERT_EQ(track->medium->release->artists.size(), 2);
EXPECT_EQ(track->medium->release->artists[0].name, "MyAlbumArtist1");
EXPECT_EQ(track->medium->release->artists[0].sortName, "MyAlbumArtist1SortName");
EXPECT_EQ(track->medium->release->artists[0].mbid, UUID::fromString("6fbf097c-1487-43e8-874b-50dd074398a7"));
EXPECT_EQ(track->medium->release->artists[0].mbid, core::UUID::fromString("6fbf097c-1487-43e8-874b-50dd074398a7"));
EXPECT_EQ(track->medium->release->artists[1].name, "MyAlbumArtist2");
EXPECT_EQ(track->medium->release->artists[1].sortName, "MyAlbumArtist2SortName");
EXPECT_EQ(track->medium->release->artists[1].mbid, UUID::fromString("5ed3d6b3-2aed-4a03-828c-3c4d4f7406e1"));
EXPECT_EQ(track->medium->release->artists[1].mbid, core::UUID::fromString("5ed3d6b3-2aed-4a03-828c-3c4d4f7406e1"));
ASSERT_TRUE(track->medium->release->mbid.has_value());
EXPECT_EQ(track->medium->release->mbid.value(), UUID::fromString("3fa39992-b786-4585-a70e-85d5cc15ef69"));
EXPECT_EQ(track->medium->release->groupMBID.value(), UUID::fromString("5b1a5a44-8420-4426-9b86-d25dc8d04838"));
EXPECT_EQ(track->medium->release->mbid.value(), core::UUID::fromString("3fa39992-b786-4585-a70e-85d5cc15ef69"));
EXPECT_EQ(track->medium->release->groupMBID.value(), core::UUID::fromString("5b1a5a44-8420-4426-9b86-d25dc8d04838"));
EXPECT_EQ(track->medium->release->mediumCount, 3);
EXPECT_EQ(track->medium->release->name, "MyAlbum");
EXPECT_EQ(track->medium->release->sortName, "MyAlbumSortName");
+1 -1
View File
@@ -23,7 +23,7 @@
#include "Parser.hpp"
namespace MetaData
namespace lms::metadata
{
class TestTagReader : public ITagReader
{
+118 -121
View File
@@ -22,137 +22,134 @@
#include "Utils.hpp"
TEST(MetaData, parseDate)
namespace lms::metadata::utils::tests
{
using namespace MetaData::Utils;
struct TestCase
TEST(MetaData, parseDate)
{
std::string str;
Wt::WDate result;
} testCases[]
{
{ "1995-05-09", Wt::WDate {1995, 5, 9} },
{ "1995-01-01", Wt::WDate {1995, 1, 1} },
{ "1900-01-01", Wt::WDate {1900, 1, 1} },
{ "1899-01-01", Wt::WDate {1899, 1, 1} },
{ "1899-12-31", Wt::WDate {1899, 12, 31} },
{ "1899-11-30", Wt::WDate {1899, 11, 30} },
{ "1500-11-30", Wt::WDate {1500, 11, 30} },
{ "1000-11-30", Wt::WDate {1000, 11, 30} },
{ "1899-11-31", Wt::WDate {} }, // invalid day
{ "1899-11-00", Wt::WDate {} }, // invalid day
{ "1899-13-01", Wt::WDate {} }, // invalid month
{ "1899-00-01", Wt::WDate {} }, // invalid month
{ "1899-11", Wt::WDate {} }, // missing day
{ "1899", Wt::WDate {} }, // missing month and days
{ "1600", Wt::WDate {} }, // missing month and days
{ "1995/05/09", Wt::WDate {1995, 5, 9} },
{ "1995/01/01", Wt::WDate {1995, 1, 1} },
{ "1900/01/01", Wt::WDate {1900, 1, 1} },
{ "1899/01/01", Wt::WDate {1899, 1, 1} },
{ "1899/12/31", Wt::WDate {1899, 12, 31} },
{ "1899/11/30", Wt::WDate {1899, 11, 30} },
{ "1500/11/30", Wt::WDate {1500, 11, 30} },
{ "1000/11/30", Wt::WDate {1000, 11, 30} },
{ "1899/11/31", Wt::WDate {} }, // invalid day
{ "1899/11/00", Wt::WDate {} }, // invalid day
{ "1899/13/01", Wt::WDate {} }, // invalid month
{ "1899/00/01", Wt::WDate {} }, // invalid month
{ "1899/11", Wt::WDate {} }, // missing day
{ "1899", Wt::WDate {} }, // missing month and days
{ "1600", Wt::WDate {} }, // missing month and days
{ "1995/05-09", Wt::WDate {} }, // invalid mixup separators
{ "1995-05/09", Wt::WDate {} }, // invalid mixup separators
};
struct TestCase
{
std::string str;
Wt::WDate result;
} testCases[]
{
{ "1995-05-09", Wt::WDate {1995, 5, 9} },
{ "1995-01-01", Wt::WDate {1995, 1, 1} },
{ "1900-01-01", Wt::WDate {1900, 1, 1} },
{ "1899-01-01", Wt::WDate {1899, 1, 1} },
{ "1899-12-31", Wt::WDate {1899, 12, 31} },
{ "1899-11-30", Wt::WDate {1899, 11, 30} },
{ "1500-11-30", Wt::WDate {1500, 11, 30} },
{ "1000-11-30", Wt::WDate {1000, 11, 30} },
{ "1899-11-31", Wt::WDate {} }, // invalid day
{ "1899-11-00", Wt::WDate {} }, // invalid day
{ "1899-13-01", Wt::WDate {} }, // invalid month
{ "1899-00-01", Wt::WDate {} }, // invalid month
{ "1899-11", Wt::WDate {} }, // missing day
{ "1899", Wt::WDate {} }, // missing month and days
{ "1600", Wt::WDate {} }, // missing month and days
{ "1995/05/09", Wt::WDate {1995, 5, 9} },
{ "1995/01/01", Wt::WDate {1995, 1, 1} },
{ "1900/01/01", Wt::WDate {1900, 1, 1} },
{ "1899/01/01", Wt::WDate {1899, 1, 1} },
{ "1899/12/31", Wt::WDate {1899, 12, 31} },
{ "1899/11/30", Wt::WDate {1899, 11, 30} },
{ "1500/11/30", Wt::WDate {1500, 11, 30} },
{ "1000/11/30", Wt::WDate {1000, 11, 30} },
{ "1899/11/31", Wt::WDate {} }, // invalid day
{ "1899/11/00", Wt::WDate {} }, // invalid day
{ "1899/13/01", Wt::WDate {} }, // invalid month
{ "1899/00/01", Wt::WDate {} }, // invalid month
{ "1899/11", Wt::WDate {} }, // missing day
{ "1899", Wt::WDate {} }, // missing month and days
{ "1600", Wt::WDate {} }, // missing month and days
{ "1995/05-09", Wt::WDate {} }, // invalid mixup separators
{ "1995-05/09", Wt::WDate {} }, // invalid mixup separators
};
for (const TestCase& testCase : testCases)
{
const Wt::WDate parsed{ parseDate(testCase.str) };
for (const TestCase& testCase : testCases)
{
const Wt::WDate parsed{ parseDate(testCase.str) };
EXPECT_EQ(parsed.year(), testCase.result.year()) << " str was '" << testCase.str << "'";
EXPECT_EQ(parsed.month(), testCase.result.month()) << " str was '" << testCase.str << "'";
EXPECT_EQ(parsed.day(), testCase.result.day()) << " str was '" << testCase.str << "'";
EXPECT_EQ(parsed.year(), testCase.result.year()) << " str was '" << testCase.str << "'";
EXPECT_EQ(parsed.month(), testCase.result.month()) << " str was '" << testCase.str << "'";
EXPECT_EQ(parsed.day(), testCase.result.day()) << " str was '" << testCase.str << "'";
}
}
}
TEST(MetaData, parseYear)
{
using namespace MetaData::Utils;
TEST(MetaData, parseYear)
{
struct TestCase
{
std::string str;
std::optional<int> result;
} testCases[]
{
{ "1995-05-09", 1995 },
{ "1995", 1995 },
{ "-0", 0 },
{ "0", 0 },
{ "00", 0 },
{ "05", 5 },
{ "050", 50 },
{ "00005", 0 },
{ "-50", -50 },
{ "-", std::nullopt },
{ "", std::nullopt },
{ "a", std::nullopt },
{ "1a", 1 },
{ "12a", 12 },
{ "123a", 123 },
{ "1234a", 1234 },
{ "19951123", 1995 },
{ "199511", 1995 },
};
struct TestCase
{
std::string str;
std::optional<int> result;
} testCases[]
{
{ "1995-05-09", 1995 },
{ "1995", 1995 },
{ "-0", 0 },
{ "0", 0 },
{ "00", 0 },
{ "05", 5 },
{ "050", 50 },
{ "00005", 0 },
{ "-50", -50 },
{ "-", std::nullopt },
{ "", std::nullopt },
{ "a", std::nullopt },
{ "1a", 1 },
{ "12a", 12 },
{ "123a", 123 },
{ "1234a", 1234 },
{ "19951123", 1995 },
{ "199511", 1995 },
};
for (const TestCase& testCase : testCases)
{
const std::optional<int> parsed{ parseYear(testCase.str) };
EXPECT_EQ(parsed, testCase.result) << " str was '" << testCase.str << "'";
for (const TestCase& testCase : testCases)
{
const std::optional<int> parsed{ parseYear(testCase.str) };
EXPECT_EQ(parsed, testCase.result) << " str was '" << testCase.str << "'";
}
}
}
TEST(MetaData, extractPerformerAndRole)
{
using namespace MetaData::Utils;
struct TestCase
TEST(MetaData, extractPerformerAndRole)
{
std::string str;
std::string expectedArtistName;
std::string expectedRole;
} testCases[]
{
{ "", "", "" },
{ "(myrole)", "", "myrole" },
{ "(my role)", "", "my role" },
{ " ( my role ) ", "", "my role" },
{ " (()) ", "", "()" },
{ ")", ")", "" },
{ "(", "(", "" },
{ "artist name (my role)", "artist name", "my role" },
{ "artist name ()", "artist name", "" },
{ "artist name ( )", "artist name", "" },
{ "artist (subname) name", "artist (subname) name", "" },
{ " artist name ( my role )", "artist name", "my role" },
{ "artist name (artist subname) (my role)", "artist name (artist subname)", "my role" },
{ "artist name", "artist name", "" },
{ " artist name ", "artist name", "" },
{ "artist name (", "artist name (", "" },
{ "artist name )", "artist name )", "" },
{ "artist name (()", "artist name (", "" },
{ "artist name (())", "artist name", "()" },
{ "artist name ( () )", "artist name", "()" },
{ "artist name (drums (drum set))", "artist name", "drums (drum set)" },
{ "artist name ( drums (drum set) )", "artist name", "drums (drum set)" },
};
struct TestCase
{
std::string str;
std::string expectedArtistName;
std::string expectedRole;
} testCases[]
{
{ "", "", "" },
{ "(myrole)", "", "myrole" },
{ "(my role)", "", "my role" },
{ " ( my role ) ", "", "my role" },
{ " (()) ", "", "()" },
{ ")", ")", "" },
{ "(", "(", "" },
{ "artist name (my role)", "artist name", "my role" },
{ "artist name ()", "artist name", "" },
{ "artist name ( )", "artist name", "" },
{ "artist (subname) name", "artist (subname) name", "" },
{ " artist name ( my role )", "artist name", "my role" },
{ "artist name (artist subname) (my role)", "artist name (artist subname)", "my role" },
{ "artist name", "artist name", "" },
{ " artist name ", "artist name", "" },
{ "artist name (", "artist name (", "" },
{ "artist name )", "artist name )", "" },
{ "artist name (()", "artist name (", "" },
{ "artist name (())", "artist name", "()" },
{ "artist name ( () )", "artist name", "()" },
{ "artist name (drums (drum set))", "artist name", "drums (drum set)" },
{ "artist name ( drums (drum set) )", "artist name", "drums (drum set)" },
};
for (const TestCase& testCase : testCases)
{
PerformerArtist performer{ extractPerformerAndRole(testCase.str) };
for (const TestCase& testCase : testCases)
{
PerformerArtist performer{ extractPerformerAndRole(testCase.str) };
EXPECT_EQ(performer.artist.name, testCase.expectedArtistName) << " str was '" << testCase.str << "'";
EXPECT_EQ(performer.role, testCase.expectedRole) << " str was '" << testCase.str << "'";
EXPECT_EQ(performer.artist.name, testCase.expectedArtistName) << " str was '" << testCase.str << "'";
EXPECT_EQ(performer.role, testCase.expectedRole) << " str was '" << testCase.str << "'";
}
}
}
}