aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/.gitignore1
-rw-r--r--test/DumpDatabase.cxx75
-rw-r--r--test/FakeDecoderAPI.cxx59
-rw-r--r--test/FakeDecoderAPI.hxx37
-rw-r--r--test/FakeReplayGainConfig.cxx2
-rw-r--r--test/ScopeIOThread.hxx (renamed from test/FakeSong.cxx)27
-rw-r--r--test/ShutdownHandler.cxx2
-rw-r--r--test/ShutdownHandler.hxx4
-rw-r--r--test/TestCircularBuffer.hxx163
-rw-r--r--test/dump_playlist.cxx109
-rw-r--r--test/dump_rva2.cxx26
-rw-r--r--test/dump_text_file.cxx71
-rw-r--r--test/read_conf.cxx38
-rw-r--r--test/read_mixer.cxx116
-rw-r--r--test/read_tags.cxx73
-rw-r--r--test/run_avahi.cxx6
-rw-r--r--test/run_convert.cxx58
-rw-r--r--test/run_decoder.cxx222
-rw-r--r--test/run_encoder.cxx50
-rw-r--r--test/run_filter.cxx93
-rw-r--r--test/run_gunzip.cxx76
-rw-r--r--test/run_gzip.cxx79
-rw-r--r--test/run_inotify.cxx19
-rw-r--r--test/run_input.cxx82
-rw-r--r--test/run_neighbor_explorer.cxx85
-rw-r--r--test/run_normalize.cxx9
-rw-r--r--test/run_output.cxx117
-rw-r--r--test/run_resolver.cxx19
-rw-r--r--test/run_storage.cxx133
-rw-r--r--test/software_volume.cxx37
-rw-r--r--test/stdbin.h2
-rw-r--r--test/test_archive.cxx16
-rw-r--r--test/test_byte_reverse.cxx2
-rw-r--r--test/test_icy_parser.cxx4
-rw-r--r--test/test_pcm_all.hxx27
-rw-r--r--test/test_pcm_channels.cxx39
-rw-r--r--test/test_pcm_dither.cxx8
-rw-r--r--test/test_pcm_export.cxx129
-rw-r--r--test/test_pcm_format.cxx70
-rw-r--r--test/test_pcm_main.cxx10
-rw-r--r--test/test_pcm_mix.cxx20
-rw-r--r--test/test_pcm_pack.cxx6
-rw-r--r--test/test_pcm_util.hxx12
-rw-r--r--test/test_pcm_volume.cxx190
-rw-r--r--test/test_queue_priority.cxx43
-rw-r--r--test/test_rewind.cxx154
-rw-r--r--test/test_translate_song.cxx318
-rw-r--r--test/test_util.cxx4
-rw-r--r--test/test_vorbis_encoder.cxx18
-rw-r--r--test/visit_archive.cxx41
50 files changed, 1929 insertions, 1072 deletions
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 000000000..132ce5fcf
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1 @@
+/run_neighbor_explorer
diff --git a/test/DumpDatabase.cxx b/test/DumpDatabase.cxx
index 21a12d294..07f342319 100644
--- a/test/DumpDatabase.cxx
+++ b/test/DumpDatabase.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2012 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,19 +18,24 @@
*/
#include "config.h"
-#include "DatabaseRegistry.hxx"
-#include "DatabasePlugin.hxx"
-#include "DatabaseSelection.hxx"
-#include "Directory.hxx"
-#include "Song.hxx"
-#include "PlaylistVector.hxx"
-#include "ConfigGlobal.hxx"
-#include "ConfigData.hxx"
+#include "db/Registry.hxx"
+#include "db/DatabasePlugin.hxx"
+#include "db/Interface.hxx"
+#include "db/Selection.hxx"
+#include "db/DatabaseListener.hxx"
+#include "db/LightDirectory.hxx"
+#include "db/LightSong.hxx"
+#include "db/PlaylistVector.hxx"
+#include "config/ConfigGlobal.hxx"
+#include "config/ConfigData.hxx"
#include "tag/TagConfig.hxx"
#include "fs/Path.hxx"
+#include "event/Loop.hxx"
#include "util/Error.hxx"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <iostream>
using std::cout;
@@ -39,35 +44,49 @@ using std::endl;
#include <stdlib.h>
-static void
-my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level,
- const gchar *message, gcc_unused gpointer user_data)
+#ifdef HAVE_LIBUPNP
+#include "input/InputStream.hxx"
+size_t
+InputStream::LockRead(void *, size_t, Error &)
{
- if (log_domain != NULL)
- g_printerr("%s: %s\n", log_domain, message);
- else
- g_printerr("%s\n", message);
+ return 0;
}
+#endif
+
+class MyDatabaseListener final : public DatabaseListener {
+public:
+ virtual void OnDatabaseModified() override {
+ cout << "DatabaseModified" << endl;
+ }
+
+ virtual void OnDatabaseSongRemoved(const LightSong &song) override {
+ cout << "SongRemoved " << song.GetURI() << endl;
+ }
+};
static bool
-DumpDirectory(const Directory &directory, Error &)
+DumpDirectory(const LightDirectory &directory, Error &)
{
- cout << "D " << directory.path << endl;
+ cout << "D " << directory.GetPath() << endl;
return true;
}
static bool
-DumpSong(Song &song, Error &)
+DumpSong(const LightSong &song, Error &)
{
- cout << "S " << song.parent->path << "/" << song.uri << endl;
+ cout << "S ";
+ if (song.directory != nullptr)
+ cout << song.directory << "/";
+ cout << song.uri << endl;
return true;
}
static bool
DumpPlaylist(const PlaylistInfo &playlist,
- const Directory &directory, Error &)
+ const LightDirectory &directory, Error &)
{
- cout << "P " << directory.path << "/" << playlist.name.c_str() << endl;
+ cout << "P " << directory.GetPath()
+ << "/" << playlist.name.c_str() << endl;
return true;
}
@@ -90,11 +109,11 @@ main(int argc, char **argv)
/* initialize GLib */
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(nullptr);
#endif
-
- g_log_set_default_handler(my_log_func, nullptr);
+#endif
/* initialize MPD */
@@ -108,14 +127,18 @@ main(int argc, char **argv)
TagLoadConfig();
+ EventLoop event_loop;
+ MyDatabaseListener database_listener;
+
/* do it */
const struct config_param *path = config_get_param(CONF_DB_FILE);
- config_param param("database", path->line);
+ config_param param("database", path != nullptr ? path->line : -1);
if (path != nullptr)
param.AddBlockParam("path", path->value.c_str(), path->line);
- Database *db = plugin->create(param, error);
+ Database *db = plugin->create(event_loop, database_listener,
+ param, error);
if (db == nullptr) {
cerr << error.GetMessage() << endl;
diff --git a/test/FakeDecoderAPI.cxx b/test/FakeDecoderAPI.cxx
index ca09ca982..3c7453a4f 100644
--- a/test/FakeDecoderAPI.cxx
+++ b/test/FakeDecoderAPI.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2012 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,21 +18,30 @@
*/
#include "config.h"
-#include "DecoderAPI.hxx"
-#include "InputStream.hxx"
+#include "FakeDecoderAPI.hxx"
+#include "decoder/DecoderAPI.hxx"
+#include "input/InputStream.hxx"
#include "util/Error.hxx"
#include "Compiler.h"
-#include <glib.h>
-
#include <unistd.h>
void
-decoder_initialized(gcc_unused Decoder &decoder,
- gcc_unused const AudioFormat audio_format,
+decoder_initialized(Decoder &decoder,
+ const AudioFormat audio_format,
gcc_unused bool seekable,
- gcc_unused float total_time)
+ SignedSongTime duration)
{
+ struct audio_format_string af_string;
+
+ assert(!decoder.initialized);
+ assert(audio_format.IsValid());
+
+ fprintf(stderr, "audio_format=%s duration=%f\n",
+ audio_format_to_string(audio_format, &af_string),
+ duration.ToDoubleS());
+
+ decoder.initialized = true;
}
DecoderCommand
@@ -46,10 +55,16 @@ decoder_command_finished(gcc_unused Decoder &decoder)
{
}
-double
-decoder_seek_where(gcc_unused Decoder &decoder)
+SongTime
+decoder_seek_time(gcc_unused Decoder &decoder)
+{
+ return SongTime();
+}
+
+uint64_t
+decoder_seek_where_frame(gcc_unused Decoder &decoder)
{
- return 1.0;
+ return 1;
}
void
@@ -57,6 +72,12 @@ decoder_seek_error(gcc_unused Decoder &decoder)
{
}
+InputStream *
+decoder_open_uri(Decoder &decoder, const char *uri, Error &error)
+{
+ return InputStream::OpenReady(uri, decoder.mutex, decoder.cond, error);
+}
+
size_t
decoder_read(gcc_unused Decoder *decoder,
InputStream &is,
@@ -111,6 +132,12 @@ decoder_data(gcc_unused Decoder &decoder,
const void *data, size_t datalen,
gcc_unused uint16_t kbit_rate)
{
+ static uint16_t prev_kbit_rate;
+ if (kbit_rate != prev_kbit_rate) {
+ prev_kbit_rate = kbit_rate;
+ fprintf(stderr, "%u kbit/s\n", kbit_rate);
+ }
+
gcc_unused ssize_t nbytes = write(1, data, datalen);
return DecoderCommand::NONE;
}
@@ -129,16 +156,18 @@ decoder_replay_gain(gcc_unused Decoder &decoder,
{
const ReplayGainTuple *tuple = &rgi->tuples[REPLAY_GAIN_ALBUM];
if (tuple->IsDefined())
- g_printerr("replay_gain[album]: gain=%f peak=%f\n",
- tuple->gain, tuple->peak);
+ fprintf(stderr, "replay_gain[album]: gain=%f peak=%f\n",
+ tuple->gain, tuple->peak);
tuple = &rgi->tuples[REPLAY_GAIN_TRACK];
if (tuple->IsDefined())
- g_printerr("replay_gain[track]: gain=%f peak=%f\n",
- tuple->gain, tuple->peak);
+ fprintf(stderr, "replay_gain[track]: gain=%f peak=%f\n",
+ tuple->gain, tuple->peak);
}
void
decoder_mixramp(gcc_unused Decoder &decoder, gcc_unused MixRampInfo &&mix_ramp)
{
+ fprintf(stderr, "MixRamp: start='%s' end='%s'\n",
+ mix_ramp.GetStart(), mix_ramp.GetEnd());
}
diff --git a/test/FakeDecoderAPI.hxx b/test/FakeDecoderAPI.hxx
new file mode 100644
index 000000000..6f1933977
--- /dev/null
+++ b/test/FakeDecoderAPI.hxx
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef FAKE_DECODER_API_HXX
+#define FAKE_DECODER_API_HXX
+
+#include "check.h"
+#include "thread/Mutex.hxx"
+#include "thread/Cond.hxx"
+
+struct Decoder {
+ Mutex mutex;
+ Cond cond;
+
+ bool initialized;
+
+ Decoder()
+ :initialized(false) {}
+};
+
+#endif
diff --git a/test/FakeReplayGainConfig.cxx b/test/FakeReplayGainConfig.cxx
index 3305b79a3..0cb282050 100644
--- a/test/FakeReplayGainConfig.cxx
+++ b/test/FakeReplayGainConfig.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/FakeSong.cxx b/test/ScopeIOThread.hxx
index c0859d7b1..06d27a4b8 100644
--- a/test/FakeSong.cxx
+++ b/test/ScopeIOThread.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2012 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,17 +17,20 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include "config.h"
-#include "Song.hxx"
-#include "directory.h"
-#include "Compiler.h"
+#ifndef MPD_SCOPE_IO_THREAD_HXX
+#define MPD_SCOPE_IO_THREAD_HXX
-#include <stdlib.h>
+#include "IOThread.hxx"
-struct directory detached_root;
+struct ScopeIOThread {
+ ScopeIOThread() {
+ io_thread_init();
+ io_thread_start();
+ }
-Song *
-song_dup_detached(gcc_unused const Song *src)
-{
- abort();
-}
+ ~ScopeIOThread() {
+ io_thread_deinit();
+ }
+};
+
+#endif
diff --git a/test/ShutdownHandler.cxx b/test/ShutdownHandler.cxx
index 341a92939..c04834444 100644
--- a/test/ShutdownHandler.cxx
+++ b/test/ShutdownHandler.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/ShutdownHandler.hxx b/test/ShutdownHandler.hxx
index 0a84ed63f..9db88a1b4 100644
--- a/test/ShutdownHandler.hxx
+++ b/test/ShutdownHandler.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@ class EventLoop;
class ShutdownHandler {
public:
- ShutdownHandler(EventLoop &loop);
+ explicit ShutdownHandler(EventLoop &loop);
~ShutdownHandler();
};
diff --git a/test/TestCircularBuffer.hxx b/test/TestCircularBuffer.hxx
new file mode 100644
index 000000000..c808d85dc
--- /dev/null
+++ b/test/TestCircularBuffer.hxx
@@ -0,0 +1,163 @@
+/*
+ * Unit tests for class CircularBuffer.
+ */
+
+#include "config.h"
+#include "util/CircularBuffer.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 <stdlib.h>
+
+class TestCircularBuffer : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(TestCircularBuffer);
+ CPPUNIT_TEST(TestIt);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void TestIt() {
+ static size_t N = 8;
+ int data[N];
+ CircularBuffer<int> buffer(data, N);
+
+ CPPUNIT_ASSERT_EQUAL(size_t(N), buffer.GetCapacity());
+
+ /* '.' = empty; 'O' = occupied; 'X' = blocked */
+
+ /* checks on empty buffer */
+ /* [.......X] */
+ CPPUNIT_ASSERT_EQUAL(true, buffer.IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull());
+ CPPUNIT_ASSERT_EQUAL(size_t(0), buffer.GetSize());
+ CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.GetSpace());
+ CPPUNIT_ASSERT_EQUAL(true, buffer.Read().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(&data[0], buffer.Write().data);
+ CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.Write().size);
+
+ /* append one element */
+ /* [O......X] */
+ buffer.Append(1);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.GetSize());
+ CPPUNIT_ASSERT_EQUAL(size_t(6), buffer.GetSpace());
+ CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.Read().size);
+ CPPUNIT_ASSERT_EQUAL(&data[0], buffer.Read().data);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(&data[1], buffer.Write().data);
+ CPPUNIT_ASSERT_EQUAL(size_t(6), buffer.Write().size);
+
+ /* append 6 elements, buffer is now full */
+ /* [OOOOOOOX] */
+ buffer.Append(6);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(true, buffer.IsFull());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.GetSize());
+ CPPUNIT_ASSERT_EQUAL(size_t(0), buffer.GetSpace());
+ CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.Read().size);
+ CPPUNIT_ASSERT_EQUAL(&data[0], buffer.Read().data);
+ CPPUNIT_ASSERT_EQUAL(true, buffer.Write().IsEmpty());
+
+ /* consume [0]; can append one at [7] */
+ /* [XOOOOOO.] */
+ buffer.Consume(1);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(size_t(6), buffer.GetSize());
+ CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.GetSpace());
+ CPPUNIT_ASSERT_EQUAL(size_t(6), buffer.Read().size);
+ CPPUNIT_ASSERT_EQUAL(&data[1], buffer.Read().data);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(&data[7], buffer.Write().data);
+ CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.Write().size);
+
+ /* append one element; [0] is still empty but cannot
+ be written to because head==1 */
+ /* [XOOOOOOO] */
+ buffer.Append(1);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(true, buffer.IsFull());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.GetSize());
+ CPPUNIT_ASSERT_EQUAL(size_t(0), buffer.GetSpace());
+ CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.Read().size);
+ CPPUNIT_ASSERT_EQUAL(&data[1], buffer.Read().data);
+ CPPUNIT_ASSERT_EQUAL(true, buffer.Write().IsEmpty());
+
+ /* consume [1..3]; can append [0..2] */
+ /* [...XOOOO] */
+ buffer.Consume(3);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.GetSize());
+ CPPUNIT_ASSERT_EQUAL(size_t(3), buffer.GetSpace());
+ CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.Read().size);
+ CPPUNIT_ASSERT_EQUAL(&data[4], buffer.Read().data);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(&data[0], buffer.Write().data);
+ CPPUNIT_ASSERT_EQUAL(size_t(3), buffer.Write().size);
+
+ /* append [0..1] */
+ /* [OO.XOOOO] */
+ buffer.Append(2);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(size_t(6), buffer.GetSize());
+ CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.GetSpace());
+ CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.Read().size);
+ CPPUNIT_ASSERT_EQUAL(&data[4], buffer.Read().data);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(&data[2], buffer.Write().data);
+ CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.Write().size);
+
+ /* append [2] */
+ /* [OOOXOOOO] */
+ buffer.Append(1);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(true, buffer.IsFull());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.GetSize());
+ CPPUNIT_ASSERT_EQUAL(size_t(0), buffer.GetSpace());
+ CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.Read().size);
+ CPPUNIT_ASSERT_EQUAL(&data[4], buffer.Read().data);
+ CPPUNIT_ASSERT_EQUAL(true, buffer.Write().IsEmpty());
+
+ /* consume [4..7] */
+ /* [OOO....X] */
+ buffer.Consume(4);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(size_t(3), buffer.GetSize());
+ CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.GetSpace());
+ CPPUNIT_ASSERT_EQUAL(size_t(3), buffer.Read().size);
+ CPPUNIT_ASSERT_EQUAL(&data[0], buffer.Read().data);
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(&data[3], buffer.Write().data);
+ CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.Write().size);
+
+ /* consume [0..2]; after that, we can only write 5,
+ because the CircularBuffer class doesn't have
+ special code to rewind/reset an empty buffer */
+ /* [..X.....] */
+ buffer.Consume(3);
+ CPPUNIT_ASSERT_EQUAL(true, buffer.IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull());
+ CPPUNIT_ASSERT_EQUAL(size_t(0), buffer.GetSize());
+ CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.GetSpace());
+ CPPUNIT_ASSERT_EQUAL(true, buffer.Read().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty());
+ CPPUNIT_ASSERT_EQUAL(&data[3], buffer.Write().data);
+ CPPUNIT_ASSERT_EQUAL(size_t(5), buffer.Write().size);
+ }
+};
diff --git a/test/dump_playlist.cxx b/test/dump_playlist.cxx
index 4ac02985a..0047ef427 100644
--- a/test/dump_playlist.cxx
+++ b/test/dump_playlist.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,48 +19,46 @@
#include "config.h"
#include "TagSave.hxx"
-#include "Song.hxx"
-#include "SongEnumerator.hxx"
-#include "Directory.hxx"
-#include "InputStream.hxx"
-#include "ConfigGlobal.hxx"
-#include "DecoderList.hxx"
-#include "InputInit.hxx"
-#include "IOThread.hxx"
-#include "PlaylistRegistry.hxx"
-#include "PlaylistPlugin.hxx"
+#include "DetachedSong.hxx"
+#include "playlist/SongEnumerator.hxx"
+#include "input/InputStream.hxx"
+#include "config/ConfigGlobal.hxx"
+#include "decoder/DecoderList.hxx"
+#include "input/Init.hxx"
+#include "ScopeIOThread.hxx"
+#include "playlist/PlaylistRegistry.hxx"
+#include "playlist/PlaylistPlugin.hxx"
#include "fs/Path.hxx"
+#include "fs/io/BufferedOutputStream.hxx"
+#include "fs/io/StdioOutputStream.hxx"
#include "util/Error.hxx"
#include "thread/Cond.hxx"
#include "Log.hxx"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <unistd.h>
#include <stdlib.h>
-Directory::Directory() {}
-Directory::~Directory() {}
-
static void
-my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level,
- const gchar *message, gcc_unused gpointer user_data)
+tag_save(FILE *file, const Tag &tag)
{
- if (log_domain != NULL)
- g_printerr("%s: %s\n", log_domain, message);
- else
- g_printerr("%s\n", message);
+ StdioOutputStream sos(file);
+ BufferedOutputStream bos(sos);
+ tag_save(bos, tag);
+ bos.Flush();
}
int main(int argc, char **argv)
{
const char *uri;
InputStream *is = NULL;
- Song *song;
if (argc != 3) {
- g_printerr("Usage: dump_playlist CONFIG URI\n");
- return 1;
+ fprintf(stderr, "Usage: dump_playlist CONFIG URI\n");
+ return EXIT_FAILURE;
}
const Path config_path = Path::FromFS(argv[1]);
@@ -68,11 +66,11 @@ int main(int argc, char **argv)
/* initialize GLib */
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(NULL);
#endif
-
- g_log_set_default_handler(my_log_func, NULL);
+#endif
/* initialize MPD */
@@ -80,16 +78,15 @@ int main(int argc, char **argv)
Error error;
if (!ReadConfigFile(config_path, error)) {
- g_printerr("%s\n", error.GetMessage());
- return 1;
+ LogError(error);
+ return EXIT_FAILURE;
}
- io_thread_init();
- io_thread_start();
+ const ScopeIOThread io_thread;
if (!input_stream_global_init(error)) {
LogError(error);
- return 2;
+ return EXIT_FAILURE;
}
playlist_list_global_init();
@@ -104,59 +101,59 @@ int main(int argc, char **argv)
if (playlist == NULL) {
/* open the stream and wait until it becomes ready */
- is = InputStream::Open(uri, mutex, cond, error);
+ is = InputStream::OpenReady(uri, mutex, cond, error);
if (is == NULL) {
if (error.IsDefined())
LogError(error);
else
- g_printerr("InputStream::Open() failed\n");
+ fprintf(stderr,
+ "InputStream::Open() failed\n");
return 2;
}
- is->LockWaitReady();
-
/* open the playlist */
playlist = playlist_list_open_stream(*is, uri);
if (playlist == NULL) {
- is->Close();
- g_printerr("Failed to open playlist\n");
+ delete is;
+ fprintf(stderr, "Failed to open playlist\n");
return 2;
}
}
/* dump the playlist */
+ DetachedSong *song;
while ((song = playlist->NextSong()) != NULL) {
- g_print("%s\n", song->uri);
-
- if (song->end_ms > 0)
- g_print("range: %u:%02u..%u:%02u\n",
- song->start_ms / 60000,
- (song->start_ms / 1000) % 60,
- song->end_ms / 60000,
- (song->end_ms / 1000) % 60);
- else if (song->start_ms > 0)
- g_print("range: %u:%02u..\n",
- song->start_ms / 60000,
- (song->start_ms / 1000) % 60);
-
- if (song->tag != NULL)
- tag_save(stdout, *song->tag);
-
- song->Free();
+ printf("%s\n", song->GetURI());
+
+ const unsigned start_ms = song->GetStartTime().ToMS();
+ const unsigned end_ms = song->GetEndTime().ToMS();
+
+ if (end_ms > 0)
+ printf("range: %u:%02u..%u:%02u\n",
+ start_ms / 60000,
+ (start_ms / 1000) % 60,
+ end_ms / 60000,
+ (end_ms / 1000) % 60);
+ else if (start_ms > 0)
+ printf("range: %u:%02u..\n",
+ start_ms / 60000,
+ (start_ms / 1000) % 60);
+
+ tag_save(stdout, song->GetTag());
+
+ delete song;
}
/* deinitialize everything */
delete playlist;
- if (is != NULL)
- is->Close();
+ delete is;
decoder_plugin_deinit_all();
playlist_list_global_finish();
input_stream_global_finish();
- io_thread_deinit();
config_global_finish();
return 0;
diff --git a/test/dump_rva2.cxx b/test/dump_rva2.cxx
index e1ba5336a..fd46ee36c 100644
--- a/test/dump_rva2.cxx
+++ b/test/dump_rva2.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,19 +21,19 @@
#include "tag/TagId3.hxx"
#include "tag/TagRva2.hxx"
#include "ReplayGainInfo.hxx"
-#include "ConfigGlobal.hxx"
+#include "config/ConfigGlobal.hxx"
#include "util/Error.hxx"
#include "fs/Path.hxx"
+#include "Log.hxx"
#include <id3tag.h>
-#include <glib.h>
-
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include <stdlib.h>
+#include <stdio.h>
const char *
config_get_string(gcc_unused enum ConfigOption option,
@@ -50,8 +50,8 @@ int main(int argc, char **argv)
#endif
if (argc != 2) {
- g_printerr("Usage: read_rva2 FILE\n");
- return 1;
+ fprintf(stderr, "Usage: read_rva2 FILE\n");
+ return EXIT_FAILURE;
}
const char *path = argv[1];
@@ -60,9 +60,9 @@ int main(int argc, char **argv)
struct id3_tag *tag = tag_id3_load(Path::FromFS(path), error);
if (tag == NULL) {
if (error.IsDefined())
- g_printerr("%s\n", error.GetMessage());
+ LogError(error);
else
- g_printerr("No ID3 tag found\n");
+ fprintf(stderr, "No ID3 tag found\n");
return EXIT_FAILURE;
}
@@ -74,19 +74,19 @@ int main(int argc, char **argv)
id3_tag_delete(tag);
if (!success) {
- g_printerr("No RVA2 tag found\n");
+ fprintf(stderr, "No RVA2 tag found\n");
return EXIT_FAILURE;
}
const ReplayGainTuple *tuple = &replay_gain.tuples[REPLAY_GAIN_ALBUM];
if (tuple->IsDefined())
- g_printerr("replay_gain[album]: gain=%f peak=%f\n",
- tuple->gain, tuple->peak);
+ fprintf(stderr, "replay_gain[album]: gain=%f peak=%f\n",
+ tuple->gain, tuple->peak);
tuple = &replay_gain.tuples[REPLAY_GAIN_TRACK];
if (tuple->IsDefined())
- g_printerr("replay_gain[track]: gain=%f peak=%f\n",
- tuple->gain, tuple->peak);
+ fprintf(stderr, "replay_gain[track]: gain=%f peak=%f\n",
+ tuple->gain, tuple->peak);
return EXIT_SUCCESS;
}
diff --git a/test/dump_text_file.cxx b/test/dump_text_file.cxx
index bb84f5cce..5bfd316a5 100644
--- a/test/dump_text_file.cxx
+++ b/test/dump_text_file.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,64 +18,39 @@
*/
#include "config.h"
-#include "IOThread.hxx"
-#include "InputInit.hxx"
-#include "InputStream.hxx"
-#include "ConfigGlobal.hxx"
+#include "ScopeIOThread.hxx"
+#include "input/Init.hxx"
+#include "input/InputStream.hxx"
+#include "input/TextInputStream.hxx"
+#include "config/ConfigGlobal.hxx"
#include "stdbin.h"
-#include "TextInputStream.hxx"
#include "util/Error.hxx"
#include "thread/Cond.hxx"
#include "Log.hxx"
#ifdef ENABLE_ARCHIVE
-#include "ArchiveList.hxx"
+#include "archive/ArchiveList.hxx"
#endif
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
static void
-my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level,
- const gchar *message, gcc_unused gpointer user_data)
-{
- if (log_domain != NULL)
- g_printerr("%s: %s\n", log_domain, message);
- else
- g_printerr("%s\n", message);
-}
-
-static void
dump_text_file(TextInputStream &is)
{
- std::string line;
- while (is.ReadLine(line))
- printf("'%s'\n", line.c_str());
+ const char *line;
+ while ((line = is.ReadLine()) != nullptr)
+ printf("'%s'\n", line);
}
static int
dump_input_stream(InputStream &is)
{
- Error error;
-
- is.Lock();
-
- /* wait until the stream becomes ready */
-
- is.WaitReady();
-
- if (!is.Check(error)) {
- LogError(error);
- is.Unlock();
- return EXIT_FAILURE;
- }
-
- /* read data and tags from the stream */
-
- is.Unlock();
{
TextInputStream tis(is);
dump_text_file(tis);
@@ -83,6 +58,7 @@ dump_input_stream(InputStream &is)
is.Lock();
+ Error error;
if (!is.Check(error)) {
LogError(error);
is.Unlock();
@@ -99,24 +75,23 @@ int main(int argc, char **argv)
int ret;
if (argc != 2) {
- g_printerr("Usage: run_input URI\n");
- return 1;
+ fprintf(stderr, "Usage: run_input URI\n");
+ return EXIT_FAILURE;
}
/* initialize GLib */
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(NULL);
#endif
-
- g_log_set_default_handler(my_log_func, NULL);
+#endif
/* initialize MPD */
config_global_init();
- io_thread_init();
- io_thread_start();
+ const ScopeIOThread io_thread;
#ifdef ENABLE_ARCHIVE
archive_plugin_init_all();
@@ -133,16 +108,16 @@ int main(int argc, char **argv)
Mutex mutex;
Cond cond;
- InputStream *is = InputStream::Open(argv[1], mutex, cond, error);
+ InputStream *is = InputStream::OpenReady(argv[1], mutex, cond, error);
if (is != NULL) {
ret = dump_input_stream(*is);
- is->Close();
+ delete is;
} else {
if (error.IsDefined())
LogError(error);
else
- g_printerr("input_stream::Open() failed\n");
- ret = 2;
+ fprintf(stderr, "input_stream::Open() failed\n");
+ ret = EXIT_FAILURE;
}
/* deinitialize everything */
@@ -153,8 +128,6 @@ int main(int argc, char **argv)
archive_plugin_deinit_all();
#endif
- io_thread_deinit();
-
config_global_finish();
return ret;
diff --git a/test/read_conf.cxx b/test/read_conf.cxx
index d5eacec67..42afdfb4b 100644
--- a/test/read_conf.cxx
+++ b/test/read_conf.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,43 +18,31 @@
*/
#include "config.h"
-#include "ConfigGlobal.hxx"
+#include "config/ConfigGlobal.hxx"
#include "fs/Path.hxx"
#include "util/Error.hxx"
-
-#include <glib.h>
+#include "Log.hxx"
#include <assert.h>
-
-static void
-my_log_func(gcc_unused const gchar *log_domain,
- GLogLevelFlags log_level,
- const gchar *message, gcc_unused gpointer user_data)
-{
- if (log_level > G_LOG_LEVEL_WARNING)
- return;
-
- g_printerr("%s\n", message);
-}
+#include <stdio.h>
+#include <stdlib.h>
int main(int argc, char **argv)
{
if (argc != 3) {
- g_printerr("Usage: read_conf FILE SETTING\n");
- return 1;
+ fprintf(stderr, "Usage: read_conf FILE SETTING\n");
+ return EXIT_FAILURE;
}
const Path config_path = Path::FromFS(argv[1]);
const char *name = argv[2];
- g_log_set_default_handler(my_log_func, NULL);
-
config_global_init();
Error error;
if (!ReadConfigFile(config_path, error)) {
- g_printerr("%s:", error.GetMessage());
- return 1;
+ LogError(error);
+ return EXIT_FAILURE;
}
ConfigOption option = ParseConfigOptionName(name);
@@ -63,11 +51,11 @@ int main(int argc, char **argv)
: nullptr;
int ret;
if (value != NULL) {
- g_print("%s\n", value);
- ret = 0;
+ printf("%s\n", value);
+ ret = EXIT_SUCCESS;
} else {
- g_printerr("No such setting: %s\n", name);
- ret = 2;
+ fprintf(stderr, "No such setting: %s\n", name);
+ ret = EXIT_FAILURE;
}
config_global_finish();
diff --git a/test/read_mixer.cxx b/test/read_mixer.cxx
index 8426443ae..de77a00c4 100644
--- a/test/read_mixer.cxx
+++ b/test/read_mixer.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,82 +18,24 @@
*/
#include "config.h"
-#include "MixerControl.hxx"
-#include "MixerList.hxx"
-#include "FilterRegistry.hxx"
-#include "pcm/PcmVolume.hxx"
-#include "GlobalEvents.hxx"
+#include "mixer/MixerControl.hxx"
+#include "mixer/MixerList.hxx"
+#include "filter/FilterRegistry.hxx"
+#include "pcm/Volume.hxx"
#include "Main.hxx"
#include "event/Loop.hxx"
-#include "ConfigData.hxx"
+#include "config/ConfigData.hxx"
#include "util/Error.hxx"
+#include "Log.hxx"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <assert.h>
#include <string.h>
#include <unistd.h>
-EventLoop *main_loop;
-
-#ifdef HAVE_PULSE
-#include "output/PulseOutputPlugin.hxx"
-
-void
-pulse_output_lock(gcc_unused PulseOutput *po)
-{
-}
-
-void
-pulse_output_unlock(gcc_unused PulseOutput *po)
-{
-}
-
-void
-pulse_output_set_mixer(gcc_unused PulseOutput *po,
- gcc_unused PulseMixer *pm)
-{
-}
-
-void
-pulse_output_clear_mixer(gcc_unused PulseOutput *po,
- gcc_unused PulseMixer *pm)
-{
-}
-
-bool
-pulse_output_set_volume(gcc_unused PulseOutput *po,
- gcc_unused const struct pa_cvolume *volume,
- gcc_unused Error &error)
-{
- return false;
-}
-
-#endif
-
-#ifdef HAVE_ROAR
-#include "output/RoarOutputPlugin.hxx"
-
-int
-roar_output_get_volume(gcc_unused RoarOutput *roar)
-{
- return -1;
-}
-
-bool
-roar_output_set_volume(gcc_unused RoarOutput *roar,
- gcc_unused unsigned volume)
-{
- return true;
-}
-
-#endif
-
-void
-GlobalEvents::Emit(gcc_unused Event event)
-{
-}
-
const struct filter_plugin *
filter_plugin_by_name(gcc_unused const char *name)
{
@@ -101,61 +43,53 @@ filter_plugin_by_name(gcc_unused const char *name)
return NULL;
}
-bool
-pcm_volume(gcc_unused void *buffer, gcc_unused size_t length,
- gcc_unused SampleFormat format,
- gcc_unused int volume)
-{
- assert(false);
- return false;
-}
-
int main(int argc, gcc_unused char **argv)
{
int volume;
if (argc != 2) {
- g_printerr("Usage: read_mixer PLUGIN\n");
- return 1;
+ fprintf(stderr, "Usage: read_mixer PLUGIN\n");
+ return EXIT_FAILURE;
}
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(NULL);
#endif
+#endif
- main_loop = new EventLoop(EventLoop::Default());
+ EventLoop event_loop;
Error error;
- Mixer *mixer = mixer_new(&alsa_mixer_plugin, nullptr,
+ Mixer *mixer = mixer_new(event_loop, alsa_mixer_plugin,
+ *(AudioOutput *)nullptr,
+ *(MixerListener *)nullptr,
config_param(), error);
if (mixer == NULL) {
- g_printerr("mixer_new() failed: %s\n", error.GetMessage());
- return 2;
+ LogError(error, "mixer_new() failed");
+ return EXIT_FAILURE;
}
if (!mixer_open(mixer, error)) {
mixer_free(mixer);
- g_printerr("failed to open the mixer: %s\n", error.GetMessage());
- return 2;
+ LogError(error, "failed to open the mixer");
+ return EXIT_FAILURE;
}
volume = mixer_get_volume(mixer, error);
mixer_close(mixer);
mixer_free(mixer);
- delete main_loop;
-
assert(volume >= -1 && volume <= 100);
if (volume < 0) {
if (error.IsDefined()) {
- g_printerr("failed to read volume: %s\n",
- error.GetMessage());
+ LogError(error, "failed to read volume");
} else
- g_printerr("failed to read volume\n");
- return 2;
+ fprintf(stderr, "failed to read volume\n");
+ return EXIT_FAILURE;
}
- g_print("%d\n", volume);
+ printf("%d\n", volume);
return 0;
}
diff --git a/test/read_tags.cxx b/test/read_tags.cxx
index 52b2561b8..91ac9c674 100644
--- a/test/read_tags.cxx
+++ b/test/read_tags.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,11 +18,11 @@
*/
#include "config.h"
-#include "IOThread.hxx"
-#include "DecoderList.hxx"
-#include "DecoderPlugin.hxx"
-#include "InputInit.hxx"
-#include "InputStream.hxx"
+#include "ScopeIOThread.hxx"
+#include "decoder/DecoderList.hxx"
+#include "decoder/DecoderPlugin.hxx"
+#include "input/Init.hxx"
+#include "input/InputStream.hxx"
#include "AudioFormat.hxx"
#include "tag/TagHandler.hxx"
#include "tag/TagId3.hxx"
@@ -32,11 +32,14 @@
#include "thread/Cond.hxx"
#include "Log.hxx"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
+#include <stdio.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
@@ -45,22 +48,22 @@
static bool empty = true;
static void
-print_duration(unsigned seconds, gcc_unused void *ctx)
+print_duration(SongTime duration, gcc_unused void *ctx)
{
- g_print("duration=%d\n", seconds);
+ printf("duration=%f\n", duration.ToDoubleS());
}
static void
print_tag(TagType type, const char *value, gcc_unused void *ctx)
{
- g_print("[%s]=%s\n", tag_item_names[type], value);
+ printf("[%s]=%s\n", tag_item_names[type], value);
empty = false;
}
static void
print_pair(const char *name, const char *value, gcc_unused void *ctx)
{
- g_print("\"%s\"=%s\n", name, value);
+ printf("\"%s\"=%s\n", name, value);
}
static const struct tag_handler print_handler = {
@@ -71,7 +74,7 @@ static const struct tag_handler print_handler = {
int main(int argc, char **argv)
{
- const char *decoder_name, *path;
+ const char *decoder_name;
const struct DecoderPlugin *plugin;
#ifdef HAVE_LOCALE_H
@@ -80,19 +83,20 @@ int main(int argc, char **argv)
#endif
if (argc != 3) {
- g_printerr("Usage: read_tags DECODER FILE\n");
- return 1;
+ fprintf(stderr, "Usage: read_tags DECODER FILE\n");
+ return EXIT_FAILURE;
}
decoder_name = argv[1];
- path = argv[2];
+ const Path path = Path::FromFS(argv[2]);
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(NULL);
#endif
+#endif
- io_thread_init();
- io_thread_start();
+ const ScopeIOThread io_thread;
Error error;
if (!input_stream_global_init(error)) {
@@ -104,8 +108,8 @@ int main(int argc, char **argv)
plugin = decoder_plugin_from_name(decoder_name);
if (plugin == NULL) {
- g_printerr("No such decoder: %s\n", decoder_name);
- return 1;
+ fprintf(stderr, "No such decoder: %s\n", decoder_name);
+ return EXIT_FAILURE;
}
bool success = plugin->ScanFile(path, print_handler, nullptr);
@@ -113,45 +117,30 @@ int main(int argc, char **argv)
Mutex mutex;
Cond cond;
- InputStream *is = InputStream::Open(path, mutex, cond,
- error);
+ InputStream *is = InputStream::OpenReady(path.c_str(),
+ mutex, cond,
+ error);
if (is == NULL) {
- g_printerr("Failed to open %s: %s\n",
- path, error.GetMessage());
- return 1;
- }
-
- mutex.lock();
-
- is->WaitReady();
-
- if (!is->Check(error)) {
- mutex.unlock();
-
- g_printerr("Failed to read %s: %s\n",
- path, error.GetMessage());
+ FormatError(error, "Failed to open %s", path.c_str());
return EXIT_FAILURE;
}
- mutex.unlock();
-
success = plugin->ScanStream(*is, print_handler, nullptr);
- is->Close();
+ delete is;
}
decoder_plugin_deinit_all();
input_stream_global_finish();
- io_thread_deinit();
if (!success) {
- g_printerr("Failed to read tags\n");
- return 1;
+ fprintf(stderr, "Failed to read tags\n");
+ return EXIT_FAILURE;
}
if (empty) {
- tag_ape_scan2(Path::FromFS(path), &print_handler, NULL);
+ tag_ape_scan2(path, &print_handler, NULL);
if (empty)
- tag_id3_scan(Path::FromFS(path), &print_handler, NULL);
+ tag_id3_scan(path, &print_handler, NULL);
}
return 0;
diff --git a/test/run_avahi.cxx b/test/run_avahi.cxx
index b392edb6d..b3b20365c 100644
--- a/test/run_avahi.cxx
+++ b/test/run_avahi.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
#include "config.h"
#include "event/Loop.hxx"
#include "ShutdownHandler.hxx"
-#include "ZeroconfAvahi.hxx"
+#include "zeroconf/ZeroconfAvahi.hxx"
#include <stdlib.h>
@@ -29,7 +29,7 @@ unsigned listen_port = 1234;
int
main(gcc_unused int argc, gcc_unused char **argv)
{
- EventLoop event_loop((EventLoop::Default()));
+ EventLoop event_loop;
const ShutdownHandler shutdown_handler(event_loop);
AvahiInit(event_loop, "test");
diff --git a/test/run_convert.cxx b/test/run_convert.cxx
index 0e873a3b3..8b9b15cf0 100644
--- a/test/run_convert.cxx
+++ b/test/run_convert.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,28 +27,18 @@
#include "AudioParser.hxx"
#include "AudioFormat.hxx"
#include "pcm/PcmConvert.hxx"
-#include "ConfigGlobal.hxx"
-#include "util/FifoBuffer.hxx"
+#include "config/ConfigGlobal.hxx"
+#include "util/ConstBuffer.hxx"
+#include "util/StaticFifoBuffer.hxx"
#include "util/Error.hxx"
+#include "Log.hxx"
#include "stdbin.h"
-#include <glib.h>
-
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
-static void
-my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level,
- const gchar *message, gcc_unused gpointer user_data)
-{
- if (log_domain != NULL)
- g_printerr("%s: %s\n", log_domain, message);
- else
- g_printerr("%s\n", message);
-}
-
const char *
config_get_string(gcc_unused enum ConfigOption option,
const char *default_value)
@@ -59,29 +49,25 @@ config_get_string(gcc_unused enum ConfigOption option,
int main(int argc, char **argv)
{
AudioFormat in_audio_format, out_audio_format;
- const void *output;
if (argc != 3) {
- g_printerr("Usage: run_convert IN_FORMAT OUT_FORMAT <IN >OUT\n");
+ fprintf(stderr,
+ "Usage: run_convert IN_FORMAT OUT_FORMAT <IN >OUT\n");
return 1;
}
- g_log_set_default_handler(my_log_func, NULL);
-
Error error;
if (!audio_format_parse(in_audio_format, argv[1],
false, error)) {
- g_printerr("Failed to parse audio format: %s\n",
- error.GetMessage());
- return 1;
+ LogError(error, "Failed to parse audio format");
+ return EXIT_FAILURE;
}
AudioFormat out_audio_format_mask;
if (!audio_format_parse(out_audio_format_mask, argv[2],
true, error)) {
- g_printerr("Failed to parse audio format: %s\n",
- error.GetMessage());
- return 1;
+ LogError(error, "Failed to parse audio format");
+ return EXIT_FAILURE;
}
out_audio_format = in_audio_format;
@@ -90,8 +76,12 @@ int main(int argc, char **argv)
const size_t in_frame_size = in_audio_format.GetFrameSize();
PcmConvert state;
+ if (!state.Open(in_audio_format, out_audio_format_mask, error)) {
+ LogError(error, "Failed to open PcmConvert");
+ return EXIT_FAILURE;
+ }
- FifoBuffer<uint8_t, 4096> buffer;
+ StaticFifoBuffer<uint8_t, 4096> buffer;
while (true) {
{
@@ -114,16 +104,18 @@ int main(int argc, char **argv)
buffer.Consume(src.size);
- size_t length;
- output = state.Convert(in_audio_format, src.data, src.size,
- out_audio_format, &length, error);
- if (output == NULL) {
- g_printerr("Failed to convert: %s\n", error.GetMessage());
- return 2;
+ auto output = state.Convert({src.data, src.size}, error);
+ if (output.IsNull()) {
+ state.Close();
+ LogError(error, "Failed to convert");
+ return EXIT_FAILURE;
}
- gcc_unused ssize_t ignored = write(1, output, length);
+ gcc_unused ssize_t ignored = write(1, output.data,
+ output.size);
}
+ state.Close();
+
return EXIT_SUCCESS;
}
diff --git a/test/run_decoder.cxx b/test/run_decoder.cxx
index 3fbfc5521..0e9af6a1a 100644
--- a/test/run_decoder.cxx
+++ b/test/run_decoder.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,239 +18,89 @@
*/
#include "config.h"
-#include "IOThread.hxx"
-#include "DecoderList.hxx"
-#include "DecoderAPI.hxx"
-#include "InputInit.hxx"
-#include "InputStream.hxx"
+#include "ScopeIOThread.hxx"
+#include "decoder/DecoderList.hxx"
+#include "decoder/DecoderPlugin.hxx"
+#include "FakeDecoderAPI.hxx"
+#include "input/Init.hxx"
+#include "input/InputStream.hxx"
+#include "fs/Path.hxx"
#include "AudioFormat.hxx"
#include "util/Error.hxx"
-#include "thread/Cond.hxx"
#include "Log.hxx"
#include "stdbin.h"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
-
-static void
-my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level,
- const gchar *message, gcc_unused gpointer user_data)
-{
- if (log_domain != NULL)
- g_printerr("%s: %s\n", log_domain, message);
- else
- g_printerr("%s\n", message);
-}
-
-struct Decoder {
- const char *uri;
-
- const struct DecoderPlugin *plugin;
-
- bool initialized;
-};
-
-void
-decoder_initialized(Decoder &decoder,
- const AudioFormat audio_format,
- gcc_unused bool seekable,
- float duration)
-{
- struct audio_format_string af_string;
-
- assert(!decoder.initialized);
- assert(audio_format.IsValid());
-
- g_printerr("audio_format=%s duration=%f\n",
- audio_format_to_string(audio_format, &af_string),
- duration);
-
- decoder.initialized = true;
-}
-
-DecoderCommand
-decoder_get_command(gcc_unused Decoder &decoder)
-{
- return DecoderCommand::NONE;
-}
-
-void
-decoder_command_finished(gcc_unused Decoder &decoder)
-{
-}
-
-double
-decoder_seek_where(gcc_unused Decoder &decoder)
-{
- return 1.0;
-}
-
-void
-decoder_seek_error(gcc_unused Decoder &decoder)
-{
-}
-
-size_t
-decoder_read(gcc_unused Decoder *decoder,
- InputStream &is,
- void *buffer, size_t length)
-{
- return is.LockRead(buffer, length, IgnoreError());
-}
-
-bool
-decoder_read_full(Decoder *decoder, InputStream &is,
- void *_buffer, size_t size)
-{
- uint8_t *buffer = (uint8_t *)_buffer;
-
- while (size > 0) {
- size_t nbytes = decoder_read(decoder, is, buffer, size);
- if (nbytes == 0)
- return false;
-
- buffer += nbytes;
- size -= nbytes;
- }
-
- return true;
-}
-
-bool
-decoder_skip(Decoder *decoder, InputStream &is, size_t size)
-{
- while (size > 0) {
- char buffer[1024];
- size_t nbytes = decoder_read(decoder, is, buffer,
- std::min(sizeof(buffer), size));
- if (nbytes == 0)
- return false;
-
- size -= nbytes;
- }
-
- return true;
-}
-
-void
-decoder_timestamp(gcc_unused Decoder &decoder,
- gcc_unused double t)
-{
-}
-
-DecoderCommand
-decoder_data(gcc_unused Decoder &decoder,
- gcc_unused InputStream *is,
- const void *data, size_t datalen,
- gcc_unused uint16_t kbit_rate)
-{
- gcc_unused ssize_t nbytes = write(1, data, datalen);
- return DecoderCommand::NONE;
-}
-
-DecoderCommand
-decoder_tag(gcc_unused Decoder &decoder,
- gcc_unused InputStream *is,
- gcc_unused Tag &&tag)
-{
- return DecoderCommand::NONE;
-}
-
-void
-decoder_replay_gain(gcc_unused Decoder &decoder,
- const ReplayGainInfo *rgi)
-{
- const ReplayGainTuple *tuple = &rgi->tuples[REPLAY_GAIN_ALBUM];
- if (tuple->IsDefined())
- g_printerr("replay_gain[album]: gain=%f peak=%f\n",
- tuple->gain, tuple->peak);
-
- tuple = &rgi->tuples[REPLAY_GAIN_TRACK];
- if (tuple->IsDefined())
- g_printerr("replay_gain[track]: gain=%f peak=%f\n",
- tuple->gain, tuple->peak);
-}
-
-void
-decoder_mixramp(gcc_unused Decoder &decoder, MixRampInfo &&mix_ramp)
-{
- fprintf(stderr, "MixRamp: start='%s' end='%s'\n",
- mix_ramp.GetStart(), mix_ramp.GetEnd());
-}
+#include <stdio.h>
int main(int argc, char **argv)
{
- const char *decoder_name;
-
if (argc != 3) {
- g_printerr("Usage: run_decoder DECODER URI >OUT\n");
- return 1;
+ fprintf(stderr, "Usage: run_decoder DECODER URI >OUT\n");
+ return EXIT_FAILURE;
}
Decoder decoder;
- decoder_name = argv[1];
- decoder.uri = argv[2];
+ const char *const decoder_name = argv[1];
+ const char *const uri = argv[2];
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(NULL);
#endif
+#endif
- g_log_set_default_handler(my_log_func, NULL);
-
- io_thread_init();
- io_thread_start();
+ const ScopeIOThread io_thread;
Error error;
if (!input_stream_global_init(error)) {
LogError(error);
- return 2;
+ return EXIT_FAILURE;
}
decoder_plugin_init_all();
- decoder.plugin = decoder_plugin_from_name(decoder_name);
- if (decoder.plugin == NULL) {
- g_printerr("No such decoder: %s\n", decoder_name);
- return 1;
+ const DecoderPlugin *plugin = decoder_plugin_from_name(decoder_name);
+ if (plugin == nullptr) {
+ fprintf(stderr, "No such decoder: %s\n", decoder_name);
+ return EXIT_FAILURE;
}
- decoder.initialized = false;
-
- if (decoder.plugin->file_decode != NULL) {
- decoder.plugin->FileDecode(decoder, decoder.uri);
- } else if (decoder.plugin->stream_decode != NULL) {
- Mutex mutex;
- Cond cond;
-
+ if (plugin->file_decode != nullptr) {
+ plugin->FileDecode(decoder, Path::FromFS(uri));
+ } else if (plugin->stream_decode != nullptr) {
InputStream *is =
- InputStream::Open(decoder.uri, mutex, cond, error);
+ InputStream::OpenReady(uri, decoder.mutex,
+ decoder.cond, error);
if (is == NULL) {
if (error.IsDefined())
LogError(error);
else
- g_printerr("InputStream::Open() failed\n");
+ fprintf(stderr, "InputStream::Open() failed\n");
- return 1;
+ return EXIT_FAILURE;
}
- decoder.plugin->StreamDecode(decoder, *is);
+ plugin->StreamDecode(decoder, *is);
- is->Close();
+ delete is;
} else {
- g_printerr("Decoder plugin is not usable\n");
- return 1;
+ fprintf(stderr, "Decoder plugin is not usable\n");
+ return EXIT_FAILURE;
}
decoder_plugin_deinit_all();
input_stream_global_finish();
- io_thread_deinit();
if (!decoder.initialized) {
- g_printerr("Decoding failed\n");
- return 1;
+ fprintf(stderr, "Decoding failed\n");
+ return EXIT_FAILURE;
}
return 0;
diff --git a/test/run_encoder.cxx b/test/run_encoder.cxx
index 838ee708e..f16d8cb0a 100644
--- a/test/run_encoder.cxx
+++ b/test/run_encoder.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,16 +18,17 @@
*/
#include "config.h"
-#include "EncoderList.hxx"
-#include "EncoderPlugin.hxx"
+#include "encoder/EncoderList.hxx"
+#include "encoder/EncoderPlugin.hxx"
#include "AudioFormat.hxx"
#include "AudioParser.hxx"
-#include "ConfigData.hxx"
+#include "config/ConfigData.hxx"
#include "util/Error.hxx"
+#include "Log.hxx"
#include "stdbin.h"
-#include <glib.h>
-
+#include <stdio.h>
+#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
@@ -50,8 +51,9 @@ int main(int argc, char **argv)
/* parse command line */
if (argc > 3) {
- g_printerr("Usage: run_encoder [ENCODER] [FORMAT] <IN >OUT\n");
- return 1;
+ fprintf(stderr,
+ "Usage: run_encoder [ENCODER] [FORMAT] <IN >OUT\n");
+ return EXIT_FAILURE;
}
if (argc > 1)
@@ -63,8 +65,8 @@ int main(int argc, char **argv)
const auto plugin = encoder_plugin_get(encoder_name);
if (plugin == NULL) {
- g_printerr("No such encoder: %s\n", encoder_name);
- return 1;
+ fprintf(stderr, "No such encoder: %s\n", encoder_name);
+ return EXIT_FAILURE;
}
config_param param;
@@ -73,9 +75,8 @@ int main(int argc, char **argv)
Error error;
const auto encoder = encoder_init(*plugin, param, error);
if (encoder == NULL) {
- g_printerr("Failed to initialize encoder: %s\n",
- error.GetMessage());
- return 1;
+ LogError(error, "Failed to initialize encoder");
+ return EXIT_FAILURE;
}
/* open the encoder */
@@ -83,16 +84,14 @@ int main(int argc, char **argv)
AudioFormat audio_format(44100, SampleFormat::S16, 2);
if (argc > 2) {
if (!audio_format_parse(audio_format, argv[2], false, error)) {
- g_printerr("Failed to parse audio format: %s\n",
- error.GetMessage());
- return 1;
+ LogError(error, "Failed to parse audio format");
+ return EXIT_FAILURE;
}
}
if (!encoder_open(encoder, audio_format, error)) {
- g_printerr("Failed to open encoder: %s\n",
- error.GetMessage());
- return 1;
+ LogError(error, "Failed to open encoder");
+ return EXIT_FAILURE;
}
encoder_to_stdout(*encoder);
@@ -102,19 +101,20 @@ int main(int argc, char **argv)
ssize_t nbytes;
while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) {
if (!encoder_write(encoder, buffer, nbytes, error)) {
- g_printerr("encoder_write() failed: %s\n",
- error.GetMessage());
- return 1;
+ LogError(error, "encoder_write() failed");
+ return EXIT_FAILURE;
}
encoder_to_stdout(*encoder);
}
if (!encoder_end(encoder, error)) {
- g_printerr("encoder_flush() failed: %s\n",
- error.GetMessage());
- return 1;
+ LogError(error, "encoder_flush() failed");
+ return EXIT_FAILURE;
}
encoder_to_stdout(*encoder);
+
+ encoder_close(encoder);
+ encoder_finish(encoder);
}
diff --git a/test/run_filter.cxx b/test/run_filter.cxx
index 085fc256b..ab99c9a1e 100644
--- a/test/run_filter.cxx
+++ b/test/run_filter.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,23 +18,29 @@
*/
#include "config.h"
-#include "ConfigData.hxx"
-#include "ConfigGlobal.hxx"
+#include "config/ConfigData.hxx"
+#include "config/ConfigGlobal.hxx"
#include "fs/Path.hxx"
#include "AudioParser.hxx"
#include "AudioFormat.hxx"
-#include "FilterPlugin.hxx"
-#include "FilterInternal.hxx"
-#include "pcm/PcmVolume.hxx"
-#include "MixerControl.hxx"
+#include "filter/FilterPlugin.hxx"
+#include "filter/FilterInternal.hxx"
+#include "pcm/Volume.hxx"
+#include "mixer/MixerControl.hxx"
#include "stdbin.h"
#include "util/Error.hxx"
+#include "util/ConstBuffer.hxx"
#include "system/FatalError.hxx"
+#include "Log.hxx"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <assert.h>
#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
#include <errno.h>
#include <unistd.h>
@@ -45,45 +51,20 @@ mixer_set_volume(gcc_unused Mixer *mixer,
return true;
}
-static void
-my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level,
- const gchar *message, gcc_unused gpointer user_data)
-{
- if (log_domain != NULL)
- g_printerr("%s: %s\n", log_domain, message);
- else
- g_printerr("%s\n", message);
-}
-
-static const struct config_param *
-find_named_config_block(ConfigOption option, const char *name)
-{
- const struct config_param *param = NULL;
-
- while ((param = config_get_next_param(option, param)) != NULL) {
- const char *current_name = param->GetBlockValue("name");
- if (current_name != NULL && strcmp(current_name, name) == 0)
- return param;
- }
-
- return NULL;
-}
-
static Filter *
load_filter(const char *name)
{
- const struct config_param *param;
-
- param = find_named_config_block(CONF_AUDIO_FILTER, name);
+ const config_param *param =
+ config_find_block(CONF_AUDIO_FILTER, "name", name);
if (param == NULL) {
- g_printerr("No such configured filter: %s\n", name);
+ fprintf(stderr, "No such configured filter: %s\n", name);
return nullptr;
}
Error error;
Filter *filter = filter_configured_new(*param, error);
if (filter == NULL) {
- g_printerr("Failed to load filter: %s\n", error.GetMessage());
+ LogError(error, "Failed to load filter");
return NULL;
}
@@ -97,8 +78,8 @@ int main(int argc, char **argv)
char buffer[4096];
if (argc < 3 || argc > 4) {
- g_printerr("Usage: run_filter CONFIG NAME [FORMAT] <IN\n");
- return 1;
+ fprintf(stderr, "Usage: run_filter CONFIG NAME [FORMAT] <IN\n");
+ return EXIT_FAILURE;
}
const Path config_path = Path::FromFS(argv[1]);
@@ -107,11 +88,11 @@ int main(int argc, char **argv)
/* initialize GLib */
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(NULL);
#endif
-
- g_log_set_default_handler(my_log_func, NULL);
+#endif
/* read configuration file (mpd.conf) */
@@ -124,9 +105,8 @@ int main(int argc, char **argv)
if (argc > 3) {
Error error;
if (!audio_format_parse(audio_format, argv[3], false, error)) {
- g_printerr("Failed to parse audio format: %s\n",
- error.GetMessage());
- return 1;
+ LogError(error, "Failed to parse audio format");
+ return EXIT_FAILURE;
}
}
@@ -134,44 +114,43 @@ int main(int argc, char **argv)
Filter *filter = load_filter(argv[2]);
if (filter == NULL)
- return 1;
+ return EXIT_FAILURE;
/* open the filter */
Error error;
const AudioFormat out_audio_format = filter->Open(audio_format, error);
if (!out_audio_format.IsDefined()) {
- g_printerr("Failed to open filter: %s\n", error.GetMessage());
+ LogError(error, "Failed to open filter");
delete filter;
- return 1;
+ return EXIT_FAILURE;
}
- g_printerr("audio_format=%s\n",
- audio_format_to_string(out_audio_format, &af_string));
+ fprintf(stderr, "audio_format=%s\n",
+ audio_format_to_string(out_audio_format, &af_string));
/* play */
while (true) {
ssize_t nbytes;
- size_t length;
- const void *dest;
nbytes = read(0, buffer, sizeof(buffer));
if (nbytes <= 0)
break;
- dest = filter->FilterPCM(buffer, (size_t)nbytes,
- &length, error);
- if (dest == NULL) {
- g_printerr("Filter failed: %s\n", error.GetMessage());
+ auto dest = filter->FilterPCM({(const void *)buffer, (size_t)nbytes},
+ error);
+ if (dest.IsNull()) {
+ LogError(error, "filter/Filter failed");
filter->Close();
delete filter;
- return 1;
+ return EXIT_FAILURE;
}
- nbytes = write(1, dest, length);
+ nbytes = write(1, dest.data, dest.size);
if (nbytes < 0) {
- g_printerr("Failed to write: %s\n", g_strerror(errno));
+ fprintf(stderr, "Failed to write: %s\n",
+ strerror(errno));
filter->Close();
delete filter;
return 1;
diff --git a/test/run_gunzip.cxx b/test/run_gunzip.cxx
new file mode 100644
index 000000000..51bdb532e
--- /dev/null
+++ b/test/run_gunzip.cxx
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "fs/io/GunzipReader.hxx"
+#include "fs/io/FileReader.hxx"
+#include "fs/io/StdioOutputStream.hxx"
+#include "util/Error.hxx"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static bool
+Copy(OutputStream &dest, Reader &src, Error &error)
+{
+ while (true) {
+ char buffer[4096];
+ size_t nbytes = src.Read(buffer, sizeof(buffer), error);
+ if (nbytes == 0)
+ return !error.IsDefined();
+
+ if (!dest.Write(buffer, nbytes, error))
+ return false;
+ }
+}
+
+static bool
+CopyGunzip(OutputStream &dest, Reader &_src, Error &error)
+{
+ GunzipReader src(_src, error);
+ return src.IsDefined() && Copy(dest, src, error);
+}
+
+static bool
+CopyGunzip(FILE *_dest, Path src_path, Error &error)
+{
+ StdioOutputStream dest(_dest);
+ FileReader src(src_path, error);
+ return src.IsDefined() && CopyGunzip(dest, src, error);
+}
+
+int
+main(int argc, gcc_unused char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: run_gunzip PATH\n");
+ return EXIT_FAILURE;
+ }
+
+ Path path = Path::FromFS(argv[1]);
+
+ Error error;
+ if (!CopyGunzip(stdout, path, error)) {
+ fprintf(stderr, "%s\n", error.GetMessage());
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/test/run_gzip.cxx b/test/run_gzip.cxx
new file mode 100644
index 000000000..c52b32ac7
--- /dev/null
+++ b/test/run_gzip.cxx
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "fs/io/GzipOutputStream.hxx"
+#include "fs/io/StdioOutputStream.hxx"
+#include "util/Error.hxx"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static bool
+Copy(OutputStream &dest, int src, Error &error)
+{
+ while (true) {
+ char buffer[4096];
+ ssize_t nbytes = read(src, buffer, sizeof(buffer));
+ if (nbytes <= 0) {
+ if (nbytes < 0) {
+ error.SetErrno();
+ return false;
+ } else
+ return true;
+ }
+
+ if (!dest.Write(buffer, nbytes, error))
+ return false;
+ }
+}
+
+static bool
+CopyGzip(OutputStream &_dest, int src, Error &error)
+{
+ GzipOutputStream dest(_dest, error);
+ return dest.IsDefined() &&
+ Copy(dest, src, error) &&
+ dest.Flush(error);
+}
+
+static bool
+CopyGzip(FILE *_dest, int src, Error &error)
+{
+ StdioOutputStream dest(_dest);
+ return CopyGzip(dest, src, error);
+}
+
+int
+main(int argc, gcc_unused char **argv)
+{
+ if (argc != 1) {
+ fprintf(stderr, "Usage: run_gzip\n");
+ return EXIT_FAILURE;
+ }
+
+ Error error;
+ if (!CopyGzip(stdout, STDIN_FILENO, error)) {
+ fprintf(stderr, "%s\n", error.GetMessage());
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/test/run_inotify.cxx b/test/run_inotify.cxx
index c57e6e9ef..df4046356 100644
--- a/test/run_inotify.cxx
+++ b/test/run_inotify.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,13 +19,11 @@
#include "config.h"
#include "ShutdownHandler.hxx"
-#include "InotifySource.hxx"
+#include "db/update/InotifySource.hxx"
#include "event/Loop.hxx"
#include "util/Error.hxx"
#include "Log.hxx"
-#include <glib.h>
-
#include <sys/inotify.h>
static constexpr unsigned IN_MASK =
@@ -39,7 +37,7 @@ static void
my_inotify_callback(gcc_unused int wd, unsigned mask,
const char *name, gcc_unused void *ctx)
{
- g_print("mask=0x%x name='%s'\n", mask, name);
+ printf("mask=0x%x name='%s'\n", mask, name);
}
int main(int argc, char **argv)
@@ -47,13 +45,13 @@ int main(int argc, char **argv)
const char *path;
if (argc != 2) {
- g_printerr("Usage: run_inotify PATH\n");
- return 1;
+ fprintf(stderr, "Usage: run_inotify PATH\n");
+ return EXIT_FAILURE;
}
path = argv[1];
- EventLoop event_loop((EventLoop::Default()));
+ EventLoop event_loop;
const ShutdownHandler shutdown_handler(event_loop);
Error error;
@@ -62,17 +60,18 @@ int main(int argc, char **argv)
nullptr, error);
if (source == NULL) {
LogError(error);
- return 2;
+ return EXIT_FAILURE;
}
int descriptor = source->Add(path, IN_MASK, error);
if (descriptor < 0) {
delete source;
LogError(error);
- return 2;
+ return EXIT_FAILURE;
}
event_loop.Run();
delete source;
+ return EXIT_SUCCESS;
}
diff --git a/test/run_input.cxx b/test/run_input.cxx
index 3817ed418..6864a5d64 100644
--- a/test/run_input.cxx
+++ b/test/run_input.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,69 +21,59 @@
#include "TagSave.hxx"
#include "stdbin.h"
#include "tag/Tag.hxx"
-#include "ConfigGlobal.hxx"
-#include "InputStream.hxx"
-#include "InputInit.hxx"
-#include "IOThread.hxx"
+#include "config/ConfigGlobal.hxx"
+#include "input/InputStream.hxx"
+#include "input/Init.hxx"
+#include "ScopeIOThread.hxx"
#include "util/Error.hxx"
#include "thread/Cond.hxx"
#include "Log.hxx"
+#include "fs/io/BufferedOutputStream.hxx"
+#include "fs/io/StdioOutputStream.hxx"
#ifdef ENABLE_ARCHIVE
-#include "ArchiveList.hxx"
+#include "archive/ArchiveList.hxx"
#endif
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <unistd.h>
#include <stdlib.h>
static void
-my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level,
- const gchar *message, gcc_unused gpointer user_data)
+tag_save(FILE *file, const Tag &tag)
{
- if (log_domain != NULL)
- g_printerr("%s: %s\n", log_domain, message);
- else
- g_printerr("%s\n", message);
+ StdioOutputStream sos(file);
+ BufferedOutputStream bos(sos);
+ tag_save(bos, tag);
+ bos.Flush();
}
static int
dump_input_stream(InputStream *is)
{
- Error error;
- char buffer[4096];
- size_t num_read;
- ssize_t num_written;
-
is->Lock();
- /* wait until the stream becomes ready */
-
- is->WaitReady();
-
- if (!is->Check(error)) {
- LogError(error);
- is->Unlock();
- return EXIT_FAILURE;
- }
-
/* print meta data */
- if (!is->mime.empty())
- g_printerr("MIME type: %s\n", is->mime.c_str());
+ if (is->HasMimeType())
+ fprintf(stderr, "MIME type: %s\n", is->GetMimeType());
/* read data and tags from the stream */
while (!is->IsEOF()) {
Tag *tag = is->ReadTag();
if (tag != NULL) {
- g_printerr("Received a tag:\n");
+ fprintf(stderr, "Received a tag:\n");
tag_save(stderr, *tag);
delete tag;
}
- num_read = is->Read(buffer, sizeof(buffer), error);
+ Error error;
+ char buffer[4096];
+ size_t num_read = is->Read(buffer, sizeof(buffer), error);
if (num_read == 0) {
if (error.IsDefined())
LogError(error);
@@ -91,11 +81,12 @@ dump_input_stream(InputStream *is)
break;
}
- num_written = write(1, buffer, num_read);
+ ssize_t num_written = write(1, buffer, num_read);
if (num_written <= 0)
break;
}
+ Error error;
if (!is->Check(error)) {
LogError(error);
is->Unlock();
@@ -109,34 +100,30 @@ dump_input_stream(InputStream *is)
int main(int argc, char **argv)
{
- Error error;
- InputStream *is;
- int ret;
-
if (argc != 2) {
- g_printerr("Usage: run_input URI\n");
- return 1;
+ fprintf(stderr, "Usage: run_input URI\n");
+ return EXIT_FAILURE;
}
/* initialize GLib */
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(NULL);
#endif
-
- g_log_set_default_handler(my_log_func, NULL);
+#endif
/* initialize MPD */
config_global_init();
- io_thread_init();
- io_thread_start();
+ const ScopeIOThread io_thread;
#ifdef ENABLE_ARCHIVE
archive_plugin_init_all();
#endif
+ Error error;
if (!input_stream_global_init(error)) {
LogError(error);
return 2;
@@ -147,16 +134,17 @@ int main(int argc, char **argv)
Mutex mutex;
Cond cond;
- is = InputStream::Open(argv[1], mutex, cond, error);
+ InputStream *is = InputStream::OpenReady(argv[1], mutex, cond, error);
+ int ret;
if (is != NULL) {
ret = dump_input_stream(is);
- is->Close();
+ delete is;
} else {
if (error.IsDefined())
LogError(error);
else
- g_printerr("input_stream::Open() failed\n");
- ret = 2;
+ fprintf(stderr, "input_stream::Open() failed\n");
+ ret = EXIT_FAILURE;
}
/* deinitialize everything */
@@ -167,8 +155,6 @@ int main(int argc, char **argv)
archive_plugin_deinit_all();
#endif
- io_thread_deinit();
-
config_global_finish();
return ret;
diff --git a/test/run_neighbor_explorer.cxx b/test/run_neighbor_explorer.cxx
new file mode 100644
index 000000000..c79948d6e
--- /dev/null
+++ b/test/run_neighbor_explorer.cxx
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "config/ConfigGlobal.hxx"
+#include "neighbor/Listener.hxx"
+#include "neighbor/Info.hxx"
+#include "neighbor/Glue.hxx"
+#include "fs/Path.hxx"
+#include "event/Loop.hxx"
+#include "util/Error.hxx"
+#include "Log.hxx"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+class MyNeighborListener final : public NeighborListener {
+ public:
+ /* virtual methods from class NeighborListener */
+ virtual void FoundNeighbor(const NeighborInfo &info) override {
+ printf("found '%s' (%s)\n",
+ info.display_name.c_str(), info.uri.c_str());
+ }
+
+ virtual void LostNeighbor(const NeighborInfo &info) override {
+ printf("lost '%s' (%s)\n",
+ info.display_name.c_str(), info.uri.c_str());
+ }
+};
+
+int
+main(int argc, char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: run_neighbor_explorer CONFIG\n");
+ return EXIT_FAILURE;
+ }
+
+ const Path config_path = Path::FromFS(argv[1]);
+
+ /* read configuration file (mpd.conf) */
+
+ Error error;
+
+ config_global_init();
+ if (!ReadConfigFile(config_path, error)) {
+ LogError(error);
+ return EXIT_FAILURE;
+ }
+
+ /* initialize the core */
+
+ EventLoop loop;
+
+ /* initialize neighbor plugins */
+
+ MyNeighborListener listener;
+ NeighborGlue neighbor;
+ if (!neighbor.Init(loop, listener, error) || !neighbor.Open(error)) {
+ LogError(error);
+ return EXIT_FAILURE;
+ }
+
+ /* run */
+
+ loop.Run();
+ neighbor.Close();
+ return EXIT_SUCCESS;
+}
diff --git a/test/run_normalize.cxx b/test/run_normalize.cxx
index 3193fefd2..9a361b790 100644
--- a/test/run_normalize.cxx
+++ b/test/run_normalize.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -30,9 +30,8 @@
#include "util/Error.hxx"
#include "stdbin.h"
-#include <glib.h>
-
#include <stddef.h>
+#include <stdio.h>
#include <unistd.h>
#include <string.h>
@@ -43,7 +42,7 @@ int main(int argc, char **argv)
ssize_t nbytes;
if (argc > 2) {
- g_printerr("Usage: run_normalize [FORMAT] <IN >OUT\n");
+ fprintf(stderr, "Usage: run_normalize [FORMAT] <IN >OUT\n");
return 1;
}
@@ -51,7 +50,7 @@ int main(int argc, char **argv)
if (argc > 1) {
Error error;
if (!audio_format_parse(audio_format, argv[1], false, error)) {
- g_printerr("Failed to parse audio format: %s\n",
+ fprintf(stderr, "Failed to parse audio format: %s\n",
error.GetMessage());
return 1;
}
diff --git a/test/run_output.cxx b/test/run_output.cxx
index 7982bd7de..345127556 100644
--- a/test/run_output.cxx
+++ b/test/run_output.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,38 +18,33 @@
*/
#include "config.h"
-#include "OutputControl.hxx"
-#include "OutputInternal.hxx"
-#include "OutputPlugin.hxx"
-#include "ConfigData.hxx"
-#include "ConfigGlobal.hxx"
-#include "ConfigOption.hxx"
+#include "output/Internal.hxx"
+#include "output/OutputPlugin.hxx"
+#include "config/ConfigData.hxx"
+#include "config/ConfigGlobal.hxx"
+#include "config/ConfigOption.hxx"
#include "Idle.hxx"
#include "Main.hxx"
#include "event/Loop.hxx"
-#include "GlobalEvents.hxx"
-#include "IOThread.hxx"
+#include "ScopeIOThread.hxx"
#include "fs/Path.hxx"
#include "AudioParser.hxx"
#include "pcm/PcmConvert.hxx"
-#include "FilterRegistry.hxx"
+#include "filter/FilterRegistry.hxx"
#include "PlayerControl.hxx"
#include "stdbin.h"
#include "util/Error.hxx"
+#include "Log.hxx"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
-
-EventLoop *main_loop;
-
-void
-GlobalEvents::Emit(gcc_unused Event event)
-{
-}
+#include <stdio.h>
const struct filter_plugin *
filter_plugin_by_name(gcc_unused const char *name)
@@ -58,68 +53,61 @@ filter_plugin_by_name(gcc_unused const char *name)
return NULL;
}
-static const struct config_param *
-find_named_config_block(ConfigOption option, const char *name)
-{
- const struct config_param *param = NULL;
-
- while ((param = config_get_next_param(option, param)) != NULL) {
- const char *current_name = param->GetBlockValue("name");
- if (current_name != NULL && strcmp(current_name, name) == 0)
- return param;
- }
-
- return NULL;
-}
-
-PlayerControl::PlayerControl(gcc_unused unsigned _buffer_chunks,
- gcc_unused unsigned _buffered_before_play) {}
+PlayerControl::PlayerControl(PlayerListener &_listener,
+ MultipleOutputs &_outputs,
+ unsigned _buffer_chunks,
+ unsigned _buffered_before_play)
+ :listener(_listener), outputs(_outputs),
+ buffer_chunks(_buffer_chunks),
+ buffered_before_play(_buffered_before_play) {}
PlayerControl::~PlayerControl() {}
-static struct audio_output *
-load_audio_output(const char *name)
+static AudioOutput *
+load_audio_output(EventLoop &event_loop, const char *name)
{
- const struct config_param *param;
-
- param = find_named_config_block(CONF_AUDIO_OUTPUT, name);
+ const config_param *param =
+ config_find_block(CONF_AUDIO_OUTPUT, "name", name);
if (param == NULL) {
- g_printerr("No such configured audio output: %s\n", name);
+ fprintf(stderr, "No such configured audio output: %s\n", name);
return nullptr;
}
- static struct PlayerControl dummy_player_control(32, 4);
+ static struct PlayerControl dummy_player_control(*(PlayerListener *)nullptr,
+ *(MultipleOutputs *)nullptr,
+ 32, 4);
Error error;
- struct audio_output *ao =
- audio_output_new(*param, dummy_player_control, error);
+ AudioOutput *ao =
+ audio_output_new(event_loop, *param,
+ *(MixerListener *)nullptr,
+ dummy_player_control,
+ error);
if (ao == nullptr)
- g_printerr("%s\n", error.GetMessage());
+ LogError(error);
return ao;
}
static bool
-run_output(struct audio_output *ao, AudioFormat audio_format)
+run_output(AudioOutput *ao, AudioFormat audio_format)
{
/* open the audio output */
Error error;
if (!ao_plugin_enable(ao, error)) {
- g_printerr("Failed to enable audio output: %s\n",
- error.GetMessage());
+ LogError(error, "Failed to enable audio output");
return false;
}
if (!ao_plugin_open(ao, audio_format, error)) {
ao_plugin_disable(ao);
- g_printerr("Failed to open audio output: %s\n",
- error.GetMessage());
+ LogError(error, "Failed to open audio output");
return false;
}
struct audio_format_string af_string;
- g_printerr("audio_format=%s\n",
- audio_format_to_string(audio_format, &af_string));
+ fprintf(stderr, "audio_format=%s\n",
+ audio_format_to_string(audio_format, &af_string));
size_t frame_size = audio_format.GetFrameSize();
@@ -145,8 +133,7 @@ run_output(struct audio_output *ao, AudioFormat audio_format)
if (consumed == 0) {
ao_plugin_close(ao);
ao_plugin_disable(ao);
- g_printerr("Failed to play: %s\n",
- error.GetMessage());
+ LogError(error, "Failed to play");
return false;
}
@@ -168,34 +155,35 @@ int main(int argc, char **argv)
Error error;
if (argc < 3 || argc > 4) {
- g_printerr("Usage: run_output CONFIG NAME [FORMAT] <IN\n");
- return 1;
+ fprintf(stderr, "Usage: run_output CONFIG NAME [FORMAT] <IN\n");
+ return EXIT_FAILURE;
}
const Path config_path = Path::FromFS(argv[1]);
AudioFormat audio_format(44100, SampleFormat::S16, 2);
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(NULL);
#endif
+#endif
/* read configuration file (mpd.conf) */
config_global_init();
if (!ReadConfigFile(config_path, error)) {
- g_printerr("%s\n", error.GetMessage());
- return 1;
+ LogError(error);
+ return EXIT_FAILURE;
}
- main_loop = new EventLoop(EventLoop::Default());
+ EventLoop event_loop;
- io_thread_init();
- io_thread_start();
+ const ScopeIOThread io_thread;
/* initialize the audio output */
- struct audio_output *ao = load_audio_output(argv[2]);
+ AudioOutput *ao = load_audio_output(event_loop, argv[2]);
if (ao == NULL)
return 1;
@@ -203,9 +191,8 @@ int main(int argc, char **argv)
if (argc > 3) {
if (!audio_format_parse(audio_format, argv[3], false, error)) {
- g_printerr("Failed to parse audio format: %s\n",
- error.GetMessage());
- return 1;
+ LogError(error, "Failed to parse audio format");
+ return EXIT_FAILURE;
}
}
@@ -217,10 +204,6 @@ int main(int argc, char **argv)
audio_output_free(ao);
- io_thread_deinit();
-
- delete main_loop;
-
config_global_finish();
return success ? EXIT_SUCCESS : EXIT_FAILURE;
diff --git a/test/run_resolver.cxx b/test/run_resolver.cxx
index 7da2fd5b2..71cadbeec 100644
--- a/test/run_resolver.cxx
+++ b/test/run_resolver.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,8 +22,6 @@
#include "util/Error.hxx"
#include "Log.hxx"
-#include <glib.h>
-
#ifdef WIN32
#include <ws2tcpip.h>
#include <winsock.h>
@@ -32,12 +30,13 @@
#include <netdb.h>
#endif
+#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
if (argc != 2) {
- g_printerr("Usage: run_resolver HOST\n");
+ fprintf(stderr, "Usage: run_resolver HOST\n");
return EXIT_FAILURE;
}
@@ -51,16 +50,8 @@ int main(int argc, char **argv)
}
for (const struct addrinfo *i = ai; i != NULL; i = i->ai_next) {
- char *p = sockaddr_to_string(i->ai_addr, i->ai_addrlen,
- error);
- if (p == NULL) {
- freeaddrinfo(ai);
- LogError(error);
- return EXIT_FAILURE;
- }
-
- g_print("%s\n", p);
- g_free(p);
+ const auto s = sockaddr_to_string(i->ai_addr, i->ai_addrlen);
+ printf("%s\n", s.c_str());
}
freeaddrinfo(ai);
diff --git a/test/run_storage.cxx b/test/run_storage.cxx
new file mode 100644
index 000000000..9fc6e6e76
--- /dev/null
+++ b/test/run_storage.cxx
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "ScopeIOThread.hxx"
+#include "storage/Registry.hxx"
+#include "storage/StorageInterface.hxx"
+#include "storage/FileInfo.hxx"
+#include "util/Error.hxx"
+
+#ifdef HAVE_GLIB
+#include <glib.h>
+#endif
+
+#include <memory>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+static Storage *
+MakeStorage(const char *uri)
+{
+ Error error;
+ Storage *storage = CreateStorageURI(io_thread_get(), uri, error);
+ if (storage == nullptr) {
+ fprintf(stderr, "%s\n", error.GetMessage());
+ exit(EXIT_FAILURE);
+ }
+
+ return storage;
+}
+
+static int
+Ls(Storage &storage, const char *path)
+{
+ Error error;
+ auto dir = storage.OpenDirectory(path, error);
+ if (dir == nullptr) {
+ fprintf(stderr, "%s\n", error.GetMessage());
+ return EXIT_FAILURE;
+ }
+
+ const char *name;
+ while ((name = dir->Read()) != nullptr) {
+ FileInfo info;
+ if (!dir->GetInfo(false, info, error)) {
+ printf("Error on %s: %s\n", name, error.GetMessage());
+ error.Clear();
+ continue;
+ }
+
+ const char *type = "unk";
+ switch (info.type) {
+ case FileInfo::Type::OTHER:
+ type = "oth";
+ break;
+
+ case FileInfo::Type::REGULAR:
+ type = "reg";
+ break;
+
+ case FileInfo::Type::DIRECTORY:
+ type = "dir";
+ break;
+ }
+
+ char mtime[32];
+ strftime(mtime, sizeof(mtime), "%F", gmtime(&info.mtime));
+
+ printf("%s %10llu %s %s\n",
+ type, (unsigned long long)info.size,
+ mtime, name);
+ }
+
+ delete dir;
+ return EXIT_SUCCESS;
+}
+
+int
+main(int argc, char **argv)
+{
+ if (argc < 3) {
+ fprintf(stderr, "Usage: run_storage COMMAND URI ...\n");
+ return EXIT_FAILURE;
+ }
+
+ /* initialize GLib */
+
+#ifdef HAVE_GLIB
+#if !GLIB_CHECK_VERSION(2,32,0)
+ g_thread_init(NULL);
+#endif
+#endif
+
+ const char *const command = argv[1];
+ const char *const storage_uri = argv[2];
+
+ const ScopeIOThread io_thread;
+
+ if (strcmp(command, "ls") == 0) {
+ if (argc != 4) {
+ fprintf(stderr, "Usage: run_storage ls URI PATH\n");
+ return EXIT_FAILURE;
+ }
+
+ const char *const path = argv[3];
+
+ std::unique_ptr<Storage> storage(MakeStorage(storage_uri));
+
+ return Ls(*storage, path);
+ } else {
+ fprintf(stderr, "Unknown command\n");
+ return EXIT_FAILURE;
+ }
+}
diff --git a/test/software_volume.cxx b/test/software_volume.cxx
index 19a0be88c..1e41f95fd 100644
--- a/test/software_volume.cxx
+++ b/test/software_volume.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,15 +24,17 @@
*/
#include "config.h"
-#include "pcm/PcmVolume.hxx"
+#include "pcm/Volume.hxx"
#include "AudioParser.hxx"
#include "AudioFormat.hxx"
+#include "util/ConstBuffer.hxx"
#include "util/Error.hxx"
#include "stdbin.h"
+#include "Log.hxx"
-#include <glib.h>
-
+#include <stdio.h>
#include <stddef.h>
+#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
@@ -41,28 +43,29 @@ int main(int argc, char **argv)
ssize_t nbytes;
if (argc > 2) {
- g_printerr("Usage: software_volume [FORMAT] <IN >OUT\n");
- return 1;
+ fprintf(stderr, "Usage: software_volume [FORMAT] <IN >OUT\n");
+ return EXIT_FAILURE;
}
Error error;
AudioFormat audio_format(48000, SampleFormat::S16, 2);
if (argc > 1) {
if (!audio_format_parse(audio_format, argv[1], false, error)) {
- g_printerr("Failed to parse audio format: %s\n",
- error.GetMessage());
- return 1;
+ LogError(error, "Failed to parse audio format");
+ return EXIT_FAILURE;
}
}
- while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) {
- if (!pcm_volume(buffer, nbytes,
- audio_format.format,
- PCM_VOLUME_1 / 2)) {
- g_printerr("pcm_volume() has failed\n");
- return 2;
- }
+ PcmVolume pv;
+ if (!pv.Open(audio_format.format, error)) {
+ fprintf(stderr, "%s\n", error.GetMessage());
+ return EXIT_FAILURE;
+ }
- gcc_unused ssize_t ignored = write(1, buffer, nbytes);
+ while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) {
+ auto dest = pv.Apply({buffer, size_t(nbytes)});
+ gcc_unused ssize_t ignored = write(1, dest.data, dest.size);
}
+
+ pv.Close();
}
diff --git a/test/stdbin.h b/test/stdbin.h
index 48cac7338..8b5502e6f 100644
--- a/test/stdbin.h
+++ b/test/stdbin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/test_archive.cxx b/test/test_archive.cxx
index dbb41fe42..1b15e306f 100644
--- a/test/test_archive.cxx
+++ b/test/test_archive.cxx
@@ -1,5 +1,5 @@
#include "config.h"
-#include "ArchiveLookup.hxx"
+#include "archive/ArchiveLookup.hxx"
#include "Compiler.h"
#include <cppunit/TestFixture.h>
@@ -7,8 +7,6 @@
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
-#include <glib.h>
-
#include <string.h>
#include <stdlib.h>
@@ -29,22 +27,22 @@ ArchiveLookupTest::TestArchiveLookup()
char *path = strdup("");
CPPUNIT_ASSERT_EQUAL(false,
archive_lookup(path, &archive, &inpath, &suffix));
- g_free(path);
+ free(path);
path = strdup(".");
CPPUNIT_ASSERT_EQUAL(false,
archive_lookup(path, &archive, &inpath, &suffix));
- g_free(path);
+ free(path);
path = strdup("config.h");
CPPUNIT_ASSERT_EQUAL(false,
archive_lookup(path, &archive, &inpath, &suffix));
- g_free(path);
+ free(path);
path = strdup("src/foo/bar");
CPPUNIT_ASSERT_EQUAL(false,
archive_lookup(path, &archive, &inpath, &suffix));
- g_free(path);
+ free(path);
path = strdup("Makefile/foo/bar");
CPPUNIT_ASSERT_EQUAL(true,
@@ -53,7 +51,7 @@ ArchiveLookupTest::TestArchiveLookup()
CPPUNIT_ASSERT_EQUAL(0, strcmp(archive, "Makefile"));
CPPUNIT_ASSERT_EQUAL(0, strcmp(inpath, "foo/bar"));
CPPUNIT_ASSERT_EQUAL((const char *)nullptr, suffix);
- g_free(path);
+ free(path);
path = strdup("config.h/foo/bar");
CPPUNIT_ASSERT_EQUAL(true,
@@ -62,7 +60,7 @@ ArchiveLookupTest::TestArchiveLookup()
CPPUNIT_ASSERT_EQUAL(0, strcmp(archive, "config.h"));
CPPUNIT_ASSERT_EQUAL(0, strcmp(inpath, "foo/bar"));
CPPUNIT_ASSERT_EQUAL(0, strcmp(suffix, "h"));
- g_free(path);
+ free(path);
}
CPPUNIT_TEST_SUITE_REGISTRATION(ArchiveLookupTest);
diff --git a/test/test_byte_reverse.cxx b/test/test_byte_reverse.cxx
index 58673e4f8..0ab97e4d1 100644
--- a/test/test_byte_reverse.cxx
+++ b/test/test_byte_reverse.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/test_icy_parser.cxx b/test/test_icy_parser.cxx
index 2abf60f9e..a996df134 100644
--- a/test/test_icy_parser.cxx
+++ b/test/test_icy_parser.cxx
@@ -28,7 +28,7 @@ icy_parse_tag(const char *p)
static void
CompareTagTitle(const Tag &tag, const std::string &title)
{
- CPPUNIT_ASSERT_EQUAL(1u, tag.num_items);
+ CPPUNIT_ASSERT_EQUAL(uint16_t(1), tag.num_items);
const TagItem &item = *tag.items[0];
CPPUNIT_ASSERT_EQUAL(TAG_TITLE, item.type);
@@ -47,7 +47,7 @@ static void
TestIcyParserEmpty(const char *input)
{
Tag *tag = icy_parse_tag(input);
- CPPUNIT_ASSERT_EQUAL(0u, tag->num_items);
+ CPPUNIT_ASSERT_EQUAL(uint16_t(0), tag->num_items);
delete tag;
}
diff --git a/test/test_pcm_all.hxx b/test/test_pcm_all.hxx
index 2a0aa8628..7cdd8b63f 100644
--- a/test/test_pcm_all.hxx
+++ b/test/test_pcm_all.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -34,8 +34,6 @@ public:
void TestDither32();
};
-CPPUNIT_TEST_SUITE_REGISTRATION(PcmDitherTest);
-
class PcmPackTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(PcmPackTest);
CPPUNIT_TEST(TestPack24);
@@ -47,8 +45,6 @@ public:
void TestUnpack24();
};
-CPPUNIT_TEST_SUITE_REGISTRATION(PcmPackTest);
-
class PcmChannelsTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(PcmChannelsTest);
CPPUNIT_TEST(TestChannels16);
@@ -60,8 +56,6 @@ public:
void TestChannels32();
};
-CPPUNIT_TEST_SUITE_REGISTRATION(PcmChannelsTest);
-
class PcmVolumeTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(PcmVolumeTest);
CPPUNIT_TEST(TestVolume8);
@@ -79,8 +73,6 @@ public:
void TestVolumeFloat();
};
-CPPUNIT_TEST_SUITE_REGISTRATION(PcmVolumeTest);
-
class PcmFormatTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(PcmFormatTest);
CPPUNIT_TEST(TestFormat8to16);
@@ -96,8 +88,6 @@ public:
void TestFormatFloat();
};
-CPPUNIT_TEST_SUITE_REGISTRATION(PcmFormatTest);
-
class PcmMixTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(PcmMixTest);
CPPUNIT_TEST(TestMix8);
@@ -113,6 +103,19 @@ public:
void TestMix32();
};
-CPPUNIT_TEST_SUITE_REGISTRATION(PcmMixTest);
+class PcmExportTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(PcmExportTest);
+ CPPUNIT_TEST(TestShift8);
+ CPPUNIT_TEST(TestPack24);
+ CPPUNIT_TEST(TestReverseEndian);
+ CPPUNIT_TEST(TestDop);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void TestShift8();
+ void TestPack24();
+ void TestReverseEndian();
+ void TestDop();
+};
#endif
diff --git a/test/test_pcm_channels.cxx b/test/test_pcm_channels.cxx
index 85c872674..748a76351 100644
--- a/test/test_pcm_channels.cxx
+++ b/test/test_pcm_channels.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,33 +22,30 @@
#include "test_pcm_util.hxx"
#include "pcm/PcmChannels.hxx"
#include "pcm/PcmBuffer.hxx"
+#include "util/ConstBuffer.hxx"
void
PcmChannelsTest::TestChannels16()
{
- constexpr unsigned N = 256;
+ constexpr size_t N = 509;
const auto src = TestDataBuffer<int16_t, N * 2>();
PcmBuffer buffer;
/* stereo to mono */
- size_t dest_size;
- const int16_t *dest =
- pcm_convert_channels_16(buffer, 1, 2, src, sizeof(src),
- &dest_size);
- CPPUNIT_ASSERT(dest != NULL);
- CPPUNIT_ASSERT_EQUAL(sizeof(src) / 2, dest_size);
+ auto dest = pcm_convert_channels_16(buffer, 1, 2, { src, N * 2 });
+ CPPUNIT_ASSERT(!dest.IsNull());
+ CPPUNIT_ASSERT_EQUAL(N, dest.size);
for (unsigned i = 0; i < N; ++i)
CPPUNIT_ASSERT_EQUAL(int16_t((src[i * 2] + src[i * 2 + 1]) / 2),
dest[i]);
/* mono to stereo */
- dest = pcm_convert_channels_16(buffer, 2, 1, src, sizeof(src),
- &dest_size);
- CPPUNIT_ASSERT(dest != NULL);
- CPPUNIT_ASSERT_EQUAL(sizeof(src) * 2, dest_size);
+ dest = pcm_convert_channels_16(buffer, 2, 1, { src, N * 2 });
+ CPPUNIT_ASSERT(!dest.IsNull());
+ CPPUNIT_ASSERT_EQUAL(N * 4, dest.size);
for (unsigned i = 0; i < N; ++i) {
CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2]);
CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2 + 1]);
@@ -58,29 +55,25 @@ PcmChannelsTest::TestChannels16()
void
PcmChannelsTest::TestChannels32()
{
- constexpr unsigned N = 256;
+ constexpr size_t N = 509;
const auto src = TestDataBuffer<int32_t, N * 2>();
PcmBuffer buffer;
/* stereo to mono */
- size_t dest_size;
- const int32_t *dest =
- pcm_convert_channels_32(buffer, 1, 2, src, sizeof(src),
- &dest_size);
- CPPUNIT_ASSERT(dest != NULL);
- CPPUNIT_ASSERT_EQUAL(sizeof(src) / 2, dest_size);
+ auto dest = pcm_convert_channels_32(buffer, 1, 2, { src, N * 2 });
+ CPPUNIT_ASSERT(!dest.IsNull());
+ CPPUNIT_ASSERT_EQUAL(N, dest.size);
for (unsigned i = 0; i < N; ++i)
CPPUNIT_ASSERT_EQUAL(int32_t(((int64_t)src[i * 2] + (int64_t)src[i * 2 + 1]) / 2),
dest[i]);
/* mono to stereo */
- dest = pcm_convert_channels_32(buffer, 2, 1, src, sizeof(src),
- &dest_size);
- CPPUNIT_ASSERT(dest != NULL);
- CPPUNIT_ASSERT_EQUAL(sizeof(src) * 2, dest_size);
+ dest = pcm_convert_channels_32(buffer, 2, 1, { src, N * 2 });
+ CPPUNIT_ASSERT(!dest.IsNull());
+ CPPUNIT_ASSERT_EQUAL(N * 4, dest.size);
for (unsigned i = 0; i < N; ++i) {
CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2]);
CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2 + 1]);
diff --git a/test/test_pcm_dither.cxx b/test/test_pcm_dither.cxx
index 710deffcc..09a2b5cf9 100644
--- a/test/test_pcm_dither.cxx
+++ b/test/test_pcm_dither.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,12 +19,12 @@
#include "test_pcm_all.hxx"
#include "test_pcm_util.hxx"
-#include "pcm/PcmDither.hxx"
+#include "pcm/PcmDither.cxx"
void
PcmDitherTest::TestDither24()
{
- constexpr unsigned N = 256;
+ constexpr unsigned N = 509;
const auto src = TestDataBuffer<int32_t, N>(RandomInt24());
int16_t dest[N];
@@ -40,7 +40,7 @@ PcmDitherTest::TestDither24()
void
PcmDitherTest::TestDither32()
{
- constexpr unsigned N = 256;
+ constexpr unsigned N = 509;
const auto src = TestDataBuffer<int32_t, N>();
int16_t dest[N];
diff --git a/test/test_pcm_export.cxx b/test/test_pcm_export.cxx
new file mode 100644
index 000000000..410e64e4d
--- /dev/null
+++ b/test/test_pcm_export.cxx
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "test_pcm_all.hxx"
+#include "pcm/PcmExport.hxx"
+#include "system/ByteOrder.hxx"
+#include "util/ConstBuffer.hxx"
+
+#include <string.h>
+
+void
+PcmExportTest::TestShift8()
+{
+ static constexpr int32_t src[] = { 0x0, 0x1, 0x100, 0x10000, 0xffffff };
+ static constexpr uint32_t expected[] = { 0x0, 0x100, 0x10000, 0x1000000, 0xffffff00 };
+
+ PcmExport e;
+ e.Open(SampleFormat::S24_P32, 2, false, true, false, false);
+
+ auto dest = e.Export({src, sizeof(src)});
+ CPPUNIT_ASSERT_EQUAL(sizeof(expected), dest.size);
+ CPPUNIT_ASSERT(memcmp(dest.data, expected, dest.size) == 0);
+}
+
+void
+PcmExportTest::TestPack24()
+{
+ static constexpr int32_t src[] = { 0x0, 0x1, 0x100, 0x10000, 0xffffff };
+
+ static constexpr uint8_t expected_be[] = {
+ 0, 0, 0x0,
+ 0, 0, 0x1,
+ 0, 0x1, 0x00,
+ 0x1, 0x00, 0x00,
+ 0xff, 0xff, 0xff,
+ };
+
+ static constexpr uint8_t expected_le[] = {
+ 0, 0, 0x0,
+ 0x1, 0, 0,
+ 0x00, 0x1, 0,
+ 0, 0x00, 0x01,
+ 0xff, 0xff, 0xff,
+ };
+
+ static constexpr size_t expected_size = sizeof(expected_be);
+ static const uint8_t *const expected = IsBigEndian()
+ ? expected_be : expected_le;
+
+ PcmExport e;
+ e.Open(SampleFormat::S24_P32, 2, false, false, true, false);
+
+ auto dest = e.Export({src, sizeof(src)});
+ CPPUNIT_ASSERT_EQUAL(expected_size, dest.size);
+ CPPUNIT_ASSERT(memcmp(dest.data, expected, dest.size) == 0);
+}
+
+void
+PcmExportTest::TestReverseEndian()
+{
+ static constexpr uint8_t src[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+ };
+
+ static constexpr uint8_t expected2[] = {
+ 2, 1, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11
+ };
+
+ static constexpr uint8_t expected4[] = {
+ 4, 3, 2, 1, 8, 7, 6, 5, 12, 11, 10, 9,
+ };
+
+ PcmExport e;
+ e.Open(SampleFormat::S8, 2, false, false, false, true);
+
+ auto dest = e.Export({src, sizeof(src)});
+ CPPUNIT_ASSERT_EQUAL(sizeof(src), dest.size);
+ CPPUNIT_ASSERT(memcmp(dest.data, src, dest.size) == 0);
+
+ e.Open(SampleFormat::S16, 2, false, false, false, true);
+ dest = e.Export({src, sizeof(src)});
+ CPPUNIT_ASSERT_EQUAL(sizeof(expected2), dest.size);
+ CPPUNIT_ASSERT(memcmp(dest.data, expected2, dest.size) == 0);
+
+ e.Open(SampleFormat::S32, 2, false, false, false, true);
+ dest = e.Export({src, sizeof(src)});
+ CPPUNIT_ASSERT_EQUAL(sizeof(expected4), dest.size);
+ CPPUNIT_ASSERT(memcmp(dest.data, expected4, dest.size) == 0);
+}
+
+void
+PcmExportTest::TestDop()
+{
+ static constexpr uint8_t src[] = {
+ 0x01, 0x23, 0x45, 0x67,
+ 0x89, 0xab, 0xcd, 0xef,
+ };
+
+ static constexpr uint32_t expected[] = {
+ 0xff050145,
+ 0xff052367,
+ 0xfffa89cd,
+ 0xfffaabef,
+ };
+
+ PcmExport e;
+ e.Open(SampleFormat::DSD, 2, true, false, false, false);
+
+ auto dest = e.Export({src, sizeof(src)});
+ CPPUNIT_ASSERT_EQUAL(sizeof(expected), dest.size);
+ CPPUNIT_ASSERT(memcmp(dest.data, expected, dest.size) == 0);
+}
diff --git a/test/test_pcm_format.cxx b/test/test_pcm_format.cxx
index 49f4ccd4b..825a8bd84 100644
--- a/test/test_pcm_format.cxx
+++ b/test/test_pcm_format.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,17 +29,14 @@
void
PcmFormatTest::TestFormat8to16()
{
- constexpr unsigned N = 256;
+ constexpr size_t N = 509;
const auto src = TestDataBuffer<int8_t, N>();
PcmBuffer buffer;
- size_t d_size;
PcmDither dither;
- auto d = pcm_convert_to_16(buffer, dither, SampleFormat::S8,
- src, sizeof(src), &d_size);
- auto d_end = pcm_end_pointer(d, d_size);
- CPPUNIT_ASSERT_EQUAL(N, unsigned(d_end - d));
+ auto d = pcm_convert_to_16(buffer, dither, SampleFormat::S8, src);
+ CPPUNIT_ASSERT_EQUAL(N, d.size);
for (size_t i = 0; i < N; ++i)
CPPUNIT_ASSERT_EQUAL(int(src[i]), d[i] >> 8);
@@ -48,16 +45,13 @@ PcmFormatTest::TestFormat8to16()
void
PcmFormatTest::TestFormat16to24()
{
- constexpr unsigned N = 256;
+ constexpr size_t N = 509;
const auto src = TestDataBuffer<int16_t, N>();
PcmBuffer buffer;
- size_t d_size;
- auto d = pcm_convert_to_24(buffer, SampleFormat::S16,
- src, sizeof(src), &d_size);
- auto d_end = pcm_end_pointer(d, d_size);
- CPPUNIT_ASSERT_EQUAL(N, unsigned(d_end - d));
+ auto d = pcm_convert_to_24(buffer, SampleFormat::S16, src);
+ CPPUNIT_ASSERT_EQUAL(N, d.size);
for (size_t i = 0; i < N; ++i)
CPPUNIT_ASSERT_EQUAL(int(src[i]), d[i] >> 8);
@@ -66,16 +60,13 @@ PcmFormatTest::TestFormat16to24()
void
PcmFormatTest::TestFormat16to32()
{
- constexpr unsigned N = 256;
+ constexpr size_t N = 509;
const auto src = TestDataBuffer<int16_t, N>();
PcmBuffer buffer;
- size_t d_size;
- auto d = pcm_convert_to_32(buffer, SampleFormat::S16,
- src, sizeof(src), &d_size);
- auto d_end = pcm_end_pointer(d, d_size);
- CPPUNIT_ASSERT_EQUAL(N, unsigned(d_end - d));
+ auto d = pcm_convert_to_32(buffer, SampleFormat::S16, src);
+ CPPUNIT_ASSERT_EQUAL(N, d.size);
for (size_t i = 0; i < N; ++i)
CPPUNIT_ASSERT_EQUAL(int(src[i]), d[i] >> 16);
@@ -84,31 +75,46 @@ PcmFormatTest::TestFormat16to32()
void
PcmFormatTest::TestFormatFloat()
{
- constexpr unsigned N = 256;
+ constexpr size_t N = 509;
const auto src = TestDataBuffer<int16_t, N>();
PcmBuffer buffer1, buffer2;
- size_t f_size;
- auto f = pcm_convert_to_float(buffer1, SampleFormat::S16,
- src, sizeof(src), &f_size);
- auto f_end = pcm_end_pointer(f, f_size);
- CPPUNIT_ASSERT_EQUAL(N, unsigned(f_end - f));
+ auto f = pcm_convert_to_float(buffer1, SampleFormat::S16, src);
+ CPPUNIT_ASSERT_EQUAL(N, f.size);
- for (auto i = f; i != f_end; ++i) {
- CPPUNIT_ASSERT(*i >= -1.);
- CPPUNIT_ASSERT(*i <= 1.);
+ for (size_t i = 0; i != f.size; ++i) {
+ CPPUNIT_ASSERT(f[i] >= -1.);
+ CPPUNIT_ASSERT(f[i] <= 1.);
}
PcmDither dither;
- size_t d_size;
auto d = pcm_convert_to_16(buffer2, dither,
SampleFormat::FLOAT,
- f, f_size, &d_size);
- auto d_end = pcm_end_pointer(d, d_size);
- CPPUNIT_ASSERT_EQUAL(N, unsigned(d_end - d));
+ f.ToVoid());
+ CPPUNIT_ASSERT_EQUAL(N, d.size);
for (size_t i = 0; i < N; ++i)
CPPUNIT_ASSERT_EQUAL(src[i], d[i]);
+
+ /* check if clamping works */
+ float *writable = const_cast<float *>(f.data);
+ *writable++ = 1.01;
+ *writable++ = 10;
+ *writable++ = -1.01;
+ *writable++ = -10;
+
+ d = pcm_convert_to_16(buffer2, dither,
+ SampleFormat::FLOAT,
+ f.ToVoid());
+ CPPUNIT_ASSERT_EQUAL(N, d.size);
+
+ CPPUNIT_ASSERT_EQUAL(32767, int(d[0]));
+ CPPUNIT_ASSERT_EQUAL(32767, int(d[1]));
+ CPPUNIT_ASSERT_EQUAL(-32768, int(d[2]));
+ CPPUNIT_ASSERT_EQUAL(-32768, int(d[3]));
+
+ for (size_t i = 4; i < N; ++i)
+ CPPUNIT_ASSERT_EQUAL(src[i], d[i]);
}
diff --git a/test/test_pcm_main.cxx b/test/test_pcm_main.cxx
index c034181d9..0e397a15c 100644
--- a/test/test_pcm_main.cxx
+++ b/test/test_pcm_main.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,14 @@
#include <stdlib.h>
+CPPUNIT_TEST_SUITE_REGISTRATION(PcmDitherTest);
+CPPUNIT_TEST_SUITE_REGISTRATION(PcmPackTest);
+CPPUNIT_TEST_SUITE_REGISTRATION(PcmChannelsTest);
+CPPUNIT_TEST_SUITE_REGISTRATION(PcmVolumeTest);
+CPPUNIT_TEST_SUITE_REGISTRATION(PcmFormatTest);
+CPPUNIT_TEST_SUITE_REGISTRATION(PcmMixTest);
+CPPUNIT_TEST_SUITE_REGISTRATION(PcmExportTest);
+
int
main(gcc_unused int argc, gcc_unused char **argv)
{
diff --git a/test/test_pcm_mix.cxx b/test/test_pcm_mix.cxx
index 2a8a11388..973b58f4d 100644
--- a/test/test_pcm_mix.cxx
+++ b/test/test_pcm_mix.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,32 +21,36 @@
#include "test_pcm_all.hxx"
#include "test_pcm_util.hxx"
#include "pcm/PcmMix.hxx"
+#include "pcm/PcmDither.hxx"
template<typename T, SampleFormat format, typename G=RandomInt<T>>
static void
TestPcmMix(G g=G())
{
- constexpr unsigned N = 256;
+ constexpr unsigned N = 509;
const auto src1 = TestDataBuffer<T, N>(g);
const auto src2 = TestDataBuffer<T, N>(g);
+ PcmDither dither;
+
/* portion1=1.0: result must be equal to src1 */
auto result = src1;
- bool success = pcm_mix(result.begin(), src2.begin(), sizeof(result),
+ bool success = pcm_mix(dither,
+ result.begin(), src2.begin(), sizeof(result),
format, 1.0);
CPPUNIT_ASSERT(success);
- AssertEqualWithTolerance(result, src1, 1);
+ AssertEqualWithTolerance(result, src1, 3);
/* portion1=0.0: result must be equal to src2 */
result = src1;
- success = pcm_mix(result.begin(), src2.begin(), sizeof(result),
+ success = pcm_mix(dither, result.begin(), src2.begin(), sizeof(result),
format, 0.0);
CPPUNIT_ASSERT(success);
- AssertEqualWithTolerance(result, src2, 1);
+ AssertEqualWithTolerance(result, src2, 3);
/* portion1=0.5 */
result = src1;
- success = pcm_mix(result.begin(), src2.begin(), sizeof(result),
+ success = pcm_mix(dither, result.begin(), src2.begin(), sizeof(result),
format, 0.5);
CPPUNIT_ASSERT(success);
@@ -54,7 +58,7 @@ TestPcmMix(G g=G())
for (unsigned i = 0; i < N; ++i)
expected[i] = (int64_t(src1[i]) + int64_t(src2[i])) / 2;
- AssertEqualWithTolerance(result, expected, 1);
+ AssertEqualWithTolerance(result, expected, 3);
}
void
diff --git a/test/test_pcm_pack.cxx b/test/test_pcm_pack.cxx
index cab78c499..fff3e10f0 100644
--- a/test/test_pcm_pack.cxx
+++ b/test/test_pcm_pack.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,7 @@
void
PcmPackTest::TestPack24()
{
- constexpr unsigned N = 256;
+ constexpr unsigned N = 509;
const auto src = TestDataBuffer<int32_t, N>(RandomInt24());
uint8_t dest[N * 3];
@@ -49,7 +49,7 @@ PcmPackTest::TestPack24()
void
PcmPackTest::TestUnpack24()
{
- constexpr unsigned N = 256;
+ constexpr unsigned N = 509;
const auto src = TestDataBuffer<uint8_t, N * 3>();
int32_t dest[N];
diff --git a/test/test_pcm_util.hxx b/test/test_pcm_util.hxx
index b378c75a7..f1efbc666 100644
--- a/test/test_pcm_util.hxx
+++ b/test/test_pcm_util.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,6 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "util/ConstBuffer.hxx"
+
#include <array>
#include <random>
@@ -76,6 +78,14 @@ public:
operator typename std::array<T, N>::const_pointer() const {
return begin();
}
+
+ operator ConstBuffer<T>() const {
+ return { begin(), size() };
+ }
+
+ operator ConstBuffer<void>() const {
+ return { begin(), size() * sizeof(T) };
+ }
};
template<typename T>
diff --git a/test/test_pcm_volume.cxx b/test/test_pcm_volume.cxx
index 764d8b127..2d908f6c1 100644
--- a/test/test_pcm_volume.cxx
+++ b/test/test_pcm_volume.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,169 +17,109 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "config.h"
#include "test_pcm_all.hxx"
-#include "pcm/PcmVolume.hxx"
+#include "pcm/Volume.hxx"
+#include "pcm/Traits.hxx"
+#include "util/ConstBuffer.hxx"
+#include "util/Error.hxx"
#include "test_pcm_util.hxx"
#include <algorithm>
#include <string.h>
-void
-PcmVolumeTest::TestVolume8()
+template<SampleFormat F, class Traits=SampleTraits<F>,
+ typename G=RandomInt<typename Traits::value_type>>
+static void
+TestVolume(G g=G())
{
- constexpr unsigned N = 256;
- static int8_t zero[N];
- const auto src = TestDataBuffer<int8_t, N>();
+ typedef typename Traits::value_type value_type;
+
+ PcmVolume pv;
+ CPPUNIT_ASSERT(pv.Open(F, IgnoreError()));
- int8_t dest[N];
+ constexpr size_t N = 509;
+ static value_type zero[N];
+ const auto _src = TestDataBuffer<value_type, N>(g);
+ const ConstBuffer<void> src(_src, sizeof(_src));
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S8, 0));
- CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, zero, sizeof(zero)));
+ pv.SetVolume(0);
+ auto dest = pv.Apply(src);
+ CPPUNIT_ASSERT_EQUAL(src.size, dest.size);
+ CPPUNIT_ASSERT_EQUAL(0, memcmp(dest.data, zero, sizeof(zero)));
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S8, PCM_VOLUME_1));
- CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, src, sizeof(src)));
+ pv.SetVolume(PCM_VOLUME_1);
+ dest = pv.Apply(src);
+ CPPUNIT_ASSERT_EQUAL(src.size, dest.size);
+ CPPUNIT_ASSERT_EQUAL(0, memcmp(dest.data, src.data, src.size));
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S8, PCM_VOLUME_1 / 2));
+ pv.SetVolume(PCM_VOLUME_1 / 2);
+ dest = pv.Apply(src);
+ CPPUNIT_ASSERT_EQUAL(src.size, dest.size);
+ const auto _dest = ConstBuffer<value_type>::FromVoid(dest);
for (unsigned i = 0; i < N; ++i) {
- CPPUNIT_ASSERT(dest[i] >= (src[i] - 1) / 2);
- CPPUNIT_ASSERT(dest[i] <= src[i] / 2 + 1);
+ const auto expected = (_src[i] + 1) / 2;
+ CPPUNIT_ASSERT(_dest[i] >= expected - 4);
+ CPPUNIT_ASSERT(_dest[i] <= expected + 4);
}
+
+ pv.Close();
}
void
-PcmVolumeTest::TestVolume16()
+PcmVolumeTest::TestVolume8()
{
- constexpr unsigned N = 256;
- static int16_t zero[N];
- const auto src = TestDataBuffer<int16_t, N>();
-
- int16_t dest[N];
-
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S16, 0));
- CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, zero, sizeof(zero)));
-
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S16, PCM_VOLUME_1));
- CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, src, sizeof(src)));
-
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S16, PCM_VOLUME_1 / 2));
+ TestVolume<SampleFormat::S8>();
+}
- for (unsigned i = 0; i < N; ++i) {
- CPPUNIT_ASSERT(dest[i] >= (src[i] - 1) / 2);
- CPPUNIT_ASSERT(dest[i] <= src[i] / 2 + 1);
- }
+void
+PcmVolumeTest::TestVolume16()
+{
+ TestVolume<SampleFormat::S16>();
}
void
PcmVolumeTest::TestVolume24()
{
- constexpr unsigned N = 256;
- static int32_t zero[N];
- const auto src = TestDataBuffer<int32_t, N>(RandomInt24());
-
- int32_t dest[N];
-
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S24_P32, 0));
- CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, zero, sizeof(zero)));
-
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S24_P32, PCM_VOLUME_1));
- CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, src, sizeof(src)));
-
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S24_P32, PCM_VOLUME_1 / 2));
-
- for (unsigned i = 0; i < N; ++i) {
- CPPUNIT_ASSERT(dest[i] >= (src[i] - 1) / 2);
- CPPUNIT_ASSERT(dest[i] <= src[i] / 2 + 1);
- }
+ TestVolume<SampleFormat::S24_P32>(RandomInt24());
}
void
PcmVolumeTest::TestVolume32()
{
- constexpr unsigned N = 256;
- static int32_t zero[N];
- const auto src = TestDataBuffer<int32_t, N>();
-
- int32_t dest[N];
-
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S32, 0));
- CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, zero, sizeof(zero)));
-
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S32, PCM_VOLUME_1));
- CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, src, sizeof(src)));
-
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::S32, PCM_VOLUME_1 / 2));
-
- for (unsigned i = 0; i < N; ++i) {
- CPPUNIT_ASSERT(dest[i] >= (src[i] - 1) / 2);
- CPPUNIT_ASSERT(dest[i] <= src[i] / 2 + 1);
- }
+ TestVolume<SampleFormat::S32>();
}
void
PcmVolumeTest::TestVolumeFloat()
{
- constexpr unsigned N = 256;
- static float zero[N];
- const auto src = TestDataBuffer<float, N>(RandomFloat());
+ PcmVolume pv;
+ CPPUNIT_ASSERT(pv.Open(SampleFormat::FLOAT, IgnoreError()));
- float dest[N];
+ constexpr size_t N = 509;
+ static float zero[N];
+ const auto _src = TestDataBuffer<float, N>(RandomFloat());
+ const ConstBuffer<void> src(_src, sizeof(_src));
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::FLOAT, 0));
- CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, zero, sizeof(zero)));
+ pv.SetVolume(0);
+ auto dest = pv.Apply(src);
+ CPPUNIT_ASSERT_EQUAL(src.size, dest.size);
+ CPPUNIT_ASSERT_EQUAL(0, memcmp(dest.data, zero, sizeof(zero)));
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::FLOAT, PCM_VOLUME_1));
- CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, src, sizeof(src)));
+ pv.SetVolume(PCM_VOLUME_1);
+ dest = pv.Apply(src);
+ CPPUNIT_ASSERT_EQUAL(src.size, dest.size);
+ CPPUNIT_ASSERT_EQUAL(0, memcmp(dest.data, src.data, src.size));
- std::copy(src.begin(), src.end(), dest);
- CPPUNIT_ASSERT_EQUAL(true,
- pcm_volume(dest, sizeof(dest),
- SampleFormat::FLOAT,
- PCM_VOLUME_1 / 2));
+ pv.SetVolume(PCM_VOLUME_1 / 2);
+ dest = pv.Apply(src);
+ CPPUNIT_ASSERT_EQUAL(src.size, dest.size);
+ const auto _dest = ConstBuffer<float>::FromVoid(dest);
for (unsigned i = 0; i < N; ++i)
- CPPUNIT_ASSERT_DOUBLES_EQUAL(src[i] / 2, dest[i], 1);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(_src[i] / 2, _dest[i], 1);
+
+ pv.Close();
}
diff --git a/test/test_queue_priority.cxx b/test/test_queue_priority.cxx
index fca18fc2d..517cb028c 100644
--- a/test/test_queue_priority.cxx
+++ b/test/test_queue_priority.cxx
@@ -1,7 +1,6 @@
#include "config.h"
-#include "Queue.hxx"
-#include "Song.hxx"
-#include "Directory.hxx"
+#include "queue/Queue.hxx"
+#include "DetachedSong.hxx"
#include "util/Macros.hxx"
#include <cppunit/TestFixture.h>
@@ -9,21 +8,8 @@
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
-Directory detached_root;
-
-Directory::Directory() {}
-Directory::~Directory() {}
-
-Song *
-Song::DupDetached() const
-{
- return const_cast<Song *>(this);
-}
-
-void
-Song::Free()
-{
-}
+Tag::Tag(const Tag &) {}
+void Tag::Clear() {}
static void
check_descending_priority(const Queue *queue,
@@ -53,12 +39,29 @@ public:
void
QueuePriorityTest::TestPriority()
{
- static Song songs[16];
+ DetachedSong songs[16] = {
+ DetachedSong("0.ogg"),
+ DetachedSong("1.ogg"),
+ DetachedSong("2.ogg"),
+ DetachedSong("3.ogg"),
+ DetachedSong("4.ogg"),
+ DetachedSong("5.ogg"),
+ DetachedSong("6.ogg"),
+ DetachedSong("7.ogg"),
+ DetachedSong("8.ogg"),
+ DetachedSong("9.ogg"),
+ DetachedSong("a.ogg"),
+ DetachedSong("b.ogg"),
+ DetachedSong("c.ogg"),
+ DetachedSong("d.ogg"),
+ DetachedSong("e.ogg"),
+ DetachedSong("f.ogg"),
+ };
Queue queue(32);
for (unsigned i = 0; i < ARRAY_SIZE(songs); ++i)
- queue.Append(&songs[i], 0);
+ queue.Append(DetachedSong(songs[i]), 0);
CPPUNIT_ASSERT_EQUAL(unsigned(ARRAY_SIZE(songs)), queue.GetLength());
diff --git a/test/test_rewind.cxx b/test/test_rewind.cxx
new file mode 100644
index 000000000..3ab37427a
--- /dev/null
+++ b/test/test_rewind.cxx
@@ -0,0 +1,154 @@
+/*
+ * Unit tests for class RewindInputStream.
+ */
+
+#include "config.h"
+#include "input/plugins/RewindInputPlugin.hxx"
+#include "input/InputStream.hxx"
+#include "thread/Mutex.hxx"
+#include "thread/Cond.hxx"
+#include "util/Error.hxx"
+
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <string>
+
+#include <string.h>
+#include <stdlib.h>
+
+class StringInputStream final : public InputStream {
+ const char *data;
+ size_t remaining;
+
+public:
+ StringInputStream(const char *_uri,
+ Mutex &_mutex, Cond &_cond,
+ const char *_data)
+ :InputStream(_uri, _mutex, _cond),
+ data(_data), remaining(strlen(data)) {
+ SetReady();
+ }
+
+ /* virtual methods from InputStream */
+ bool IsEOF() override {
+ return remaining == 0;
+ }
+
+ size_t Read(void *ptr, size_t read_size,
+ gcc_unused Error &error) override {
+ size_t nbytes = std::min(remaining, read_size);
+ memcpy(ptr, data, nbytes);
+ data += nbytes;
+ remaining -= nbytes;
+ offset += nbytes;
+ return nbytes;
+ }
+};
+
+class RewindTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(RewindTest);
+ CPPUNIT_TEST(TestRewind);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void TestRewind() {
+ Mutex mutex;
+ Cond cond;
+
+ StringInputStream *sis =
+ new StringInputStream("foo://", mutex, cond,
+ "foo bar");
+ CPPUNIT_ASSERT(sis->IsReady());
+
+ InputStream *ris = input_rewind_open(sis);
+ CPPUNIT_ASSERT(ris != sis);
+ CPPUNIT_ASSERT(ris != nullptr);
+
+ const ScopeLock protect(mutex);
+
+ ris->Update();
+ CPPUNIT_ASSERT(ris->IsReady());
+ CPPUNIT_ASSERT(!ris->KnownSize());
+ CPPUNIT_ASSERT_EQUAL(offset_type(0), ris->GetOffset());
+
+ Error error;
+ char buffer[16];
+ size_t nbytes = ris->Read(buffer, 2, error);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
+ CPPUNIT_ASSERT_EQUAL('f', buffer[0]);
+ CPPUNIT_ASSERT_EQUAL('o', buffer[1]);
+ CPPUNIT_ASSERT_EQUAL(offset_type(2), ris->GetOffset());
+ CPPUNIT_ASSERT(!ris->IsEOF());
+
+ nbytes = ris->Read(buffer, 2, error);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
+ CPPUNIT_ASSERT_EQUAL('o', buffer[0]);
+ CPPUNIT_ASSERT_EQUAL(' ', buffer[1]);
+ CPPUNIT_ASSERT_EQUAL(offset_type(4), ris->GetOffset());
+ CPPUNIT_ASSERT(!ris->IsEOF());
+
+ CPPUNIT_ASSERT(ris->Seek(1, error));
+ CPPUNIT_ASSERT_EQUAL(offset_type(1), ris->GetOffset());
+ CPPUNIT_ASSERT(!ris->IsEOF());
+
+ nbytes = ris->Read(buffer, 2, error);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
+ CPPUNIT_ASSERT_EQUAL('o', buffer[0]);
+ CPPUNIT_ASSERT_EQUAL('o', buffer[1]);
+ CPPUNIT_ASSERT_EQUAL(offset_type(3), ris->GetOffset());
+ CPPUNIT_ASSERT(!ris->IsEOF());
+
+ CPPUNIT_ASSERT(ris->Seek(0, error));
+ CPPUNIT_ASSERT_EQUAL(offset_type(0), ris->GetOffset());
+ CPPUNIT_ASSERT(!ris->IsEOF());
+
+ nbytes = ris->Read(buffer, 2, error);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
+ CPPUNIT_ASSERT_EQUAL('f', buffer[0]);
+ CPPUNIT_ASSERT_EQUAL('o', buffer[1]);
+ CPPUNIT_ASSERT_EQUAL(offset_type(2), ris->GetOffset());
+ CPPUNIT_ASSERT(!ris->IsEOF());
+
+ nbytes = ris->Read(buffer, sizeof(buffer), error);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
+ CPPUNIT_ASSERT_EQUAL('o', buffer[0]);
+ CPPUNIT_ASSERT_EQUAL(' ', buffer[1]);
+ CPPUNIT_ASSERT_EQUAL(offset_type(4), ris->GetOffset());
+ CPPUNIT_ASSERT(!ris->IsEOF());
+
+ nbytes = ris->Read(buffer, sizeof(buffer), error);
+ CPPUNIT_ASSERT_EQUAL(size_t(3), nbytes);
+ CPPUNIT_ASSERT_EQUAL('b', buffer[0]);
+ CPPUNIT_ASSERT_EQUAL('a', buffer[1]);
+ CPPUNIT_ASSERT_EQUAL('r', buffer[2]);
+ CPPUNIT_ASSERT_EQUAL(offset_type(7), ris->GetOffset());
+ CPPUNIT_ASSERT(ris->IsEOF());
+
+ CPPUNIT_ASSERT(ris->Seek(3, error));
+ CPPUNIT_ASSERT_EQUAL(offset_type(3), ris->GetOffset());
+ CPPUNIT_ASSERT(!ris->IsEOF());
+
+ nbytes = ris->Read(buffer, sizeof(buffer), error);
+ CPPUNIT_ASSERT_EQUAL(size_t(4), nbytes);
+ CPPUNIT_ASSERT_EQUAL(' ', buffer[0]);
+ CPPUNIT_ASSERT_EQUAL('b', buffer[1]);
+ CPPUNIT_ASSERT_EQUAL('a', buffer[2]);
+ CPPUNIT_ASSERT_EQUAL('r', buffer[3]);
+ CPPUNIT_ASSERT_EQUAL(offset_type(7), ris->GetOffset());
+ CPPUNIT_ASSERT(ris->IsEOF());
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(RewindTest);
+
+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;
+}
diff --git a/test/test_translate_song.cxx b/test/test_translate_song.cxx
new file mode 100644
index 000000000..e3c1bcb79
--- /dev/null
+++ b/test/test_translate_song.cxx
@@ -0,0 +1,318 @@
+/*
+ * Unit tests for playlist_check_translate_song().
+ */
+
+#include "config.h"
+#include "playlist/PlaylistSong.hxx"
+#include "DetachedSong.hxx"
+#include "SongLoader.hxx"
+#include "client/Client.hxx"
+#include "tag/TagBuilder.hxx"
+#include "tag/Tag.hxx"
+#include "util/Domain.hxx"
+#include "fs/AllocatedPath.hxx"
+#include "ls.hxx"
+#include "Log.hxx"
+#include "db/DatabaseSong.hxx"
+#include "storage/plugins/LocalStorage.hxx"
+#include "util/Error.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;
+}
+
+static const char *const music_directory = "/music";
+static Storage *storage;
+
+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(gcc_unused const Database &db,
+ gcc_unused const Storage &_storage,
+ 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;
+}
+
+const Database *
+Client::GetDatabase(gcc_unused Error &error) const
+{
+ return reinterpret_cast<const Database *>(this);
+}
+
+const Storage *
+Client::GetStorage() const
+{
+ return ::storage;
+}
+
+bool
+Client::AllowFile(gcc_unused Path path_fs, gcc_unused Error &error) const
+{
+ /* always return false, so a SongLoader with a non-nullptr
+ Client pointer will be regarded "insecure", while one with
+ client==nullptr will allow all files */
+ return false;
+}
+
+static std::string
+ToString(const Tag &tag)
+{
+ std::string result;
+
+ if (!tag.duration.IsNegative()) {
+ char buffer[64];
+ sprintf(buffer, "%d", tag.duration.ToMS());
+ result.append(buffer);
+ }
+
+ for (const auto &item : tag) {
+ 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.GetStartTime().IsPositive()) {
+ sprintf(buffer, "%u", song.GetStartTime().ToMS());
+ result.append(buffer);
+ }
+
+ result.push_back('-');
+
+ if (song.GetEndTime().IsPositive()) {
+ sprintf(buffer, "%u", song.GetEndTime().ToMS());
+ result.append(buffer);
+ }
+
+ result.push_back('|');
+
+ result.append(ToString(song.GetTag()));
+
+ return result;
+}
+
+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() {
+ DetachedSong song1("http://example.com/foo.ogg");
+ auto se = ToString(song1);
+ const SongLoader loader(nullptr, nullptr);
+ CPPUNIT_ASSERT(playlist_check_translate_song(song1, "/ignored",
+ loader));
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song1));
+ }
+
+ void TestInsecure() {
+ /* illegal because secure=false */
+ DetachedSong song1 (uri1);
+ const SongLoader loader(*reinterpret_cast<const Client *>(1));
+ CPPUNIT_ASSERT(!playlist_check_translate_song(song1, nullptr,
+ loader));
+ }
+
+ void TestSecure() {
+ DetachedSong song1(uri1, MakeTag1b());
+ auto s1 = ToString(song1);
+ auto se = ToString(DetachedSong(uri1, MakeTag1c()));
+
+ const SongLoader loader(nullptr, nullptr);
+ CPPUNIT_ASSERT(playlist_check_translate_song(song1, "/ignored",
+ loader));
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song1));
+ }
+
+ void TestInDatabase() {
+ const SongLoader loader(reinterpret_cast<const Database *>(1),
+ storage);
+
+ DetachedSong song1("doesntexist");
+ CPPUNIT_ASSERT(!playlist_check_translate_song(song1, nullptr,
+ loader));
+
+ DetachedSong song2(uri2, MakeTag2b());
+ auto s1 = ToString(song2);
+ auto se = ToString(DetachedSong(uri2, MakeTag2c()));
+ CPPUNIT_ASSERT(playlist_check_translate_song(song2, nullptr,
+ loader));
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song2));
+
+ DetachedSong song3("/music/foo/bar.ogg", MakeTag2b());
+ s1 = ToString(song3);
+ se = ToString(DetachedSong(uri2, MakeTag2c()));
+ CPPUNIT_ASSERT(playlist_check_translate_song(song3, nullptr,
+ loader));
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song3));
+ }
+
+ void TestRelative() {
+ const Database &db = *reinterpret_cast<const Database *>(1);
+ const SongLoader secure_loader(&db, storage);
+ const SongLoader insecure_loader(*reinterpret_cast<const Client *>(1),
+ &db, storage);
+
+ /* map to music_directory */
+ DetachedSong song1("bar.ogg", MakeTag2b());
+ auto s1 = ToString(song1);
+ auto se = ToString(DetachedSong(uri2, MakeTag2c()));
+ CPPUNIT_ASSERT(playlist_check_translate_song(song1, "/music/foo",
+ insecure_loader));
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song1));
+
+ /* illegal because secure=false */
+ DetachedSong song2("bar.ogg", MakeTag2b());
+ CPPUNIT_ASSERT(!playlist_check_translate_song(song1, "/foo",
+ insecure_loader));
+
+ /* legal because secure=true */
+ DetachedSong song3("bar.ogg", MakeTag1b());
+ s1 = ToString(song3);
+ se = ToString(DetachedSong(uri1, MakeTag1c()));
+ CPPUNIT_ASSERT(playlist_check_translate_song(song3, "/foo",
+ secure_loader));
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song3));
+
+ /* relative to http:// */
+ DetachedSong song4("bar.ogg", MakeTag2a());
+ s1 = ToString(song4);
+ se = ToString(DetachedSong("http://example.com/foo/bar.ogg", MakeTag2a()));
+ CPPUNIT_ASSERT(playlist_check_translate_song(song4, "http://example.com/foo",
+ insecure_loader));
+ CPPUNIT_ASSERT_EQUAL(se, ToString(song4));
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TranslateSongTest);
+
+int
+main(gcc_unused int argc, gcc_unused char **argv)
+{
+ storage = CreateLocalStorage(Path::FromFS(music_directory));
+
+ CppUnit::TextUi::TestRunner runner;
+ auto &registry = CppUnit::TestFactoryRegistry::getRegistry();
+ runner.addTest(registry.makeTest());
+ return runner.run() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/test/test_util.cxx b/test/test_util.cxx
index 91e87957f..3e79aeca0 100644
--- a/test/test_util.cxx
+++ b/test/test_util.cxx
@@ -4,6 +4,7 @@
#include "config.h"
#include "util/UriUtil.hxx"
+#include "TestCircularBuffer.hxx"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
@@ -63,10 +64,13 @@ public:
uri_remove_auth("http://foo@www.example.com/"));
CPPUNIT_ASSERT_EQUAL(std::string(),
uri_remove_auth("http://www.example.com/f:oo@bar"));
+ CPPUNIT_ASSERT_EQUAL(std::string("ftp://ftp.example.com/"),
+ uri_remove_auth("ftp://foo:bar@ftp.example.com/"));
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(UriUtilTest);
+CPPUNIT_TEST_SUITE_REGISTRATION(TestCircularBuffer);
int
main(gcc_unused int argc, gcc_unused char **argv)
diff --git a/test/test_vorbis_encoder.cxx b/test/test_vorbis_encoder.cxx
index 1d95f6deb..59b901da2 100644
--- a/test/test_vorbis_encoder.cxx
+++ b/test/test_vorbis_encoder.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,12 +18,13 @@
*/
#include "config.h"
-#include "EncoderList.hxx"
-#include "EncoderPlugin.hxx"
+#include "encoder/EncoderList.hxx"
+#include "encoder/EncoderPlugin.hxx"
#include "AudioFormat.hxx"
-#include "ConfigData.hxx"
+#include "config/ConfigData.hxx"
#include "stdbin.h"
#include "tag/Tag.hxx"
+#include "tag/TagBuilder.hxx"
#include "util/Error.hxx"
#include <stddef.h>
@@ -81,8 +82,13 @@ main(gcc_unused int argc, gcc_unused char **argv)
encoder_to_stdout(*encoder);
Tag tag;
- tag.AddItem(TAG_ARTIST, "Foo");
- tag.AddItem(TAG_TITLE, "Bar");
+
+ {
+ TagBuilder tag_builder;
+ tag_builder.AddItem(TAG_ARTIST, "Foo");
+ tag_builder.AddItem(TAG_TITLE, "Bar");
+ tag_builder.Commit(tag);
+ }
success = encoder_tag(encoder, &tag, IgnoreError());
assert(success);
diff --git a/test/visit_archive.cxx b/test/visit_archive.cxx
index 6e66c4696..1ff3ba484 100644
--- a/test/visit_archive.cxx
+++ b/test/visit_archive.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,31 +20,23 @@
#include "config.h"
#include "stdbin.h"
#include "tag/Tag.hxx"
-#include "ConfigGlobal.hxx"
-#include "IOThread.hxx"
-#include "InputInit.hxx"
-#include "ArchiveList.hxx"
-#include "ArchivePlugin.hxx"
-#include "ArchiveFile.hxx"
-#include "ArchiveVisitor.hxx"
+#include "config/ConfigGlobal.hxx"
+#include "ScopeIOThread.hxx"
+#include "input/Init.hxx"
+#include "archive/ArchiveList.hxx"
+#include "archive/ArchivePlugin.hxx"
+#include "archive/ArchiveFile.hxx"
+#include "archive/ArchiveVisitor.hxx"
#include "fs/Path.hxx"
#include "util/Error.hxx"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <unistd.h>
#include <stdlib.h>
-static void
-my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level,
- const gchar *message, gcc_unused gpointer user_data)
-{
- if (log_domain != NULL)
- g_printerr("%s: %s\n", log_domain, message);
- else
- g_printerr("%s\n", message);
-}
-
class MyArchiveVisitor final : public ArchiveVisitor {
public:
virtual void VisitArchiveEntry(const char *path_utf8) override {
@@ -67,18 +59,17 @@ main(int argc, char **argv)
/* initialize GLib */
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(NULL);
#endif
-
- g_log_set_default_handler(my_log_func, NULL);
+#endif
/* initialize MPD */
config_global_init();
- io_thread_init();
- io_thread_start();
+ const ScopeIOThread io_thread;
archive_plugin_init_all();
@@ -89,7 +80,7 @@ main(int argc, char **argv)
/* open the archive and dump it */
- const archive_plugin *plugin = archive_plugin_from_name(plugin_name);
+ const ArchivePlugin *plugin = archive_plugin_from_name(plugin_name);
if (plugin == nullptr) {
fprintf(stderr, "No such plugin: %s\n", plugin_name);
return EXIT_FAILURE;
@@ -97,7 +88,7 @@ main(int argc, char **argv)
int result = EXIT_SUCCESS;
- ArchiveFile *file = archive_file_open(plugin, path.c_str(), error);
+ ArchiveFile *file = archive_file_open(plugin, path, error);
if (file != nullptr) {
MyArchiveVisitor visitor;
file->Visit(visitor);
@@ -113,8 +104,6 @@ main(int argc, char **argv)
archive_plugin_deinit_all();
- io_thread_deinit();
-
config_global_finish();
return result;