aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-01-20 21:31:40 +0100
committerMax Kellermann <max@duempel.org>2014-01-21 00:28:34 +0100
commitdd20a3ce7e5d6bb3efd41a2c9ab5ba27e8e15248 (patch)
tree7512a952fd46640fcbe60cbe00cb6bc249daf009 /test
parentc727c86245ddbf1052023c3dba82b2020836e4ff (diff)
downloadmpd-dd20a3ce7e5d6bb3efd41a2c9ab5ba27e8e15248.tar.gz
mpd-dd20a3ce7e5d6bb3efd41a2c9ab5ba27e8e15248.tar.xz
mpd-dd20a3ce7e5d6bb3efd41a2c9ab5ba27e8e15248.zip
test: add unit test for playlist_check_translate_song()
Diffstat (limited to 'test')
-rw-r--r--test/test_translate_song.cxx290
1 files changed, 290 insertions, 0 deletions
diff --git a/test/test_translate_song.cxx b/test/test_translate_song.cxx
new file mode 100644
index 000000000..34af2c1de
--- /dev/null
+++ b/test/test_translate_song.cxx
@@ -0,0 +1,290 @@
+/*
+ * Unit tests for playlist_check_translate_song().
+ */
+
+#include "config.h"
+#include "PlaylistSong.hxx"
+#include "DetachedSong.hxx"
+#include "tag/TagBuilder.hxx"
+#include "tag/Tag.hxx"
+#include "util/Domain.hxx"
+#include "fs/AllocatedPath.hxx"
+#include "ls.hxx"
+#include "Log.hxx"
+#include "DatabaseSong.hxx"
+#include "Mapper.hxx"
+
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <string.h>
+#include <stdio.h>
+
+void
+Log(const Domain &domain, gcc_unused LogLevel level, const char *msg)
+{
+ fprintf(stderr, "[%s] %s\n", domain.GetName(), msg);
+}
+
+bool
+uri_supported_scheme(const char *uri)
+{
+ return memcmp(uri, "http://", 7) == 0;
+}
+
+const char *const music_directory = "/music";
+
+const char *
+map_to_relative_path(const char *path_utf8)
+{
+ size_t length = strlen(music_directory);
+ if (memcmp(path_utf8, music_directory, length) == 0 &&
+ path_utf8[length] == '/')
+ path_utf8 += length + 1;
+ return path_utf8;
+}
+
+static void
+BuildTag(gcc_unused TagBuilder &tag)
+{
+}
+
+template<typename... Args>
+static void
+BuildTag(TagBuilder &tag, TagType type, const char *value, Args&&... args)
+{
+ tag.AddItem(type, value);
+ BuildTag(tag, std::forward<Args>(args)...);
+}
+
+template<typename... Args>
+static Tag
+MakeTag(Args&&... args)
+{
+ TagBuilder tag;
+ BuildTag(tag, std::forward<Args>(args)...);
+ return tag.Commit();
+}
+
+static Tag
+MakeTag1a()
+{
+ return MakeTag(TAG_ARTIST, "artist_a1", TAG_TITLE, "title_a1",
+ TAG_ALBUM, "album_a1");
+}
+
+static Tag
+MakeTag1b()
+{
+ return MakeTag(TAG_ARTIST, "artist_b1", TAG_TITLE, "title_b1",
+ TAG_COMMENT, "comment_b1");
+}
+
+static Tag
+MakeTag1c()
+{
+ return MakeTag(TAG_ARTIST, "artist_b1", TAG_TITLE, "title_b1",
+ TAG_COMMENT, "comment_b1", TAG_ALBUM, "album_a1");
+}
+
+static Tag
+MakeTag2a()
+{
+ return MakeTag(TAG_ARTIST, "artist_a2", TAG_TITLE, "title_a2",
+ TAG_ALBUM, "album_a2");
+}
+
+static Tag
+MakeTag2b()
+{
+ return MakeTag(TAG_ARTIST, "artist_b2", TAG_TITLE, "title_b2",
+ TAG_COMMENT, "comment_b2");
+}
+
+static Tag
+MakeTag2c()
+{
+ return MakeTag(TAG_ARTIST, "artist_b2", TAG_TITLE, "title_b2",
+ TAG_COMMENT, "comment_b2", TAG_ALBUM, "album_a2");
+}
+
+static const char *uri1 = "/foo/bar.ogg";
+static const char *uri2 = "foo/bar.ogg";
+
+DetachedSong *
+DatabaseDetachSong(const char *uri, gcc_unused Error &error)
+{
+ if (strcmp(uri, uri2) == 0)
+ return new DetachedSong(uri, MakeTag2a());
+
+ return nullptr;
+}
+
+bool
+DetachedSong::Update()
+{
+ if (strcmp(GetURI(), uri1) == 0) {
+ SetTag(MakeTag1a());
+ return true;
+ }
+
+ return false;
+}
+
+static std::string
+ToString(const Tag &tag)
+{
+ char buffer[64];
+ sprintf(buffer, "%d", tag.time);
+
+ std::string result = buffer;
+
+ for (unsigned i = 0, n = tag.num_items; i != n; ++i) {
+ const TagItem &item = *tag.items[i];
+ result.push_back('|');
+ result.append(tag_item_names[item.type]);
+ result.push_back('=');
+ result.append(item.value);
+ }
+
+ return result;
+}
+
+static std::string
+ToString(const DetachedSong &song)
+{
+ std::string result = song.GetURI();
+ result.push_back('|');
+
+ char buffer[64];
+
+ if (song.GetLastModified() > 0) {
+ sprintf(buffer, "%lu", (unsigned long)song.GetLastModified());
+ result.append(buffer);
+ }
+
+ result.push_back('|');
+
+ if (song.GetStartMS() > 0) {
+ sprintf(buffer, "%u", song.GetStartMS());
+ result.append(buffer);
+ }
+
+ result.push_back('-');
+
+ if (song.GetEndMS() > 0) {
+ sprintf(buffer, "%u", song.GetEndMS());
+ result.append(buffer);
+ }
+
+ result.push_back('|');
+
+ result.append(ToString(song.GetTag()));
+
+ return result;
+}
+
+static std::string
+ToString(const DetachedSong *song)
+{
+ if (song == nullptr)
+ return "nullptr";
+
+ return ToString(*song);
+}
+
+class TranslateSongTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(TranslateSongTest);
+ CPPUNIT_TEST(TestAbsoluteURI);
+ CPPUNIT_TEST(TestInsecure);
+ CPPUNIT_TEST(TestSecure);
+ CPPUNIT_TEST(TestInDatabase);
+ CPPUNIT_TEST(TestRelative);
+ CPPUNIT_TEST_SUITE_END();
+
+ void TestAbsoluteURI() {
+ auto song1 = new DetachedSong("http://example.com/foo.ogg");
+ auto song2 = playlist_check_translate_song(song1, "/ignored", false);
+ CPPUNIT_ASSERT_EQUAL(song1, song2);
+ }
+
+ void TestInsecure() {
+ /* illegal because secure=false */
+ auto song1 = new DetachedSong(uri1);
+ auto song2 = playlist_check_translate_song(song1, nullptr, false);
+ CPPUNIT_ASSERT_EQUAL((DetachedSong *)nullptr, song2);
+ }
+
+ void TestSecure() {
+ auto song1 = new DetachedSong(uri1, MakeTag1b());
+ auto s1 = ToString(song1);
+ auto se = ToString(DetachedSong(uri1, MakeTag1c()));
+ auto song2 = playlist_check_translate_song(song1, "/ignored", true);
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song2));
+ delete song2;
+ }
+
+ void TestInDatabase() {
+ auto song1 = new DetachedSong("doesntexist");
+ auto song2 = playlist_check_translate_song(song1, nullptr, false);
+ CPPUNIT_ASSERT_EQUAL((DetachedSong *)nullptr, song2);
+
+ song1 = new DetachedSong(uri2, MakeTag2b());
+ auto s1 = ToString(song1);
+ auto se = ToString(DetachedSong(uri2, MakeTag2c()));
+ song2 = playlist_check_translate_song(song1, nullptr, false);
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song2));
+ delete song2;
+
+ song1 = new DetachedSong("/music/foo/bar.ogg", MakeTag2b());
+ s1 = ToString(song1);
+ se = ToString(DetachedSong(uri2, MakeTag2c()));
+ song2 = playlist_check_translate_song(song1, nullptr, false);
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song2));
+ delete song2;
+ }
+
+ void TestRelative() {
+ /* map to music_directory */
+ auto song1 = new DetachedSong("bar.ogg", MakeTag2b());
+ auto s1 = ToString(song1);
+ auto se = ToString(DetachedSong(uri2, MakeTag2c()));
+ auto song2 = playlist_check_translate_song(song1, "/music/foo", false);
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song2));
+ delete song2;
+
+ /* illegal because secure=false */
+ song1 = new DetachedSong("bar.ogg", MakeTag2b());
+ song2 = playlist_check_translate_song(song1, "/foo", false);
+ CPPUNIT_ASSERT_EQUAL((DetachedSong *)nullptr, song2);
+
+ /* legal because secure=true */
+ song1 = new DetachedSong("bar.ogg", MakeTag1b());
+ s1 = ToString(song2);
+ se = ToString(DetachedSong(uri1, MakeTag1c()));
+ song2 = playlist_check_translate_song(song1, "/foo", true);
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song2));
+ delete song2;
+
+ /* relative to http:// */
+ song1 = new DetachedSong("bar.ogg", MakeTag2a());
+ s1 = ToString(song1);
+ se = ToString(DetachedSong("http://example.com/foo/bar.ogg", MakeTag2a()));
+ song2 = playlist_check_translate_song(song1, "http://example.com/foo", false);
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song2));
+ delete song2;
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TranslateSongTest);
+
+int
+main(gcc_unused int argc, gcc_unused char **argv)
+{
+ CppUnit::TextUi::TestRunner runner;
+ auto &registry = CppUnit::TestFactoryRegistry::getRegistry();
+ runner.addTest(registry.makeTest());
+ return runner.run() ? EXIT_SUCCESS : EXIT_FAILURE;
+}