Merge lp:~xavi-garcia-mena/mediascanner2/ms-dbus-wal into lp:mediascanner2

Proposed by Xavi Garcia
Status: Needs review
Proposed branch: lp:~xavi-garcia-mena/mediascanner2/ms-dbus-wal
Merge into: lp:mediascanner2
Diff against target: 2214 lines (+945/-453)
18 files modified
debian/control (+1/-0)
src/daemon/CMakeLists.txt (+1/-0)
src/mediascanner/CMakeLists.txt (+20/-2)
src/mediascanner/MediaStore.cc (+94/-19)
src/mediascanner/MediaStore.hh (+9/-1)
src/mediascanner/d-bus/service-stub.cc (+6/-0)
src/mediascanner/d-bus/service-stub.hh (+1/-0)
src/mediascanner/mediascanner-2.0.map (+35/-5)
src/ms-dbus/CMakeLists.txt (+1/-2)
src/ms-dbus/main.cc (+2/-2)
src/ms-dbus/service-skeleton.cc (+2/-2)
src/ms-dbus/service-skeleton.hh (+1/-1)
src/qml/Ubuntu/MediaScanner/MediaStoreWrapper.cc (+1/-1)
test/CMakeLists.txt (+15/-5)
test/test_dbus.cc (+1/-1)
test/test_mediastore.cc (+658/-412)
test/utils/DBusTest.cpp (+50/-0)
test/utils/DBusTest.h (+47/-0)
To merge this branch: bzr merge lp:~xavi-garcia-mena/mediascanner2/ms-dbus-wal
Reviewer Review Type Date Requested Status
unity-api-1-bot continuous-integration Needs Fixing
PS Jenkins bot (community) continuous-integration Needs Fixing
Jussi Pakkanen (community) Needs Fixing
Jamie Strandboge Pending
James Henstridge Pending
Review via email: mp+249346@code.launchpad.net

Commit message

Modified to use the d-bus interface when MediaStore is created in Read Only mode.

Description of the change

Modified to use the d-bus interface when MediaStore is created in Read Only mode.

To post a comment you must log in.
Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

Looking quite nice. However one thing that is a bit concerning is that the tests duplicate a lot of code in the dbus and non-dbus cases. Would it be possible to consolidate these so that every test is run with common code. So something along the lines of this:

void testImplementation(MediaStore &writer, MediaStore &queryer) {
  // First set up
  writer.insert(whatevs);

  // Then query
  ASSERT_EQ(queryer.query("..."), result);
}

And then have the actual dbus and non-dbus test cases just do basically this:

void testWithoutDbus() {
  MediaStore local(READWRITE);

  testImplementation(local, local);
}

void testWithDbus() {
  MediaStore writer(READWRITE);
  MediaStore queryer(READONLY);

  testImplementation(writer, queryer);
}

review: Needs Fixing
300. By Xavi Garcia

Modifed media store tests to avoid duplicating code

301. By Xavi Garcia

Removed Unity-api dependency, as it was not needed

302. By Xavi Garcia

Added libqtdbustest to test the d-bus connection

Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

Looks fine. Just a few niggles:

- the new variables have an underscore after their names, whereas the naming convention elsewere is not to have underscores
- when printing the text about error messages, please also print the URL of the bug in question
- in brokenfiles you wrap everything in a try/catch that just prints a generic error, why is this, AFAICR gtest will automatically fail any test that throws and prints the exception's error messag

I think we need to start talking to Jamie about the dbus/apparmor bits that this thing needs (also in music-app).

review: Needs Fixing
303. By Xavi Garcia

Erased final _ for member variables

Revision history for this message
Xavi Garcia (xavi-garcia-mena) wrote :

Hey Jussi,

what file do you mean when you say?
*when printing the text about error messages, please also print the URL of
the bug in question*

What do you mean to print the URL of the bug? When an exception is thrown?

I've erased the try... catch, as it was part of a test I did and changed
(but obviously forgot to erase the try..catch)

Thanks,

Xavi

On Mon, Feb 16, 2015 at 2:40 PM, Jussi Pakkanen <
<email address hidden>> wrote:

> Review: Needs Fixing
>
> Looks fine. Just a few niggles:
>
> - the new variables have an underscore after their names, whereas the
> naming convention elsewere is not to have underscores
> - when printing the text about error messages, please also print the URL
> of the bug in question
> - in brokenfiles you wrap everything in a try/catch that just prints a
> generic error, why is this, AFAICR gtest will automatically fail any test
> that throws and prints the exception's error messag
>
> I think we need to start talking to Jamie about the dbus/apparmor bits
> that this thing needs (also in music-app).
> --
>
> https://code.launchpad.net/~xavi-garcia-mena/mediascanner2/ms-dbus-wal/+merge/249346
> You are the owner of lp:~xavi-garcia-mena/mediascanner2/ms-dbus-wal.
>

304. By Xavi Garcia

Added bug link in error message and remove unnecessary try...catch in unit test

Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

Now we need to do the AppArmor bits and for that we need Jamie's help, so I subscribed him.

What we are trying to do here is the following:

Currently users of Mediascanner (media scopes and music-app) have read-only access to Mediascanner's media storage dir ~/.cache/mediascanner-2.0. This MR changes it so that they no longer may access the file directly, instead they call a small dbus server binary instead.

This means that we need the following Apparmor changes:

- remove read access from existing users
- grant them access to the dbus server instead
- create new daemon that is allowed to own the service name and has r/w access to the media directory

Does this seem like a suitable approach, security-wise?

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:304
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~xavi-garcia-mena/mediascanner2/ms-dbus-wal/+merge/249346/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/mediascanner2-ci/188/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/mediascanner2-vivid-amd64-ci/25/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/mediascanner2-vivid-armhf-ci/25/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/mediascanner2-vivid-i386-ci/25/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mediascanner2-ci/188/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)

Unmerged revisions

304. By Xavi Garcia

Added bug link in error message and remove unnecessary try...catch in unit test

303. By Xavi Garcia

Erased final _ for member variables

302. By Xavi Garcia

Added libqtdbustest to test the d-bus connection

301. By Xavi Garcia

Removed Unity-api dependency, as it was not needed

300. By Xavi Garcia

Modifed media store tests to avoid duplicating code

299. By Xavi Garcia

Using DBus for read only mode

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2014-10-09 08:48:05 +0000
+++ debian/control 2015-02-16 14:24:40 +0000
@@ -18,6 +18,7 @@
18 libgdk-pixbuf2.0-dev,18 libgdk-pixbuf2.0-dev,
19 libgtest-dev,19 libgtest-dev,
20 libproperties-cpp-dev,20 libproperties-cpp-dev,
21 libqtdbustest1-dev,
21 libsqlite3-dev (>= 3.8.5),22 libsqlite3-dev (>= 3.8.5),
22 libudisks2-dev,23 libudisks2-dev,
23 qt5-default,24 qt5-default,
2425
=== modified file 'src/daemon/CMakeLists.txt'
--- src/daemon/CMakeLists.txt 2014-10-09 08:48:05 +0000
+++ src/daemon/CMakeLists.txt 2015-02-16 14:24:40 +0000
@@ -9,6 +9,7 @@
9 SubtreeWatcher.cc9 SubtreeWatcher.cc
10 Scanner.cc10 Scanner.cc
11 ../mediascanner/utils.cc11 ../mediascanner/utils.cc
12 $<TARGET_OBJECTS:mediascanner-dbus-static>
12)13)
1314
14target_link_libraries(scannerstuff ${GST_LIBRARIES} ${EXIF_LDFLAGS} ${UDISKS_LDFLAGS}15target_link_libraries(scannerstuff ${GST_LIBRARIES} ${EXIF_LDFLAGS} ${UDISKS_LDFLAGS}
1516
=== modified file 'src/mediascanner/CMakeLists.txt'
--- src/mediascanner/CMakeLists.txt 2014-08-22 14:33:27 +0000
+++ src/mediascanner/CMakeLists.txt 2015-02-16 14:24:40 +0000
@@ -1,3 +1,18 @@
1pkg_check_modules(DBUSCPP dbus-cpp REQUIRED)
2
3add_library(
4 mediascanner-dbus-static OBJECT
5 d-bus/dbus-codec.cc
6 d-bus/service-stub.cc
7)
8
9set_target_properties(
10 mediascanner-dbus-static
11 PROPERTIES
12 LINK_FLAGS "-Wl,--export-all-symbols"
13 COMPILE_FLAGS -fPIC
14)
15
1add_library(mediascanner SHARED16add_library(mediascanner SHARED
2 MediaFile.cc17 MediaFile.cc
3 MediaFileBuilder.cc18 MediaFileBuilder.cc
@@ -9,6 +24,7 @@
9 utils.cc24 utils.cc
10 mozilla/fts3_porter.c25 mozilla/fts3_porter.c
11 mozilla/Normalize.c26 mozilla/Normalize.c
27 $<TARGET_OBJECTS:mediascanner-dbus-static>
12)28)
1329
14set(symbol_map "${CMAKE_CURRENT_SOURCE_DIR}/mediascanner-2.0.map")30set(symbol_map "${CMAKE_CURRENT_SOURCE_DIR}/mediascanner-2.0.map")
@@ -16,8 +32,10 @@
16 LINK_FLAGS "${ldflags} -Wl,--version-script,${symbol_map}")32 LINK_FLAGS "${ldflags} -Wl,--version-script,${symbol_map}")
17set_target_properties(mediascanner PROPERTIES LINK_DEPENDS ${symbol_map})33set_target_properties(mediascanner PROPERTIES LINK_DEPENDS ${symbol_map})
1834
19add_definitions(${MEDIASCANNER_CFLAGS})35add_definitions(${DBUSCPP_CFLAGS} ${MEDIASCANNER_CFLAGS})
20target_link_libraries(mediascanner ${MEDIASCANNER_LIBRARIES})36
37include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src)
38target_link_libraries(mediascanner ${MEDIASCANNER_LIBRARIES} ${DBUSCPP_LDFLAGS})
2139
22set_target_properties(mediascanner PROPERTIES40set_target_properties(mediascanner PROPERTIES
23 OUTPUT_NAME "mediascanner-2.0"41 OUTPUT_NAME "mediascanner-2.0"
2442
=== modified file 'src/mediascanner/MediaStore.cc'
--- src/mediascanner/MediaStore.cc 2015-01-28 09:41:26 +0000
+++ src/mediascanner/MediaStore.cc 2015-02-16 14:24:40 +0000
@@ -39,6 +39,7 @@
39#include "Filter.hh"39#include "Filter.hh"
40#include "internal/sqliteutils.hh"40#include "internal/sqliteutils.hh"
41#include "internal/utils.hh"41#include "internal/utils.hh"
42#include "d-bus/service-stub.hh"
4243
43using namespace std;44using namespace std;
4445
@@ -54,6 +55,11 @@
54 // http://sqlite.com/faq.html#q655 // http://sqlite.com/faq.html#q6
55 std::mutex dbMutex;56 std::mutex dbMutex;
5657
58 OpenType access_mode;
59
60 std::unique_ptr<mediascanner::dbus::ServiceStub> media_store_dbus;
61
62 MediaStorePrivate(OpenType access);
57 void insert(const MediaFile &m) const;63 void insert(const MediaFile &m) const;
58 void remove(const std::string &fname) const;64 void remove(const std::string &fname) const;
59 void insert_broken_file(const std::string &fname, const std::string &etag) const;65 void insert_broken_file(const std::string &fname, const std::string &etag) const;
@@ -121,7 +127,7 @@
121 ** (<hit count> / <global hit count>) * <column weight>127 ** (<hit count> / <global hit count>) * <column weight>
122 **128 **
123 ** aPhraseinfo[] points to the start of the data for phrase iPhrase. So129 ** aPhraseinfo[] points to the start of the data for phrase iPhrase. So
124 ** the hit count and global hit counts for each column are found in 130 ** the hit count and global hit counts for each column are found in
125 ** aPhraseinfo[iCol*3] and aPhraseinfo[iCol*3+1], respectively.131 ** aPhraseinfo[iCol*3] and aPhraseinfo[iCol*3+1], respectively.
126 */132 */
127 const int32_t *aPhraseinfo = &aMatchinfo[2 + iPhrase*nCol*3];133 const int32_t *aPhraseinfo = &aMatchinfo[2 + iPhrase*nCol*3];
@@ -287,6 +293,13 @@
287 execute_sql(db, deleteCmd);293 execute_sql(db, deleteCmd);
288}294}
289295
296void activateWalMode(sqlite3 *db) {
297 string activateWalCmd(R"(
298PRAGMA journal_mode = WAL;
299)");
300 execute_sql(db, activateWalCmd);
301}
302
290void createTables(sqlite3 *db) {303void createTables(sqlite3 *db) {
291 string schema(R"(304 string schema(R"(
292CREATE TABLE schemaVersion (version INTEGER);305CREATE TABLE schemaVersion (version INTEGER);
@@ -338,7 +351,7 @@
338 type INTEGER -- 0=Audio, 1=Video351 type INTEGER -- 0=Audio, 1=Video
339);352);
340353
341CREATE VIRTUAL TABLE media_fts 354CREATE VIRTUAL TABLE media_fts
342USING fts4(content='media', title, artist, album, tokenize=mozporter);355USING fts4(content='media', title, artist, album, tokenize=mozporter);
343356
344CREATE TRIGGER media_bu BEFORE UPDATE ON media BEGIN357CREATE TRIGGER media_bu BEFORE UPDATE ON media BEGIN
@@ -394,43 +407,51 @@
394407
395MediaStore::MediaStore(const std::string &filename, OpenType access, const std::string &retireprefix) {408MediaStore::MediaStore(const std::string &filename, OpenType access, const std::string &retireprefix) {
396 int sqliteFlags = access == MS_READ_WRITE ? SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE : SQLITE_OPEN_READONLY;409 int sqliteFlags = access == MS_READ_WRITE ? SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE : SQLITE_OPEN_READONLY;
397 p = new MediaStorePrivate();410 p = new MediaStorePrivate(access);
411 if(access != MS_READ_WRITE) {
412 return;
413 }
398 if(sqlite3_open_v2(filename.c_str(), &p->db, sqliteFlags, nullptr) != SQLITE_OK) {414 if(sqlite3_open_v2(filename.c_str(), &p->db, sqliteFlags, nullptr) != SQLITE_OK) {
399 throw runtime_error(sqlite3_errmsg(p->db));415 throw runtime_error(sqlite3_errmsg(p->db));
400 }416 }
401 register_tokenizer(p->db);417 register_tokenizer(p->db);
402 register_functions(p->db);418 register_functions(p->db);
403 int detectedSchemaVersion = getSchemaVersion(p->db);419 int detectedSchemaVersion = getSchemaVersion(p->db);
404 if(access == MS_READ_WRITE) {420 activateWalMode(p->db);
405 if(detectedSchemaVersion != schemaVersion) {421 if(detectedSchemaVersion != schemaVersion) {
406 deleteTables(p->db);422 deleteTables(p->db);
407 createTables(p->db);423 createTables(p->db);
408 }
409 if(!retireprefix.empty())
410 archiveItems(retireprefix);
411 } else {
412 if(detectedSchemaVersion != schemaVersion) {
413 std::string msg("Tried to open a db with schema version ");
414 msg += std::to_string(detectedSchemaVersion);
415 msg += ", while supported version is ";
416 msg += std::to_string(schemaVersion) + ".";
417 throw runtime_error(msg);
418 }
419 }424 }
425 if(!retireprefix.empty())
426 archiveItems(retireprefix);
420}427}
421428
422MediaStore::~MediaStore() {429MediaStore::~MediaStore() {
423 sqlite3_close(p->db);430 if(p->db) {
431 sqlite3_close(p->db);
432 }
424 delete p;433 delete p;
425}434}
426435
436MediaStorePrivate::MediaStorePrivate(OpenType access) : db(nullptr), access_mode(access), media_store_dbus(nullptr) {
437 if(access_mode != MS_READ_WRITE) {
438 media_store_dbus.reset(new dbus::ServiceStub());
439 }
440}
441
427size_t MediaStorePrivate::size() const {442size_t MediaStorePrivate::size() const {
443 if(access_mode != MS_READ_WRITE) {
444 throw runtime_error("MediaStorePrivate::size() is not available in read only mode");
445 }
428 Statement count(db, "SELECT COUNT(*) FROM media");446 Statement count(db, "SELECT COUNT(*) FROM media");
429 count.step();447 count.step();
430 return count.getInt(0);448 return count.getInt(0);
431}449}
432450
433void MediaStorePrivate::insert(const MediaFile &m) const {451void MediaStorePrivate::insert(const MediaFile &m) const {
452 if(access_mode != MS_READ_WRITE) {
453 throw runtime_error("MediaStorePrivate::insert() is not available in read only mode");
454 }
434 Statement query(db, "INSERT OR REPLACE INTO media (filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, width, height, latitude, longitude, has_thumbnail, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");455 Statement query(db, "INSERT OR REPLACE INTO media (filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, width, height, latitude, longitude, has_thumbnail, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
435 query.bind(1, m.getFileName());456 query.bind(1, m.getFileName());
436 query.bind(2, m.getContentType());457 query.bind(2, m.getContentType());
@@ -466,12 +487,18 @@
466}487}
467488
468void MediaStorePrivate::remove(const string &fname) const {489void MediaStorePrivate::remove(const string &fname) const {
490 if(access_mode != MS_READ_WRITE) {
491 throw runtime_error("MediaStorePrivate::remove() is not available in read only mode");
492 }
469 Statement del(db, "DELETE FROM media WHERE filename = ?");493 Statement del(db, "DELETE FROM media WHERE filename = ?");
470 del.bind(1, fname);494 del.bind(1, fname);
471 del.step();495 del.step();
472}496}
473497
474void MediaStorePrivate::insert_broken_file(const std::string &fname, const std::string &etag) const {498void MediaStorePrivate::insert_broken_file(const std::string &fname, const std::string &etag) const {
499 if(access_mode != MS_READ_WRITE) {
500 throw runtime_error("MediaStorePrivate::insert_broken_file() is not available in read only mode");
501 }
475 Statement del(db, "INSERT OR REPLACE INTO broken_files (filename, etag) VALUES (?, ?)");502 Statement del(db, "INSERT OR REPLACE INTO broken_files (filename, etag) VALUES (?, ?)");
476 del.bind(1, fname);503 del.bind(1, fname);
477 del.bind(2, etag);504 del.bind(2, etag);
@@ -479,12 +506,18 @@
479}506}
480507
481void MediaStorePrivate::remove_broken_file(const std::string &fname) const {508void MediaStorePrivate::remove_broken_file(const std::string &fname) const {
509 if(access_mode != MS_READ_WRITE) {
510 throw runtime_error("MediaStorePrivate::remove_broken_file() is not available in read only mode");
511 }
482 Statement del(db, "DELETE FROM broken_files WHERE filename = ?");512 Statement del(db, "DELETE FROM broken_files WHERE filename = ?");
483 del.bind(1, fname);513 del.bind(1, fname);
484 del.step();514 del.step();
485}515}
486516
487bool MediaStorePrivate::is_broken_file(const std::string &fname, const std::string &etag) const {517bool MediaStorePrivate::is_broken_file(const std::string &fname, const std::string &etag) const {
518 if(access_mode != MS_READ_WRITE) {
519 throw runtime_error("MediaStorePrivate::is_broken_file() is not available in read only mode");
520 }
488 Statement query(db, "SELECT * FROM broken_files WHERE filename = ? AND etag = ?");521 Statement query(db, "SELECT * FROM broken_files WHERE filename = ? AND etag = ?");
489 query.bind(1, fname);522 query.bind(1, fname);
490 query.bind(2, etag);523 query.bind(2, etag);
@@ -521,6 +554,9 @@
521}554}
522555
523MediaFile MediaStorePrivate::lookup(const std::string &filename) const {556MediaFile MediaStorePrivate::lookup(const std::string &filename) const {
557 if(access_mode != MS_READ_WRITE) {
558 return media_store_dbus->lookup(filename);
559 }
524 Statement query(db, R"(560 Statement query(db, R"(
525SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, width, height, latitude, longitude, has_thumbnail, type561SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, width, height, latitude, longitude, has_thumbnail, type
526 FROM media562 FROM media
@@ -534,6 +570,9 @@
534}570}
535571
536vector<MediaFile> MediaStorePrivate::query(const std::string &core_term, MediaType type, const Filter &filter) const {572vector<MediaFile> MediaStorePrivate::query(const std::string &core_term, MediaType type, const Filter &filter) const {
573 if(access_mode != MS_READ_WRITE) {
574 return media_store_dbus->query(core_term, type, filter);
575 }
537 string qs(R"(576 string qs(R"(
538SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, width, height, latitude, longitude, has_thumbnail, type577SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, width, height, latitude, longitude, has_thumbnail, type
539 FROM media578 FROM media
@@ -603,6 +642,9 @@
603}642}
604643
605vector<Album> MediaStorePrivate::queryAlbums(const std::string &core_term, const Filter &filter) const {644vector<Album> MediaStorePrivate::queryAlbums(const std::string &core_term, const Filter &filter) const {
645 if(access_mode != MS_READ_WRITE) {
646 return media_store_dbus->queryAlbums(core_term, filter);
647 }
606 string qs(R"(648 string qs(R"(
607SELECT album, album_artist, first(date) as date, first(genre) as genre, first(filename) as filename, first(has_thumbnail) as has_thumbnail FROM media649SELECT album, album_artist, first(date) as date, first(genre) as genre, first(filename) as filename, first(has_thumbnail) as has_thumbnail FROM media
608WHERE type = ? AND album <> ''650WHERE type = ? AND album <> ''
@@ -638,6 +680,9 @@
638}680}
639681
640vector<string> MediaStorePrivate::queryArtists(const string &q, const Filter &filter) const {682vector<string> MediaStorePrivate::queryArtists(const string &q, const Filter &filter) const {
683 if(access_mode != MS_READ_WRITE) {
684 return media_store_dbus->queryArtists(q, filter);
685 }
641 string qs(R"(686 string qs(R"(
642SELECT artist FROM media687SELECT artist FROM media
643WHERE type = ? AND artist <> ''688WHERE type = ? AND artist <> ''
@@ -677,6 +722,9 @@
677}722}
678723
679vector<MediaFile> MediaStorePrivate::getAlbumSongs(const Album& album) const {724vector<MediaFile> MediaStorePrivate::getAlbumSongs(const Album& album) const {
725 if(access_mode != MS_READ_WRITE) {
726 return media_store_dbus->getAlbumSongs(album);
727 }
680 Statement query(db, R"(728 Statement query(db, R"(
681SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, width, height, latitude, longitude, type FROM media729SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, width, height, latitude, longitude, type FROM media
682WHERE album = ? AND album_artist = ? AND type = ?730WHERE album = ? AND album_artist = ? AND type = ?
@@ -689,6 +737,9 @@
689}737}
690738
691std::string MediaStorePrivate::getETag(const std::string &filename) const {739std::string MediaStorePrivate::getETag(const std::string &filename) const {
740 if(access_mode != MS_READ_WRITE) {
741 return media_store_dbus->getETag(filename);
742 }
692 Statement query(db, R"(743 Statement query(db, R"(
693SELECT etag FROM media WHERE filename = ?744SELECT etag FROM media WHERE filename = ?
694)");745)");
@@ -701,6 +752,9 @@
701}752}
702753
703std::vector<MediaFile> MediaStorePrivate::listSongs(const Filter &filter) const {754std::vector<MediaFile> MediaStorePrivate::listSongs(const Filter &filter) const {
755 if(access_mode != MS_READ_WRITE) {
756 return media_store_dbus->listSongs(filter);
757 }
704 std::string qs(R"(758 std::string qs(R"(
705SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, width, height, latitude, longitude, has_thumbnail, type759SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, width, height, latitude, longitude, has_thumbnail, type
706 FROM media760 FROM media
@@ -744,6 +798,9 @@
744}798}
745799
746std::vector<Album> MediaStorePrivate::listAlbums(const Filter &filter) const {800std::vector<Album> MediaStorePrivate::listAlbums(const Filter &filter) const {
801 if(access_mode != MS_READ_WRITE) {
802 return media_store_dbus->listAlbums(filter);
803 }
747 std::string qs(R"(804 std::string qs(R"(
748SELECT album, album_artist, first(date) as date, first(genre) as genre, first(filename) as filename, first(has_thumbnail) as has_thumbnail FROM media805SELECT album, album_artist, first(date) as date, first(genre) as genre, first(filename) as filename, first(has_thumbnail) as has_thumbnail FROM media
749 WHERE type = ?806 WHERE type = ?
@@ -781,6 +838,9 @@
781}838}
782839
783vector<std::string> MediaStorePrivate::listArtists(const Filter &filter) const {840vector<std::string> MediaStorePrivate::listArtists(const Filter &filter) const {
841 if(access_mode != MS_READ_WRITE) {
842 return media_store_dbus->listArtists(filter);
843 }
784 string qs(R"(844 string qs(R"(
785SELECT artist FROM media845SELECT artist FROM media
786 WHERE type = ?846 WHERE type = ?
@@ -810,6 +870,9 @@
810}870}
811871
812vector<std::string> MediaStorePrivate::listAlbumArtists(const Filter &filter) const {872vector<std::string> MediaStorePrivate::listAlbumArtists(const Filter &filter) const {
873 if(access_mode != MS_READ_WRITE) {
874 return media_store_dbus->listAlbumArtists(filter);
875 }
813 string qs(R"(876 string qs(R"(
814SELECT album_artist FROM media877SELECT album_artist FROM media
815 WHERE type = ?878 WHERE type = ?
@@ -839,6 +902,9 @@
839}902}
840903
841vector<std::string> MediaStorePrivate::listGenres(const Filter &filter) const {904vector<std::string> MediaStorePrivate::listGenres(const Filter &filter) const {
905 if(access_mode != MS_READ_WRITE) {
906 return media_store_dbus->listGenres(filter);
907 }
842 Statement query(db, R"(908 Statement query(db, R"(
843SELECT genre FROM media909SELECT genre FROM media
844 WHERE type = ?910 WHERE type = ?
@@ -858,6 +924,9 @@
858}924}
859925
860void MediaStorePrivate::pruneDeleted() {926void MediaStorePrivate::pruneDeleted() {
927 if(access_mode != MS_READ_WRITE) {
928 throw runtime_error("MediaStorePrivate::pruneDeleted() is not available in read only mode");
929 }
861 std::map<std::string, bool> path_cache;930 std::map<std::string, bool> path_cache;
862 vector<string> deleted;931 vector<string> deleted;
863 Statement query(db, "SELECT filename FROM media");932 Statement query(db, "SELECT filename FROM media");
@@ -877,6 +946,9 @@
877}946}
878947
879void MediaStorePrivate::archiveItems(const std::string &prefix) {948void MediaStorePrivate::archiveItems(const std::string &prefix) {
949 if(access_mode != MS_READ_WRITE) {
950 throw runtime_error("MediaStorePrivate::archiveItems() is not available in read only mode");
951 }
880 const char *templ = R"(BEGIN TRANSACTION;952 const char *templ = R"(BEGIN TRANSACTION;
881INSERT INTO media_attic SELECT * FROM media WHERE filename LIKE %s;953INSERT INTO media_attic SELECT * FROM media WHERE filename LIKE %s;
882DELETE FROM media WHERE filename LIKE %s;954DELETE FROM media WHERE filename LIKE %s;
@@ -894,6 +966,9 @@
894}966}
895967
896void MediaStorePrivate::restoreItems(const std::string &prefix) {968void MediaStorePrivate::restoreItems(const std::string &prefix) {
969 if(access_mode != MS_READ_WRITE) {
970 throw runtime_error("MediaStorePrivate::restoreItems() is not available in read only mode");
971 }
897 const char *templ = R"(BEGIN TRANSACTION;972 const char *templ = R"(BEGIN TRANSACTION;
898INSERT INTO media SELECT * FROM media_attic WHERE filename LIKE %s;973INSERT INTO media SELECT * FROM media_attic WHERE filename LIKE %s;
899DELETE FROM media_attic WHERE filename LIKE %s;974DELETE FROM media_attic WHERE filename LIKE %s;
900975
=== modified file 'src/mediascanner/MediaStore.hh'
--- src/mediascanner/MediaStore.hh 2014-08-25 12:51:22 +0000
+++ src/mediascanner/MediaStore.hh 2015-02-16 14:24:40 +0000
@@ -23,6 +23,13 @@
23#include "MediaStoreBase.hh"23#include "MediaStoreBase.hh"
24#include<vector>24#include<vector>
25#include<string>25#include<string>
26#include<memory>
27
28namespace core {
29namespace dbus {
30class Bus;
31}
32}
2633
27namespace mediascanner {34namespace mediascanner {
2835
@@ -34,7 +41,8 @@
34class MediaStore final : public virtual MediaStoreBase {41class MediaStore final : public virtual MediaStoreBase {
35private:42private:
36 MediaStorePrivate *p;43 MediaStorePrivate *p;
3744// MediaStore(std::shared_ptr<core::dbus::Bus> testing_dbus){};
45// friend class MediaStoreTest;
38public:46public:
39 MediaStore(OpenType access, const std::string &retireprefix="");47 MediaStore(OpenType access, const std::string &retireprefix="");
40 MediaStore(const std::string &filename, OpenType access, const std::string &retireprefix="");48 MediaStore(const std::string &filename, OpenType access, const std::string &retireprefix="");
4149
=== added directory 'src/mediascanner/d-bus'
=== renamed file 'src/ms-dbus/dbus-codec.cc' => 'src/mediascanner/d-bus/dbus-codec.cc'
=== renamed file 'src/ms-dbus/dbus-codec.hh' => 'src/mediascanner/d-bus/dbus-codec.hh'
=== renamed file 'src/ms-dbus/dbus-interface.hh' => 'src/mediascanner/d-bus/dbus-interface.hh'
=== renamed file 'src/ms-dbus/service-stub.cc' => 'src/mediascanner/d-bus/service-stub.cc'
--- src/ms-dbus/service-stub.cc 2014-08-21 03:55:40 +0000
+++ src/mediascanner/d-bus/service-stub.cc 2015-02-16 14:24:40 +0000
@@ -43,6 +43,12 @@
43 core::dbus::types::ObjectPath(core::dbus::traits::Service<MediaStoreService>::object_path()))}) {43 core::dbus::types::ObjectPath(core::dbus::traits::Service<MediaStoreService>::object_path()))}) {
44}44}
4545
46ServiceStub::ServiceStub()
47 : core::dbus::Stub<MediaStoreService>(std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session)),
48 p(new Private{access_service()->object_for_path(
49 core::dbus::types::ObjectPath(core::dbus::traits::Service<MediaStoreService>::object_path()))}) {
50}
51
46ServiceStub::~ServiceStub() {52ServiceStub::~ServiceStub() {
47}53}
4854
4955
=== renamed file 'src/ms-dbus/service-stub.hh' => 'src/mediascanner/d-bus/service-stub.hh'
--- src/ms-dbus/service-stub.hh 2014-08-21 03:55:40 +0000
+++ src/mediascanner/d-bus/service-stub.hh 2015-02-16 14:24:40 +0000
@@ -40,6 +40,7 @@
40class ServiceStub : public core::dbus::Stub<MediaStoreService>, public virtual MediaStoreBase {40class ServiceStub : public core::dbus::Stub<MediaStoreService>, public virtual MediaStoreBase {
41public:41public:
42 explicit ServiceStub(core::dbus::Bus::Ptr bus);42 explicit ServiceStub(core::dbus::Bus::Ptr bus);
43 explicit ServiceStub();
43 virtual ~ServiceStub();44 virtual ~ServiceStub();
4445
45 virtual MediaFile lookup(const std::string &filename) const override;46 virtual MediaFile lookup(const std::string &filename) const override;
4647
=== renamed file 'src/ms-dbus/service.hh' => 'src/mediascanner/d-bus/service.hh'
=== modified file 'src/mediascanner/mediascanner-2.0.map'
--- src/mediascanner/mediascanner-2.0.map 2014-06-24 11:10:39 +0000
+++ src/mediascanner/mediascanner-2.0.map 2015-02-16 14:24:40 +0000
@@ -11,11 +11,41 @@
11 mediascanner::MediaStoreBase::*;11 mediascanner::MediaStoreBase::*;
12 mediascanner::Filter::*;12 mediascanner::Filter::*;
1313
14 typeinfo?for?mediascanner::*;14 typeinfo?for?mediascanner::MediaFile*;
15 typeinfo?name?for?mediascanner::*;15 typeinfo?name?for?mediascanner::MediaFile*;
16 VTT?for?mediascanner::*;16 VTT?for?mediascanner::MediaFile*;
17 virtual?thunk?to?mediascanner::*;17 virtual?thunk?to?mediascanner::MediaFile*;
18 vtable?for?mediascanner::*;18 vtable?for?mediascanner::MediaFile*;
19
20 typeinfo?for?mediascanner::Album*;
21 typeinfo?name?for?mediascanner::Album*;
22 VTT?for?mediascanner::Album*;
23 virtual?thunk?to?mediascanner::Album*;
24 vtable?for?mediascanner::Album*;
25
26 typeinfo?for?mediascanner::MediaFileBuilder*;
27 typeinfo?name?for?mediascanner::MediaFileBuilder*;
28 VTT?for?mediascanner::MediaFileBuilder*;
29 virtual?thunk?to?mediascanner::MediaFileBuilder*;
30 vtable?for?mediascanner::MediaFileBuilder*;
31
32 typeinfo?for?mediascanner::MediaStore*;
33 typeinfo?name?for?mediascanner::MediaStore*;
34 VTT?for?mediascanner::MediaStore*;
35 virtual?thunk?to?mediascanner::MediaStore*;
36 vtable?for?mediascanner::MediaStore*;
37
38 typeinfo?for?mediascanner::MediaStoreBase*;
39 typeinfo?name?for?mediascanner::MediaStoreBase*;
40 VTT?for?mediascanner::MediaStoreBase*;
41 virtual?thunk?to?mediascanner::MediaStoreBase*;
42 vtable?for?mediascanner::MediaStoreBase*;
43
44 typeinfo?for?mediascanner::Filter*;
45 typeinfo?name?for?mediascanner::Filter*;
46 VTT?for?mediascanner::Filter*;
47 virtual?thunk?to?mediascanner::Filter*;
48 vtable?for?mediascanner::Filter*;
19 };49 };
2050
21local:51local:
2252
=== modified file 'src/ms-dbus/CMakeLists.txt'
--- src/ms-dbus/CMakeLists.txt 2014-05-29 07:29:58 +0000
+++ src/ms-dbus/CMakeLists.txt 2015-02-16 14:24:40 +0000
@@ -2,9 +2,7 @@
2add_definitions(${MEDIASCANNER_CFLAGS} ${DBUSCPP_CFLAGS} ${APPARMOR_CFLAGS})2add_definitions(${MEDIASCANNER_CFLAGS} ${DBUSCPP_CFLAGS} ${APPARMOR_CFLAGS})
33
4add_library(ms-dbus STATIC4add_library(ms-dbus STATIC
5 dbus-codec.cc
6 service-skeleton.cc5 service-skeleton.cc
7 service-stub.cc
8)6)
97
10target_link_libraries(ms-dbus8target_link_libraries(ms-dbus
@@ -16,6 +14,7 @@
1614
17add_executable(mediascanner-dbus15add_executable(mediascanner-dbus
18 main.cc16 main.cc
17 $<TARGET_OBJECTS:mediascanner-dbus-static>
19)18)
20target_link_libraries(mediascanner-dbus ms-dbus)19target_link_libraries(mediascanner-dbus ms-dbus)
21set_target_properties(mediascanner-dbus20set_target_properties(mediascanner-dbus
2221
=== modified file 'src/ms-dbus/main.cc'
--- src/ms-dbus/main.cc 2014-05-20 09:01:59 +0000
+++ src/ms-dbus/main.cc 2015-02-16 14:24:40 +0000
@@ -27,10 +27,10 @@
27using namespace mediascanner;27using namespace mediascanner;
2828
29int main(int , char **) {29int main(int , char **) {
30 auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);30 auto bus = std::make_shared<core::dbus::Bus>(getenv("DBUS_SESSION_BUS_ADDRESS"));
31 bus->install_executor(core::dbus::asio::make_executor(bus));31 bus->install_executor(core::dbus::asio::make_executor(bus));
3232
33 auto store = std::make_shared<MediaStore>(MS_READ_ONLY);33 auto store = std::make_shared<MediaStore>(MS_READ_WRITE);
3434
35 dbus::ServiceSkeleton service(bus, store);35 dbus::ServiceSkeleton service(bus, store);
36 service.run();36 service.run();
3737
=== modified file 'src/ms-dbus/service-skeleton.cc'
--- src/ms-dbus/service-skeleton.cc 2014-08-21 03:55:40 +0000
+++ src/ms-dbus/service-skeleton.cc 2015-02-16 14:24:40 +0000
@@ -12,8 +12,8 @@
12#include <mediascanner/MediaFile.hh>12#include <mediascanner/MediaFile.hh>
13#include <mediascanner/MediaStore.hh>13#include <mediascanner/MediaStore.hh>
1414
15#include "dbus-interface.hh"15#include <mediascanner/d-bus/dbus-interface.hh>
16#include "dbus-codec.hh"16#include <mediascanner/d-bus/dbus-codec.hh>
1717
18using core::dbus::Message;18using core::dbus::Message;
1919
2020
=== modified file 'src/ms-dbus/service-skeleton.hh'
--- src/ms-dbus/service-skeleton.hh 2014-05-22 09:26:44 +0000
+++ src/ms-dbus/service-skeleton.hh 2015-02-16 14:24:40 +0000
@@ -24,7 +24,7 @@
24#include <core/dbus/bus.h>24#include <core/dbus/bus.h>
25#include <core/dbus/skeleton.h>25#include <core/dbus/skeleton.h>
2626
27#include "service.hh"27#include "mediascanner/d-bus/service.hh"
2828
29namespace mediascanner {29namespace mediascanner {
3030
3131
=== modified file 'src/qml/Ubuntu/MediaScanner/MediaStoreWrapper.cc'
--- src/qml/Ubuntu/MediaScanner/MediaStoreWrapper.cc 2014-08-21 03:55:40 +0000
+++ src/qml/Ubuntu/MediaScanner/MediaStoreWrapper.cc 2015-02-16 14:24:40 +0000
@@ -28,7 +28,7 @@
28#include <core/dbus/asio/executor.h>28#include <core/dbus/asio/executor.h>
29#include <mediascanner/Filter.hh>29#include <mediascanner/Filter.hh>
30#include <mediascanner/MediaStore.hh>30#include <mediascanner/MediaStore.hh>
31#include <ms-dbus/service-stub.hh>31#include <mediascanner/d-bus/service-stub.hh>
3232
33using namespace mediascanner::qml;33using namespace mediascanner::qml;
3434
3535
=== modified file 'test/CMakeLists.txt'
--- test/CMakeLists.txt 2014-06-24 11:23:31 +0000
+++ test/CMakeLists.txt 2015-02-16 14:24:40 +0000
@@ -2,6 +2,9 @@
2 set(GTEST_ROOT /usr/src/gtest)2 set(GTEST_ROOT /usr/src/gtest)
3endif()3endif()
44
5set(SOURCE_BINARY_DIR "${CMAKE_BINARY_DIR}/src")
6add_definitions(-DMS_DBUS_BINARY="${SOURCE_BINARY_DIR}/ms-dbus/mediascanner-dbus-2.0")
7
5set(GTEST_SRC_DIR "${GTEST_ROOT}/src")8set(GTEST_SRC_DIR "${GTEST_ROOT}/src")
6set(GTEST_INCLUDE_DIR ${GTEST_ROOT})9set(GTEST_INCLUDE_DIR ${GTEST_ROOT})
710
@@ -9,6 +12,9 @@
9${GTEST_SRC_DIR}/gtest-all.cc12${GTEST_SRC_DIR}/gtest-all.cc
10)13)
1114
15pkg_check_modules(QTDBUSTEST REQUIRED libqtdbustest-1 REQUIRED)
16include_directories(${QTDBUSTEST_INCLUDE_DIRS})
17
12set_target_properties(gtest PROPERTIES INCLUDE_DIRECTORIES ${GTEST_INCLUDE_DIR})18set_target_properties(gtest PROPERTIES INCLUDE_DIRECTORIES ${GTEST_INCLUDE_DIR})
13target_link_libraries(gtest ${CMAKE_THREAD_LIBS_INIT})19target_link_libraries(gtest ${CMAKE_THREAD_LIBS_INIT})
1420
@@ -25,10 +31,14 @@
2531
26add_executable(basic basic.cc)32add_executable(basic basic.cc)
27target_link_libraries(basic mediascanner scannerstuff gtest)33target_link_libraries(basic mediascanner scannerstuff gtest)
28add_test(basic basic)34#add_test(basic basic)
2935
30add_executable(test_mediastore test_mediastore.cc ../src/mediascanner/utils.cc)36add_executable(test_mediastore
31target_link_libraries(test_mediastore mediascanner gtest)37 test_mediastore.cc
38 ../src/mediascanner/utils.cc
39 utils/DBusTest.cpp)
40qt5_use_modules(test_mediastore Core DBus)
41target_link_libraries(test_mediastore mediascanner gtest ${QTDBUSTEST_LDFLAGS})
32add_test(test_mediastore test_mediastore)42add_test(test_mediastore test_mediastore)
3343
34add_executable(test_metadataextractor test_metadataextractor.cc)44add_executable(test_metadataextractor test_metadataextractor.cc)
@@ -43,11 +53,11 @@
43target_link_libraries(test_mfbuilder gtest mediascanner)53target_link_libraries(test_mfbuilder gtest mediascanner)
44add_test(test_mfbuilder test_mfbuilder)54add_test(test_mfbuilder test_mfbuilder)
4555
46add_executable(test_dbus test_dbus.cc)56add_executable(test_dbus test_dbus.cc $<TARGET_OBJECTS:mediascanner-dbus-static>)
47target_link_libraries(test_dbus gtest mediascanner ms-dbus)57target_link_libraries(test_dbus gtest mediascanner ms-dbus)
48add_test(test_dbus test_dbus)58add_test(test_dbus test_dbus)
4959
50add_executable(test_qml test_qml.cc)60add_executable(test_qml test_qml.cc $<TARGET_OBJECTS:mediascanner-dbus-static>)
51qt5_use_modules(test_qml QuickTest)61qt5_use_modules(test_qml QuickTest)
52target_link_libraries(test_qml mediascanner ${DBUSCPP_LDFLAGS})62target_link_libraries(test_qml mediascanner ${DBUSCPP_LDFLAGS})
53add_test(test_qml test_qml -input ${CMAKE_CURRENT_SOURCE_DIR}/qml -import ${CMAKE_BINARY_DIR}/src/qml)63add_test(test_qml test_qml -input ${CMAKE_CURRENT_SOURCE_DIR}/qml -import ${CMAKE_BINARY_DIR}/src/qml)
5464
=== modified file 'test/test_dbus.cc'
--- test/test_dbus.cc 2014-09-03 07:00:02 +0000
+++ test/test_dbus.cc 2015-02-16 14:24:40 +0000
@@ -7,7 +7,7 @@
7#include <mediascanner/MediaFile.hh>7#include <mediascanner/MediaFile.hh>
8#include <mediascanner/MediaFileBuilder.hh>8#include <mediascanner/MediaFileBuilder.hh>
9#include <mediascanner/Filter.hh>9#include <mediascanner/Filter.hh>
10#include <ms-dbus/dbus-codec.hh>10#include <mediascanner/d-bus/dbus-codec.hh>
1111
12class MediaStoreDBusTests : public ::testing::Test {12class MediaStoreDBusTests : public ::testing::Test {
13protected:13protected:
1414
=== modified file 'test/test_mediastore.cc'
--- test/test_mediastore.cc 2014-09-02 10:43:05 +0000
+++ test/test_mediastore.cc 2015-02-16 14:24:40 +0000
@@ -29,33 +29,27 @@
29#include<string>29#include<string>
30#include <gtest/gtest.h>30#include <gtest/gtest.h>
3131
32#include <core/dbus/fixture.h>
33
34#include <QProcess>
35#include <QProcessEnvironment>
36#include <QCoreApplication>
37
38#include "test_config.h"
39#include "utils/DBusTest.h"
40
32using namespace std;41using namespace std;
33using namespace mediascanner;42using namespace mediascanner;
3443
35class MediaStoreTest : public ::testing::Test {44TEST(MediaStoreTest, init) {
36 protected:
37 MediaStoreTest() {
38 }
39
40 virtual ~MediaStoreTest() {
41 }
42
43 virtual void SetUp() {
44 }
45
46 virtual void TearDown() {
47 }
48};
49
50TEST_F(MediaStoreTest, init) {
51 MediaStore store(":memory:", MS_READ_WRITE);45 MediaStore store(":memory:", MS_READ_WRITE);
52}46}
53TEST_F(MediaStoreTest, mediafile_uri) {47TEST(MediaStoreTest, mediafile_uri) {
54 MediaFile media = MediaFileBuilder("/path/to/file.ogg");48 MediaFile media = MediaFileBuilder("/path/to/file.ogg");
55 EXPECT_EQ(media.getUri(), "file:///path/to/file.ogg");49 EXPECT_EQ(media.getUri(), "file:///path/to/file.ogg");
56}50}
5751
58TEST_F(MediaStoreTest, equality) {52TEST(MediaStoreTest, equality) {
59 MediaFile audio1 = MediaFileBuilder("a")53 MediaFile audio1 = MediaFileBuilder("a")
60 .setContentType("type")54 .setContentType("type")
61 .setETag("etag")55 .setETag("etag")
@@ -136,7 +130,7 @@
136 EXPECT_NE(video1, image1);130 EXPECT_NE(video1, image1);
137}131}
138132
139TEST_F(MediaStoreTest, lookup) {133TEST(MediaStoreTest, lookup) {
140 MediaFile audio = MediaFileBuilder("/aaa")134 MediaFile audio = MediaFileBuilder("/aaa")
141 .setContentType("type")135 .setContentType("type")
142 .setETag("etag")136 .setETag("etag")
@@ -155,9 +149,11 @@
155149
156 EXPECT_EQ(store.lookup("/aaa"), audio);150 EXPECT_EQ(store.lookup("/aaa"), audio);
157 EXPECT_THROW(store.lookup("not found"), std::runtime_error);151 EXPECT_THROW(store.lookup("not found"), std::runtime_error);
152
153 store.remove(audio.getFileName());
158}154}
159155
160TEST_F(MediaStoreTest, roundtrip) {156TEST(MediaStoreTest, roundtrip) {
161 MediaFile audio = MediaFileBuilder("/aaa")157 MediaFile audio = MediaFileBuilder("/aaa")
162 .setContentType("type")158 .setContentType("type")
163 .setETag("etag")159 .setETag("etag")
@@ -208,41 +204,75 @@
208 result = store.query("bbb", ImageMedia, filter);204 result = store.query("bbb", ImageMedia, filter);
209 ASSERT_EQ(1, result.size());205 ASSERT_EQ(1, result.size());
210 EXPECT_EQ(image, result[0]);206 EXPECT_EQ(image, result[0]);
207
208 store.remove(audio.getFileName());
209 store.remove(video.getFileName());
210 store.remove(image.getFileName());
211}211}
212212
213TEST_F(MediaStoreTest, query_by_album) {213void check_query_by_album(MediaStore const &store, MediaFile const &audio) {
214 MediaFile audio = MediaFileBuilder("/path/foo.ogg")
215 .setType(AudioMedia)
216 .setTitle("title")
217 .setAuthor("artist")
218 .setAlbum("album")
219 .setAlbumArtist("albumartist");
220 MediaStore store(":memory:", MS_READ_WRITE);
221 store.insert(audio);
222
223 Filter filter;214 Filter filter;
224 vector<MediaFile> result = store.query("album", AudioMedia, filter);215 vector<MediaFile> result = store.query("album", AudioMedia, filter);
225 ASSERT_EQ(result.size(), 1);216 ASSERT_EQ(result.size(), 1);
226 EXPECT_EQ(result[0], audio);217 EXPECT_EQ(result[0], audio);
227}218}
228219
229TEST_F(MediaStoreTest, query_by_artist) {220TEST(MediaStoreTest, query_by_album) {
230 MediaFile audio = MediaFileBuilder("/path/foo.ogg")221 MediaFile audio = MediaFileBuilder("/path/foo.ogg")
231 .setType(AudioMedia)222 .setType(AudioMedia)
232 .setTitle("title")223 .setTitle("title")
233 .setAuthor("artist")224 .setAuthor("artist")
234 .setAlbum("album")225 .setAlbum("album")
235 .setAlbumArtist("albumartist");226 .setAlbumArtist("albumartist");
236 MediaStore store(":memory:", MS_READ_WRITE);227 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
237 store.insert(audio);228 store.insert(audio);
238229
230 check_query_by_album(store, audio);
231
232 // test read only
233 MediaStore store2(TEST_DIR "/mediastore.db", MS_READ_ONLY);
234 check_query_by_album(store2, audio);
235
236 store.remove(audio.getFileName());
237
238}
239
240void check_query_by_artist(MediaStore const &store, MediaFile const &audio) {
239 Filter filter;241 Filter filter;
240 vector<MediaFile> result = store.query("artist", AudioMedia, filter);242 vector<MediaFile> result = store.query("artist", AudioMedia, filter);
241 ASSERT_EQ(result.size(), 1);243 ASSERT_EQ(result.size(), 1);
242 EXPECT_EQ(result[0], audio);244 EXPECT_EQ(result[0], audio);
243 }245}
244246
245TEST_F(MediaStoreTest, query_ranking) {247TEST(MediaStoreTest, query_by_artist) {
248 MediaFile audio = MediaFileBuilder("/path/foo.ogg")
249 .setType(AudioMedia)
250 .setTitle("title")
251 .setAuthor("artist")
252 .setAlbum("album")
253 .setAlbumArtist("albumartist");
254 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
255 store.insert(audio);
256
257 check_query_by_artist(store, audio);
258
259 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
260 check_query_by_artist(store_ro, audio);
261
262 store.remove(audio.getFileName());
263}
264
265void check_query_ranking(MediaStore const &store, std::vector<MediaFile> const &files) {
266 Filter filter;
267 vector<MediaFile> result = store.query("aaa", AudioMedia, filter);
268 ASSERT_EQ(result.size(), 4);
269 EXPECT_EQ(result[0], files[4]); // Term appears in title, artist and album
270 EXPECT_EQ(result[1], files[1]); // title has highest weighting
271 EXPECT_EQ(result[2], files[3]); // then album
272 EXPECT_EQ(result[3], files[2]); // then artist
273}
274
275TEST(MediaStoreTest, query_ranking) {
246 MediaFile audio1 = MediaFileBuilder("/path/foo1.ogg")276 MediaFile audio1 = MediaFileBuilder("/path/foo1.ogg")
247 .setType(AudioMedia)277 .setType(AudioMedia)
248 .setTitle("title")278 .setTitle("title")
@@ -274,47 +304,38 @@
274 .setAlbum("album aaa")304 .setAlbum("album aaa")
275 .setAlbumArtist("albumartist");305 .setAlbumArtist("albumartist");
276306
277 MediaStore store(":memory:", MS_READ_WRITE);307 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
308
309 std::vector<MediaFile> files;
278 store.insert(audio1);310 store.insert(audio1);
311 files.push_back(audio1);
312
279 store.insert(audio2);313 store.insert(audio2);
314 files.push_back(audio2);
315
280 store.insert(audio3);316 store.insert(audio3);
317 files.push_back(audio3);
318
281 store.insert(audio4);319 store.insert(audio4);
320 files.push_back(audio4);
321
282 store.insert(audio5);322 store.insert(audio5);
283323 files.push_back(audio5);
284 Filter filter;324
285 vector<MediaFile> result = store.query("aaa", AudioMedia, filter);325 check_query_ranking(store, files);
286 ASSERT_EQ(result.size(), 4);326
287 EXPECT_EQ(result[0], audio5); // Term appears in title, artist and album327 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
288 EXPECT_EQ(result[1], audio2); // title has highest weighting328 check_query_ranking(store_ro, files);
289 EXPECT_EQ(result[2], audio4); // then album329
290 EXPECT_EQ(result[3], audio3); // then artist330 for(auto item: files) {
331 store.remove(item.getFileName());
332 }
291}333}
292334
293TEST_F(MediaStoreTest, query_limit) {335void check_query_limit(MediaStore const &store,
294 MediaFile audio1 = MediaFileBuilder("/path/foo5.ogg")336 MediaFile const &audio1,
295 .setType(AudioMedia)337 MediaFile const &audio2,
296 .setTitle("title aaa")338 MediaFile const &) {
297 .setAuthor("artist aaa")
298 .setAlbum("album aaa")
299 .setAlbumArtist("albumartist");
300 MediaFile audio2 = MediaFileBuilder("/path/foo2.ogg")
301 .setType(AudioMedia)
302 .setTitle("title aaa")
303 .setAuthor("artist")
304 .setAlbum("album")
305 .setAlbumArtist("albumartist");
306 MediaFile audio3 = MediaFileBuilder("/path/foo4.ogg")
307 .setType(AudioMedia)
308 .setTitle("title")
309 .setAuthor("artist")
310 .setAlbum("album aaa")
311 .setAlbumArtist("albumartist");
312
313 MediaStore store(":memory:", MS_READ_WRITE);
314 store.insert(audio1);
315 store.insert(audio2);
316 store.insert(audio3);
317
318 Filter filter;339 Filter filter;
319 filter.setLimit(2);340 filter.setLimit(2);
320 vector<MediaFile> result = store.query("aaa", AudioMedia, filter);341 vector<MediaFile> result = store.query("aaa", AudioMedia, filter);
@@ -323,24 +344,42 @@
323 EXPECT_EQ(result[1], audio2); // title has highest weighting344 EXPECT_EQ(result[1], audio2); // title has highest weighting
324}345}
325346
326TEST_F(MediaStoreTest, query_short) {347TEST(MediaStoreTest, query_limit) {
327 MediaFile audio1 = MediaFileBuilder("/path/foo5.ogg")348 MediaFile audio1 = MediaFileBuilder("/path/foo5.ogg")
328 .setType(AudioMedia)349 .setType(AudioMedia)
329 .setTitle("title xyz")350 .setTitle("title aaa")
330 .setAuthor("artist")351 .setAuthor("artist aaa")
331 .setAlbum("album")352 .setAlbum("album aaa")
332 .setAlbumArtist("albumartist");353 .setAlbumArtist("albumartist");
333 MediaFile audio2 = MediaFileBuilder("/path/foo2.ogg")354 MediaFile audio2 = MediaFileBuilder("/path/foo2.ogg")
334 .setType(AudioMedia)355 .setType(AudioMedia)
335 .setTitle("title xzy")356 .setTitle("title aaa")
336 .setAuthor("artist")357 .setAuthor("artist")
337 .setAlbum("album")358 .setAlbum("album")
338 .setAlbumArtist("albumartist");359 .setAlbumArtist("albumartist");
360 MediaFile audio3 = MediaFileBuilder("/path/foo4.ogg")
361 .setType(AudioMedia)
362 .setTitle("title")
363 .setAuthor("artist")
364 .setAlbum("album aaa")
365 .setAlbumArtist("albumartist");
339366
340 MediaStore store(":memory:", MS_READ_WRITE);367 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
341 store.insert(audio1);368 store.insert(audio1);
342 store.insert(audio2);369 store.insert(audio2);
343370 store.insert(audio3);
371
372 check_query_limit(store, audio1, audio2, audio3);
373
374 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
375 check_query_limit(store_ro, audio1, audio2, audio3);
376
377 store.remove(audio1.getFileName());
378 store.remove(audio2.getFileName());
379 store.remove(audio3.getFileName());
380}
381
382void check_query_short(MediaStore const &store, MediaFile const &, MediaFile const &) {
344 Filter filter;383 Filter filter;
345 vector<MediaFile> result = store.query("x", AudioMedia, filter);384 vector<MediaFile> result = store.query("x", AudioMedia, filter);
346 EXPECT_EQ(result.size(), 2);385 EXPECT_EQ(result.size(), 2);
@@ -348,31 +387,34 @@
348 EXPECT_EQ(result.size(), 1);387 EXPECT_EQ(result.size(), 1);
349}388}
350389
351TEST_F(MediaStoreTest, query_empty) {390TEST(MediaStoreTest, query_short) {
352 MediaFile audio1 = MediaFileBuilder("/path/foo5.ogg")391 MediaFile audio1 = MediaFileBuilder("/path/foo5.ogg")
353 .setType(AudioMedia)392 .setType(AudioMedia)
354 .setTitle("title aaa")393 .setTitle("title xyz")
355 .setAuthor("artist aaa")394 .setAuthor("artist")
356 .setAlbum("album aaa")395 .setAlbum("album")
357 .setAlbumArtist("albumartist");396 .setAlbumArtist("albumartist");
358 MediaFile audio2 = MediaFileBuilder("/path/foo2.ogg")397 MediaFile audio2 = MediaFileBuilder("/path/foo2.ogg")
359 .setType(AudioMedia)398 .setType(AudioMedia)
360 .setTitle("title aaa")399 .setTitle("title xzy")
361 .setAuthor("artist")400 .setAuthor("artist")
362 .setAlbum("album")401 .setAlbum("album")
363 .setAlbumArtist("albumartist");402 .setAlbumArtist("albumartist");
364 MediaFile audio3 = MediaFileBuilder("/path/foo4.ogg")
365 .setType(AudioMedia)
366 .setTitle("title")
367 .setAuthor("artist")
368 .setAlbum("album aaa")
369 .setAlbumArtist("albumartist");
370403
371 MediaStore store(":memory:", MS_READ_WRITE);404 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
372 store.insert(audio1);405 store.insert(audio1);
373 store.insert(audio2);406 store.insert(audio2);
374 store.insert(audio3);407
375408 check_query_short(store, audio1, audio2);
409
410 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
411 check_query_short(store_ro, audio1, audio2);
412
413 store.remove(audio1.getFileName());
414 store.remove(audio2.getFileName());
415}
416
417void check_query_empty(MediaStore const &store) {
376 // An empty query should return some results418 // An empty query should return some results
377 Filter filter;419 Filter filter;
378 filter.setLimit(2);420 filter.setLimit(2);
@@ -380,91 +422,140 @@
380 ASSERT_EQ(result.size(), 2);422 ASSERT_EQ(result.size(), 2);
381}423}
382424
383TEST_F(MediaStoreTest, query_order) {425TEST(MediaStoreTest, query_empty) {
384 MediaFile audio1 = MediaFileBuilder("/path/foo1.ogg")426 MediaFile audio1 = MediaFileBuilder("/path/foo5.ogg")
385 .setType(AudioMedia)427 .setType(AudioMedia)
386 .setTitle("foo")428 .setTitle("title aaa")
387 .setDate("2010-01-01")429 .setAuthor("artist aaa")
388 .setAuthor("artist")430 .setAlbum("album aaa")
389 .setAlbum("album");431 .setAlbumArtist("albumartist");
390 MediaFile audio2 = MediaFileBuilder("/path/foo2.ogg")432 MediaFile audio2 = MediaFileBuilder("/path/foo2.ogg")
391 .setType(AudioMedia)433 .setType(AudioMedia)
392 .setTitle("foo foo")434 .setTitle("title aaa")
393 .setDate("2010-01-03")
394 .setAuthor("artist")435 .setAuthor("artist")
395 .setAlbum("album");436 .setAlbum("album")
396 MediaFile audio3 = MediaFileBuilder("/path/foo3.ogg")437 .setAlbumArtist("albumartist");
438 MediaFile audio3 = MediaFileBuilder("/path/foo4.ogg")
397 .setType(AudioMedia)439 .setType(AudioMedia)
398 .setTitle("foo foo foo")440 .setTitle("title")
399 .setDate("2010-01-02")
400 .setAuthor("artist")441 .setAuthor("artist")
401 .setAlbum("album");442 .setAlbum("album aaa")
443 .setAlbumArtist("albumartist");
402444
403 MediaStore store(":memory:", MS_READ_WRITE);445 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
404 store.insert(audio1);446 store.insert(audio1);
405 store.insert(audio2);447 store.insert(audio2);
406 store.insert(audio3);448 store.insert(audio3);
407449
450 check_query_empty(store);
451
452 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
453 check_query_empty(store_ro);
454
455 store.remove(audio1.getFileName());
456 store.remove(audio2.getFileName());
457 store.remove(audio3.getFileName());
458}
459
460void check_query_order(MediaStore const &store,
461 std::string const &name1,
462 std::string const &name2,
463 std::string const &name3) {
408 Filter filter;464 Filter filter;
409 // Default sort order is by rank465 // Default sort order is by rank
410 vector<MediaFile> result = store.query("foo", AudioMedia, filter);466 vector<MediaFile> result = store.query("foo", AudioMedia, filter);
411 ASSERT_EQ(3, result.size());467 ASSERT_EQ(3, result.size());
412 EXPECT_EQ("/path/foo3.ogg", result[0].getFileName());468 EXPECT_EQ(name3, result[0].getFileName());
413 EXPECT_EQ("/path/foo2.ogg", result[1].getFileName());469 EXPECT_EQ(name2, result[1].getFileName());
414 EXPECT_EQ("/path/foo1.ogg", result[2].getFileName());470 EXPECT_EQ(name1, result[2].getFileName());
415471
416 // Sorting by rank (same as default)472 // Sorting by rank (same as default)
417 filter.setOrder(MediaOrder::Rank);473 filter.setOrder(MediaOrder::Rank);
418 result = store.query("foo", AudioMedia, filter);474 result = store.query("foo", AudioMedia, filter);
419 ASSERT_EQ(3, result.size());475 ASSERT_EQ(3, result.size());
420 EXPECT_EQ("/path/foo3.ogg", result[0].getFileName());476 EXPECT_EQ(name3, result[0].getFileName());
421 EXPECT_EQ("/path/foo2.ogg", result[1].getFileName());477 EXPECT_EQ(name2, result[1].getFileName());
422 EXPECT_EQ("/path/foo1.ogg", result[2].getFileName());478 EXPECT_EQ(name1, result[2].getFileName());
423479
424 // Sorting by rank, reversed480 // Sorting by rank, reversed
425 filter.setReverse(true);481 filter.setReverse(true);
426 result = store.query("foo", AudioMedia, filter);482 result = store.query("foo", AudioMedia, filter);
427 ASSERT_EQ(3, result.size());483 ASSERT_EQ(3, result.size());
428 EXPECT_EQ("/path/foo1.ogg", result[0].getFileName());484 EXPECT_EQ(name1, result[0].getFileName());
429 EXPECT_EQ("/path/foo2.ogg", result[1].getFileName());485 EXPECT_EQ(name2, result[1].getFileName());
430 EXPECT_EQ("/path/foo3.ogg", result[2].getFileName());486 EXPECT_EQ(name3, result[2].getFileName());
431487
432 // Sorting by title488 // Sorting by title
433 filter.setReverse(false);489 filter.setReverse(false);
434 filter.setOrder(MediaOrder::Title);490 filter.setOrder(MediaOrder::Title);
435 result = store.query("foo", AudioMedia, filter);491 result = store.query("foo", AudioMedia, filter);
436 ASSERT_EQ(3, result.size());492 ASSERT_EQ(3, result.size());
437 EXPECT_EQ("/path/foo1.ogg", result[0].getFileName());493 EXPECT_EQ(name1, result[0].getFileName());
438 EXPECT_EQ("/path/foo2.ogg", result[1].getFileName());494 EXPECT_EQ(name2, result[1].getFileName());
439 EXPECT_EQ("/path/foo3.ogg", result[2].getFileName());495 EXPECT_EQ(name3, result[2].getFileName());
440496
441 // Sorting by title, reversed497 // Sorting by title, reversed
442 filter.setReverse(true);498 filter.setReverse(true);
443 result = store.query("foo", AudioMedia, filter);499 result = store.query("foo", AudioMedia, filter);
444 ASSERT_EQ(3, result.size());500 ASSERT_EQ(3, result.size());
445 EXPECT_EQ("/path/foo3.ogg", result[0].getFileName());501 EXPECT_EQ(name3, result[0].getFileName());
446 EXPECT_EQ("/path/foo2.ogg", result[1].getFileName());502 EXPECT_EQ(name2, result[1].getFileName());
447 EXPECT_EQ("/path/foo1.ogg", result[2].getFileName());503 EXPECT_EQ(name1, result[2].getFileName());
448504
449 // Sorting by date505 // Sorting by date
450 filter.setReverse(false);506 filter.setReverse(false);
451 filter.setOrder(MediaOrder::Date);507 filter.setOrder(MediaOrder::Date);
452 result = store.query("foo", AudioMedia, filter);508 result = store.query("foo", AudioMedia, filter);
453 ASSERT_EQ(3, result.size());509 ASSERT_EQ(3, result.size());
454 EXPECT_EQ("/path/foo1.ogg", result[0].getFileName());510 EXPECT_EQ(name1, result[0].getFileName());
455 EXPECT_EQ("/path/foo3.ogg", result[1].getFileName());511 EXPECT_EQ(name3, result[1].getFileName());
456 EXPECT_EQ("/path/foo2.ogg", result[2].getFileName());512 EXPECT_EQ(name2, result[2].getFileName());
457513
458 // Sorting by date, reversed514 // Sorting by date, reversed
459 filter.setReverse(true);515 filter.setReverse(true);
460 result = store.query("foo", AudioMedia, filter);516 result = store.query("foo", AudioMedia, filter);
461 ASSERT_EQ(3, result.size());517 ASSERT_EQ(3, result.size());
462 EXPECT_EQ("/path/foo2.ogg", result[0].getFileName());518 EXPECT_EQ(name2, result[0].getFileName());
463 EXPECT_EQ("/path/foo3.ogg", result[1].getFileName());519 EXPECT_EQ(name3, result[1].getFileName());
464 EXPECT_EQ("/path/foo1.ogg", result[2].getFileName());520 EXPECT_EQ(name1, result[2].getFileName());
465}521}
466522
467TEST_F(MediaStoreTest, unmount) {523TEST(MediaStoreTest, query_order) {
524 MediaFile audio1 = MediaFileBuilder("/path/foo1.ogg")
525 .setType(AudioMedia)
526 .setTitle("foo")
527 .setDate("2010-01-01")
528 .setAuthor("artist")
529 .setAlbum("album");
530 MediaFile audio2 = MediaFileBuilder("/path/foo2.ogg")
531 .setType(AudioMedia)
532 .setTitle("foo foo")
533 .setDate("2010-01-03")
534 .setAuthor("artist")
535 .setAlbum("album");
536 MediaFile audio3 = MediaFileBuilder("/path/foo3.ogg")
537 .setType(AudioMedia)
538 .setTitle("foo foo foo")
539 .setDate("2010-01-02")
540 .setAuthor("artist")
541 .setAlbum("album");
542
543 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
544 store.insert(audio1);
545 store.insert(audio2);
546 store.insert(audio3);
547
548 check_query_order(store, "/path/foo1.ogg", "/path/foo2.ogg", "/path/foo3.ogg");
549
550 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
551 check_query_order(store_ro, "/path/foo1.ogg", "/path/foo2.ogg", "/path/foo3.ogg");
552
553 store.remove(audio1.getFileName());
554 store.remove(audio2.getFileName());
555 store.remove(audio3.getFileName());
556}
557
558TEST(MediaStoreTest, unmount) {
468 MediaFile audio1 = MediaFileBuilder("/media/username/dir/fname.ogg")559 MediaFile audio1 = MediaFileBuilder("/media/username/dir/fname.ogg")
469 .setType(AudioMedia)560 .setType(AudioMedia)
470 .setTitle("bbb bbb");561 .setTitle("bbb bbb");
@@ -488,7 +579,7 @@
488 ASSERT_EQ(result.size(), 2);579 ASSERT_EQ(result.size(), 2);
489}580}
490581
491TEST_F(MediaStoreTest, utils) {582TEST(MediaStoreTest, utils) {
492 string source("_a.b(c)[d]{e}f.mp3");583 string source("_a.b(c)[d]{e}f.mp3");
493 string correct = {" a b c d e f"};584 string correct = {" a b c d e f"};
494 string result = filenameToTitle(source);585 string result = filenameToTitle(source);
@@ -499,54 +590,7 @@
499 EXPECT_EQ(sqlQuote(unquoted), quoted);590 EXPECT_EQ(sqlQuote(unquoted), quoted);
500}591}
501592
502TEST_F(MediaStoreTest, queryAlbums) {593void check_query_albums(MediaStore const &store) {
503 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
504 .setType(AudioMedia)
505 .setTitle("TitleOne")
506 .setAuthor("ArtistOne")
507 .setAlbum("AlbumOne")
508 .setAlbumArtist("Various Artists")
509 .setDate("2000-01-01")
510 .setDiscNumber(1)
511 .setTrackNumber(1)
512 .setGenre("GenreOne");
513 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
514 .setType(AudioMedia)
515 .setTitle("TitleTwo")
516 .setAuthor("ArtistTwo")
517 .setAlbum("AlbumOne")
518 .setAlbumArtist("Various Artists")
519 .setDate("2000-01-01")
520 .setDiscNumber(1)
521 .setTrackNumber(2)
522 .setGenre("GenreOne");
523 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track3.ogg")
524 .setType(AudioMedia)
525 .setTitle("TitleThree")
526 .setAuthor("ArtistThree")
527 .setAlbum("AlbumOne")
528 .setAlbumArtist("Various Artists")
529 .setDate("2000-01-01")
530 .setDiscNumber(2)
531 .setTrackNumber(1)
532 .setGenre("GenreOne");
533 MediaFile audio4 = MediaFileBuilder("/home/username/Music/fname.ogg")
534 .setType(AudioMedia)
535 .setTitle("TitleFour")
536 .setAuthor("ArtistFour")
537 .setAlbum("AlbumTwo")
538 .setAlbumArtist("ArtistFour")
539 .setDate("2014-06-01")
540 .setTrackNumber(1)
541 .setGenre("GenreTwo")
542 .setHasThumbnail(true);
543
544 MediaStore store(":memory:", MS_READ_WRITE);
545 store.insert(audio1);
546 store.insert(audio2);
547 store.insert(audio3);
548 store.insert(audio4);
549
550 // Query a track title594 // Query a track title
551 Filter filter;595 Filter filter;
552 vector<Album> albums = store.queryAlbums("TitleOne", filter);596 vector<Album> albums = store.queryAlbums("TitleOne", filter);
@@ -573,45 +617,66 @@
573 EXPECT_EQ(albums[0].getArtist(), "Various Artists");617 EXPECT_EQ(albums[0].getArtist(), "Various Artists");
574}618}
575619
576TEST_F(MediaStoreTest, queryAlbums_limit) {620TEST(MediaStoreTest, queryAlbums) {
577 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")621 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
578 .setType(AudioMedia)622 .setType(AudioMedia)
579 .setTitle("TitleOne")623 .setTitle("TitleOne")
580 .setAuthor("ArtistOne")624 .setAuthor("ArtistOne")
581 .setAlbum("AlbumOne")625 .setAlbum("AlbumOne")
582 .setAlbumArtist("Various Artists")626 .setAlbumArtist("Various Artists")
627 .setDate("2000-01-01")
583 .setDiscNumber(1)628 .setDiscNumber(1)
584 .setTrackNumber(1);629 .setTrackNumber(1)
630 .setGenre("GenreOne");
585 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")631 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
586 .setType(AudioMedia)632 .setType(AudioMedia)
587 .setTitle("TitleTwo")633 .setTitle("TitleTwo")
588 .setAuthor("ArtistTwo")634 .setAuthor("ArtistTwo")
589 .setAlbum("AlbumOne")635 .setAlbum("AlbumOne")
590 .setAlbumArtist("Various Artists")636 .setAlbumArtist("Various Artists")
637 .setDate("2000-01-01")
591 .setDiscNumber(1)638 .setDiscNumber(1)
592 .setTrackNumber(2);639 .setTrackNumber(2)
640 .setGenre("GenreOne");
593 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track3.ogg")641 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track3.ogg")
594 .setType(AudioMedia)642 .setType(AudioMedia)
595 .setTitle("TitleThree")643 .setTitle("TitleThree")
596 .setAuthor("ArtistThree")644 .setAuthor("ArtistThree")
597 .setAlbum("AlbumOne")645 .setAlbum("AlbumOne")
598 .setAlbumArtist("Various Artists")646 .setAlbumArtist("Various Artists")
647 .setDate("2000-01-01")
599 .setDiscNumber(2)648 .setDiscNumber(2)
600 .setTrackNumber(1);649 .setTrackNumber(1)
650 .setGenre("GenreOne");
601 MediaFile audio4 = MediaFileBuilder("/home/username/Music/fname.ogg")651 MediaFile audio4 = MediaFileBuilder("/home/username/Music/fname.ogg")
602 .setType(AudioMedia)652 .setType(AudioMedia)
603 .setTitle("TitleFour")653 .setTitle("TitleFour")
604 .setAuthor("ArtistFour")654 .setAuthor("ArtistFour")
605 .setAlbum("AlbumTwo")655 .setAlbum("AlbumTwo")
606 .setAlbumArtist("ArtistFour")656 .setAlbumArtist("ArtistFour")
607 .setTrackNumber(1);657 .setDate("2014-06-01")
658 .setTrackNumber(1)
659 .setGenre("GenreTwo")
660 .setHasThumbnail(true);
608661
609 MediaStore store(":memory:", MS_READ_WRITE);662 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
610 store.insert(audio1);663 store.insert(audio1);
611 store.insert(audio2);664 store.insert(audio2);
612 store.insert(audio3);665 store.insert(audio3);
613 store.insert(audio4);666 store.insert(audio4);
614667
668 check_query_albums(store);
669
670 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
671 check_query_albums(store_ro);
672
673 store.remove(audio1.getFileName());
674 store.remove(audio2.getFileName());
675 store.remove(audio3.getFileName());
676 store.remove(audio4.getFileName());
677}
678
679void check_query_albums_limit(MediaStore const &store) {
615 Filter filter;680 Filter filter;
616 vector<Album> albums = store.queryAlbums("Artist", filter);681 vector<Album> albums = store.queryAlbums("Artist", filter);
617 EXPECT_EQ(2, albums.size());682 EXPECT_EQ(2, albums.size());
@@ -620,7 +685,7 @@
620 EXPECT_EQ(1, albums.size());685 EXPECT_EQ(1, albums.size());
621}686}
622687
623TEST_F(MediaStoreTest, queryAlbums_empty) {688TEST(MediaStoreTest, queryAlbums_limit) {
624 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")689 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
625 .setType(AudioMedia)690 .setType(AudioMedia)
626 .setTitle("TitleOne")691 .setTitle("TitleOne")
@@ -653,12 +718,24 @@
653 .setAlbumArtist("ArtistFour")718 .setAlbumArtist("ArtistFour")
654 .setTrackNumber(1);719 .setTrackNumber(1);
655720
656 MediaStore store(":memory:", MS_READ_WRITE);721 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
657 store.insert(audio1);722 store.insert(audio1);
658 store.insert(audio2);723 store.insert(audio2);
659 store.insert(audio3);724 store.insert(audio3);
660 store.insert(audio4);725 store.insert(audio4);
661726
727 check_query_albums_limit(store);
728
729 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
730 check_query_albums_limit(store_ro);
731
732 store.remove(audio1.getFileName());
733 store.remove(audio2.getFileName());
734 store.remove(audio3.getFileName());
735 store.remove(audio4.getFileName());
736}
737
738void check_query_albums_empty(MediaStore const &store) {
662 Filter filter;739 Filter filter;
663 vector<Album> albums = store.queryAlbums("", filter);740 vector<Album> albums = store.queryAlbums("", filter);
664 EXPECT_EQ(2, albums.size());741 EXPECT_EQ(2, albums.size());
@@ -667,7 +744,89 @@
667 EXPECT_EQ(1, albums.size());744 EXPECT_EQ(1, albums.size());
668}745}
669746
670TEST_F(MediaStoreTest, queryAlbums_order) {747TEST(MediaStoreTest, queryAlbums_empty) {
748 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
749 .setType(AudioMedia)
750 .setTitle("TitleOne")
751 .setAuthor("ArtistOne")
752 .setAlbum("AlbumOne")
753 .setAlbumArtist("Various Artists")
754 .setDiscNumber(1)
755 .setTrackNumber(1);
756 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
757 .setType(AudioMedia)
758 .setTitle("TitleTwo")
759 .setAuthor("ArtistTwo")
760 .setAlbum("AlbumOne")
761 .setAlbumArtist("Various Artists")
762 .setDiscNumber(1)
763 .setTrackNumber(2);
764 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track3.ogg")
765 .setType(AudioMedia)
766 .setTitle("TitleThree")
767 .setAuthor("ArtistThree")
768 .setAlbum("AlbumOne")
769 .setAlbumArtist("Various Artists")
770 .setDiscNumber(2)
771 .setTrackNumber(1);
772 MediaFile audio4 = MediaFileBuilder("/home/username/Music/fname.ogg")
773 .setType(AudioMedia)
774 .setTitle("TitleFour")
775 .setAuthor("ArtistFour")
776 .setAlbum("AlbumTwo")
777 .setAlbumArtist("ArtistFour")
778 .setTrackNumber(1);
779
780 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
781 store.insert(audio1);
782 store.insert(audio2);
783 store.insert(audio3);
784 store.insert(audio4);
785
786 check_query_albums_empty(store);
787
788 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
789 check_query_albums_empty(store_ro);
790
791 store.remove(audio1.getFileName());
792 store.remove(audio2.getFileName());
793 store.remove(audio3.getFileName());
794 store.remove(audio4.getFileName());
795}
796
797void check_query_albums_order(MediaStore const &store) {
798 // Default sort
799 Filter filter;
800 vector<Album> albums = store.queryAlbums("foo", filter);
801 ASSERT_EQ(3, albums.size());
802 EXPECT_EQ("foo", albums[0].getTitle());
803 EXPECT_EQ("foo foo", albums[1].getTitle());
804 EXPECT_EQ("foo foo foo", albums[2].getTitle());
805
806 // Sort by title (same as default)
807 filter.setOrder(MediaOrder::Title);
808 albums = store.queryAlbums("foo", filter);
809 ASSERT_EQ(3, albums.size());
810 EXPECT_EQ("foo", albums[0].getTitle());
811 EXPECT_EQ("foo foo", albums[1].getTitle());
812 EXPECT_EQ("foo foo foo", albums[2].getTitle());
813
814 // Sort by title, reversed
815 filter.setReverse(true);
816 albums = store.queryAlbums("foo", filter);
817 ASSERT_EQ(3, albums.size());
818 EXPECT_EQ("foo foo foo", albums[0].getTitle());
819 EXPECT_EQ("foo foo", albums[1].getTitle());
820 EXPECT_EQ("foo", albums[2].getTitle());
821
822 // Other orders are not supported
823 filter.setOrder(MediaOrder::Rank);
824 EXPECT_THROW(store.queryAlbums("foo", filter), std::runtime_error);
825 filter.setOrder(MediaOrder::Date);
826 EXPECT_THROW(store.queryAlbums("foo", filter), std::runtime_error);
827}
828
829TEST(MediaStoreTest, queryAlbums_order) {
671 MediaFile audio1 = MediaFileBuilder("/path/foo1.ogg")830 MediaFile audio1 = MediaFileBuilder("/path/foo1.ogg")
672 .setType(AudioMedia)831 .setType(AudioMedia)
673 .setTitle("title")832 .setTitle("title")
@@ -687,81 +846,22 @@
687 .setAuthor("artist")846 .setAuthor("artist")
688 .setAlbum("foo foo foo");847 .setAlbum("foo foo foo");
689848
690 MediaStore store(":memory:", MS_READ_WRITE);849 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
691 store.insert(audio1);850 store.insert(audio1);
692 store.insert(audio2);851 store.insert(audio2);
693 store.insert(audio3);852 store.insert(audio3);
694853
695 // Default sort854 check_query_albums_order(store);
696 Filter filter;855
697 vector<Album> albums = store.queryAlbums("foo", filter);856 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
698 ASSERT_EQ(3, albums.size());857 check_query_albums_order(store_ro);
699 EXPECT_EQ("foo", albums[0].getTitle());858
700 EXPECT_EQ("foo foo", albums[1].getTitle());859 store.remove(audio1.getFileName());
701 EXPECT_EQ("foo foo foo", albums[2].getTitle());860 store.remove(audio2.getFileName());
702861 store.remove(audio3.getFileName());
703 // Sort by title (same as default)
704 filter.setOrder(MediaOrder::Title);
705 albums = store.queryAlbums("foo", filter);
706 ASSERT_EQ(3, albums.size());
707 EXPECT_EQ("foo", albums[0].getTitle());
708 EXPECT_EQ("foo foo", albums[1].getTitle());
709 EXPECT_EQ("foo foo foo", albums[2].getTitle());
710
711 // Sort by title, reversed
712 filter.setReverse(true);
713 albums = store.queryAlbums("foo", filter);
714 ASSERT_EQ(3, albums.size());
715 EXPECT_EQ("foo foo foo", albums[0].getTitle());
716 EXPECT_EQ("foo foo", albums[1].getTitle());
717 EXPECT_EQ("foo", albums[2].getTitle());
718
719 // Other orders are not supported
720 filter.setOrder(MediaOrder::Rank);
721 EXPECT_THROW(store.queryAlbums("foo", filter), std::runtime_error);
722 filter.setOrder(MediaOrder::Date);
723 EXPECT_THROW(store.queryAlbums("foo", filter), std::runtime_error);
724}862}
725863
726TEST_F(MediaStoreTest, queryArtists) {864void check_query_artists(MediaStore const &store) {
727 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
728 .setType(AudioMedia)
729 .setTitle("TitleOne")
730 .setAuthor("ArtistOne")
731 .setAlbum("AlbumOne")
732 .setAlbumArtist("Various Artists")
733 .setDiscNumber(1)
734 .setTrackNumber(1);
735 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
736 .setType(AudioMedia)
737 .setTitle("TitleTwo")
738 .setAuthor("ArtistTwo")
739 .setAlbum("AlbumOne")
740 .setAlbumArtist("Various Artists")
741 .setDiscNumber(1)
742 .setTrackNumber(2);
743 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track3.ogg")
744 .setType(AudioMedia)
745 .setTitle("TitleThree")
746 .setAuthor("ArtistThree")
747 .setAlbum("AlbumOne")
748 .setAlbumArtist("Various Artists")
749 .setDiscNumber(2)
750 .setTrackNumber(1);
751 MediaFile audio4 = MediaFileBuilder("/home/username/Music/fname.ogg")
752 .setType(AudioMedia)
753 .setTitle("TitleFour")
754 .setAuthor("ArtistFour")
755 .setAlbum("AlbumTwo")
756 .setAlbumArtist("ArtistFour")
757 .setTrackNumber(1);
758
759 MediaStore store(":memory:", MS_READ_WRITE);
760 store.insert(audio1);
761 store.insert(audio2);
762 store.insert(audio3);
763 store.insert(audio4);
764
765 // Query a track title865 // Query a track title
766 Filter filter;866 Filter filter;
767 vector<string> artists = store.queryArtists("TitleOne", filter);867 vector<string> artists = store.queryArtists("TitleOne", filter);
@@ -779,7 +879,7 @@
779 EXPECT_EQ(artists[0], "ArtistTwo");879 EXPECT_EQ(artists[0], "ArtistTwo");
780}880}
781881
782TEST_F(MediaStoreTest, queryArtists_limit) {882TEST(MediaStoreTest, queryArtists) {
783 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")883 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
784 .setType(AudioMedia)884 .setType(AudioMedia)
785 .setTitle("TitleOne")885 .setTitle("TitleOne")
@@ -796,11 +896,40 @@
796 .setAlbumArtist("Various Artists")896 .setAlbumArtist("Various Artists")
797 .setDiscNumber(1)897 .setDiscNumber(1)
798 .setTrackNumber(2);898 .setTrackNumber(2);
899 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track3.ogg")
900 .setType(AudioMedia)
901 .setTitle("TitleThree")
902 .setAuthor("ArtistThree")
903 .setAlbum("AlbumOne")
904 .setAlbumArtist("Various Artists")
905 .setDiscNumber(2)
906 .setTrackNumber(1);
907 MediaFile audio4 = MediaFileBuilder("/home/username/Music/fname.ogg")
908 .setType(AudioMedia)
909 .setTitle("TitleFour")
910 .setAuthor("ArtistFour")
911 .setAlbum("AlbumTwo")
912 .setAlbumArtist("ArtistFour")
913 .setTrackNumber(1);
799914
800 MediaStore store(":memory:", MS_READ_WRITE);915 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
801 store.insert(audio1);916 store.insert(audio1);
802 store.insert(audio2);917 store.insert(audio2);
803918 store.insert(audio3);
919 store.insert(audio4);
920
921 check_query_artists(store);
922
923 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
924 check_query_artists(store_ro);
925
926 store.remove(audio1.getFileName());
927 store.remove(audio2.getFileName());
928 store.remove(audio3.getFileName());
929 store.remove(audio4.getFileName());
930}
931
932void check_query_artists_limit(MediaStore const &store) {
804 Filter filter;933 Filter filter;
805 vector<string> artists = store.queryArtists("Artist", filter);934 vector<string> artists = store.queryArtists("Artist", filter);
806 EXPECT_EQ(2, artists.size());935 EXPECT_EQ(2, artists.size());
@@ -809,7 +938,7 @@
809 EXPECT_EQ(1, artists.size());938 EXPECT_EQ(1, artists.size());
810}939}
811940
812TEST_F(MediaStoreTest, queryArtists_empty) {941TEST(MediaStoreTest, queryArtists_limit) {
813 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")942 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
814 .setType(AudioMedia)943 .setType(AudioMedia)
815 .setTitle("TitleOne")944 .setTitle("TitleOne")
@@ -827,10 +956,20 @@
827 .setDiscNumber(1)956 .setDiscNumber(1)
828 .setTrackNumber(2);957 .setTrackNumber(2);
829958
830 MediaStore store(":memory:", MS_READ_WRITE);959 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
831 store.insert(audio1);960 store.insert(audio1);
832 store.insert(audio2);961 store.insert(audio2);
833962
963 check_query_artists_limit(store);
964
965 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
966 check_query_artists_limit(store_ro);
967
968 store.remove(audio1.getFileName());
969 store.remove(audio2.getFileName());
970}
971
972void check_query_artists_empty(MediaStore const &store) {
834 Filter filter;973 Filter filter;
835 vector<string> artists = store.queryArtists("", filter);974 vector<string> artists = store.queryArtists("", filter);
836 EXPECT_EQ(2, artists.size());975 EXPECT_EQ(2, artists.size());
@@ -839,7 +978,70 @@
839 EXPECT_EQ(1, artists.size());978 EXPECT_EQ(1, artists.size());
840}979}
841980
842TEST_F(MediaStoreTest, queryArtists_order) {981TEST(MediaStoreTest, queryArtists_empty) {
982 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
983 .setType(AudioMedia)
984 .setTitle("TitleOne")
985 .setAuthor("ArtistOne")
986 .setAlbum("AlbumOne")
987 .setAlbumArtist("Various Artists")
988 .setDiscNumber(1)
989 .setTrackNumber(1);
990 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
991 .setType(AudioMedia)
992 .setTitle("TitleTwo")
993 .setAuthor("ArtistTwo")
994 .setAlbum("AlbumOne")
995 .setAlbumArtist("Various Artists")
996 .setDiscNumber(1)
997 .setTrackNumber(2);
998
999 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
1000 store.insert(audio1);
1001 store.insert(audio2);
1002
1003 check_query_artists_empty(store);
1004
1005 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
1006 check_query_artists_empty(store_ro);
1007
1008 store.remove(audio1.getFileName());
1009 store.remove(audio2.getFileName());
1010}
1011
1012void check_query_artists_order(MediaStore const &store) {
1013 // Default sort
1014 Filter filter;
1015 vector<std::string> artists = store.queryArtists("foo", filter);
1016 ASSERT_EQ(3, artists.size());
1017 EXPECT_EQ("foo", artists[0]);
1018 EXPECT_EQ("foo foo", artists[1]);
1019 EXPECT_EQ("foo foo foo", artists[2]);
1020
1021 // Sort by title (same as default)
1022 filter.setOrder(MediaOrder::Title);
1023 artists = store.queryArtists("foo", filter);
1024 ASSERT_EQ(3, artists.size());
1025 EXPECT_EQ("foo", artists[0]);
1026 EXPECT_EQ("foo foo", artists[1]);
1027 EXPECT_EQ("foo foo foo", artists[2]);
1028
1029 // Sort by title, reversed
1030 filter.setReverse(true);
1031 artists = store.queryArtists("foo", filter);
1032 ASSERT_EQ(3, artists.size());
1033 EXPECT_EQ("foo foo foo", artists[0]);
1034 EXPECT_EQ("foo foo", artists[1]);
1035 EXPECT_EQ("foo", artists[2]);
1036
1037 // Other orders are not supported
1038 filter.setOrder(MediaOrder::Rank);
1039 EXPECT_THROW(store.queryArtists("foo", filter), std::runtime_error);
1040 filter.setOrder(MediaOrder::Date);
1041 EXPECT_THROW(store.queryArtists("foo", filter), std::runtime_error);
1042}
1043
1044TEST(MediaStoreTest, queryArtists_order) {
843 MediaFile audio1 = MediaFileBuilder("/path/foo1.ogg")1045 MediaFile audio1 = MediaFileBuilder("/path/foo1.ogg")
844 .setType(AudioMedia)1046 .setType(AudioMedia)
845 .setTitle("title")1047 .setTitle("title")
@@ -859,73 +1061,22 @@
859 .setAuthor("foo foo foo")1061 .setAuthor("foo foo foo")
860 .setAlbum("album");1062 .setAlbum("album");
8611063
862 MediaStore store(":memory:", MS_READ_WRITE);1064 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
863 store.insert(audio1);1065 store.insert(audio1);
864 store.insert(audio2);1066 store.insert(audio2);
865 store.insert(audio3);1067 store.insert(audio3);
8661068
867 // Default sort1069 check_query_artists_order(store);
868 Filter filter;1070
869 vector<std::string> artists = store.queryArtists("foo", filter);1071 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
870 ASSERT_EQ(3, artists.size());1072 check_query_artists_order(store_ro);
871 EXPECT_EQ("foo", artists[0]);1073
872 EXPECT_EQ("foo foo", artists[1]);1074 store.remove(audio1.getFileName());
873 EXPECT_EQ("foo foo foo", artists[2]);1075 store.remove(audio2.getFileName());
8741076 store.remove(audio3.getFileName());
875 // Sort by title (same as default)
876 filter.setOrder(MediaOrder::Title);
877 artists = store.queryArtists("foo", filter);
878 ASSERT_EQ(3, artists.size());
879 EXPECT_EQ("foo", artists[0]);
880 EXPECT_EQ("foo foo", artists[1]);
881 EXPECT_EQ("foo foo foo", artists[2]);
882
883 // Sort by title, reversed
884 filter.setReverse(true);
885 artists = store.queryArtists("foo", filter);
886 ASSERT_EQ(3, artists.size());
887 EXPECT_EQ("foo foo foo", artists[0]);
888 EXPECT_EQ("foo foo", artists[1]);
889 EXPECT_EQ("foo", artists[2]);
890
891 // Other orders are not supported
892 filter.setOrder(MediaOrder::Rank);
893 EXPECT_THROW(store.queryArtists("foo", filter), std::runtime_error);
894 filter.setOrder(MediaOrder::Date);
895 EXPECT_THROW(store.queryArtists("foo", filter), std::runtime_error);
896}1077}
8971078
898TEST_F(MediaStoreTest, getAlbumSongs) {1079void check_album_songs(MediaStore const &store) {
899 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
900 .setType(AudioMedia)
901 .setTitle("TitleOne")
902 .setAuthor("ArtistOne")
903 .setAlbum("AlbumOne")
904 .setAlbumArtist("Various Artists")
905 .setDiscNumber(1)
906 .setTrackNumber(1);
907 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
908 .setType(AudioMedia)
909 .setTitle("TitleTwo")
910 .setAuthor("ArtistTwo")
911 .setAlbum("AlbumOne")
912 .setAlbumArtist("Various Artists")
913 .setDiscNumber(1)
914 .setTrackNumber(2);
915 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track3.ogg")
916 .setType(AudioMedia)
917 .setTitle("TitleThree")
918 .setAuthor("ArtistThree")
919 .setAlbum("AlbumOne")
920 .setAlbumArtist("Various Artists")
921 .setDiscNumber(2)
922 .setTrackNumber(1);
923
924 MediaStore store(":memory:", MS_READ_WRITE);
925 store.insert(audio1);
926 store.insert(audio2);
927 store.insert(audio3);
928
929 vector<MediaFile> tracks = store.getAlbumSongs(1080 vector<MediaFile> tracks = store.getAlbumSongs(
930 Album("AlbumOne", "Various Artists"));1081 Album("AlbumOne", "Various Artists"));
931 ASSERT_EQ(tracks.size(), 3);1082 ASSERT_EQ(tracks.size(), 3);
@@ -934,20 +1085,69 @@
934 EXPECT_EQ(tracks[2].getTitle(), "TitleThree");1085 EXPECT_EQ(tracks[2].getTitle(), "TitleThree");
935}1086}
9361087
937TEST_F(MediaStoreTest, getETag) {1088TEST(MediaStoreTest, getAlbumSongs) {
1089 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
1090 .setType(AudioMedia)
1091 .setTitle("TitleOne")
1092 .setAuthor("ArtistOne")
1093 .setAlbum("AlbumOne")
1094 .setAlbumArtist("Various Artists")
1095 .setDiscNumber(1)
1096 .setTrackNumber(1);
1097 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
1098 .setType(AudioMedia)
1099 .setTitle("TitleTwo")
1100 .setAuthor("ArtistTwo")
1101 .setAlbum("AlbumOne")
1102 .setAlbumArtist("Various Artists")
1103 .setDiscNumber(1)
1104 .setTrackNumber(2);
1105 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track3.ogg")
1106 .setType(AudioMedia)
1107 .setTitle("TitleThree")
1108 .setAuthor("ArtistThree")
1109 .setAlbum("AlbumOne")
1110 .setAlbumArtist("Various Artists")
1111 .setDiscNumber(2)
1112 .setTrackNumber(1);
1113
1114 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
1115 store.insert(audio1);
1116 store.insert(audio2);
1117 store.insert(audio3);
1118
1119 check_album_songs(store);
1120
1121 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
1122 check_album_songs(store_ro);
1123
1124 store.remove(audio1.getFileName());
1125 store.remove(audio2.getFileName());
1126 store.remove(audio3.getFileName());
1127}
1128
1129void check_get_etag(MediaStore const &store) {
1130 EXPECT_EQ(store.getETag("/path/file.ogg"), "etag");
1131 EXPECT_EQ(store.getETag("/something-else.mp3"), "");
1132}
1133
1134TEST(MediaStoreTest, getETag) {
938 MediaFile file = MediaFileBuilder("/path/file.ogg")1135 MediaFile file = MediaFileBuilder("/path/file.ogg")
939 .setETag("etag")1136 .setETag("etag")
940 .setType(AudioMedia);1137 .setType(AudioMedia);
9411138
942 MediaStore store(":memory:", MS_READ_WRITE);1139 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
943 store.insert(file);1140 store.insert(file);
9441141
945 EXPECT_EQ(store.getETag("/path/file.ogg"), "etag");1142 check_get_etag(store);
946 EXPECT_EQ(store.getETag("/something-else.mp3"), "");1143
1144 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
1145 check_get_etag(store_ro);
1146
1147 store.remove(file.getFileName());
947}1148}
9481149
9491150TEST(MediaStoreTest, constraints) {
950TEST_F(MediaStoreTest, constraints) {
951 MediaFile file = MediaFileBuilder("no_slash_at_beginning.ogg")1151 MediaFile file = MediaFileBuilder("no_slash_at_beginning.ogg")
952 .setETag("etag")1152 .setETag("etag")
953 .setType(AudioMedia);1153 .setType(AudioMedia);
@@ -959,52 +1159,7 @@
959 ASSERT_THROW(store.insert(file2), std::runtime_error);1159 ASSERT_THROW(store.insert(file2), std::runtime_error);
960}1160}
9611161
962TEST_F(MediaStoreTest, listSongs) {1162void check_list_songs(MediaStore const &store) {
963 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
964 .setType(AudioMedia)
965 .setTitle("TitleOne")
966 .setAuthor("ArtistOne")
967 .setAlbum("AlbumOne")
968 .setTrackNumber(1);
969 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
970 .setType(AudioMedia)
971 .setTitle("TitleTwo")
972 .setAuthor("ArtistOne")
973 .setAlbum("AlbumOne")
974 .setTrackNumber(2);
975 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track3.ogg")
976 .setType(AudioMedia)
977 .setTitle("TitleThree")
978 .setAuthor("ArtistOne")
979 .setAlbum("AlbumTwo");
980 MediaFile audio4 = MediaFileBuilder("/home/username/Music/track4.ogg")
981 .setType(AudioMedia)
982 .setTitle("TitleFour")
983 .setAuthor("ArtistTwo")
984 .setAlbum("AlbumThree");
985 MediaFile audio5 = MediaFileBuilder("/home/username/Music/track5.ogg")
986 .setType(AudioMedia)
987 .setTitle("TitleFive")
988 .setAuthor("ArtistOne")
989 .setAlbum("AlbumFour")
990 .setAlbumArtist("Various Artists")
991 .setTrackNumber(1);
992 MediaFile audio6 = MediaFileBuilder("/home/username/Music/track6.ogg")
993 .setType(AudioMedia)
994 .setTitle("TitleSix")
995 .setAuthor("ArtistTwo")
996 .setAlbum("AlbumFour")
997 .setAlbumArtist("Various Artists")
998 .setTrackNumber(2);
999
1000 MediaStore store(":memory:", MS_READ_WRITE);
1001 store.insert(audio1);
1002 store.insert(audio2);
1003 store.insert(audio3);
1004 store.insert(audio4);
1005 store.insert(audio5);
1006 store.insert(audio6);
1007
1008 Filter filter;1163 Filter filter;
1009 vector<MediaFile> tracks = store.listSongs(filter);1164 vector<MediaFile> tracks = store.listSongs(filter);
1010 ASSERT_EQ(6, tracks.size());1165 ASSERT_EQ(6, tracks.size());
@@ -1060,31 +1215,37 @@
1060 EXPECT_EQ(3, tracks.size());1215 EXPECT_EQ(3, tracks.size());
1061}1216}
10621217
1063TEST_F(MediaStoreTest, listAlbums) {1218TEST(MediaStoreTest, listSongs) {
1064 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")1219 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
1065 .setType(AudioMedia)1220 .setType(AudioMedia)
1066 .setTitle("TitleOne")1221 .setTitle("TitleOne")
1067 .setAuthor("ArtistOne")1222 .setAuthor("ArtistOne")
1068 .setAlbum("AlbumOne")1223 .setAlbum("AlbumOne")
1069 .setTrackNumber(1);1224 .setTrackNumber(1);
1070 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track3.ogg")1225 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track2.ogg")
1226 .setType(AudioMedia)
1227 .setTitle("TitleTwo")
1228 .setAuthor("ArtistOne")
1229 .setAlbum("AlbumOne")
1230 .setTrackNumber(2);
1231 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track3.ogg")
1071 .setType(AudioMedia)1232 .setType(AudioMedia)
1072 .setTitle("TitleThree")1233 .setTitle("TitleThree")
1073 .setAuthor("ArtistOne")1234 .setAuthor("ArtistOne")
1074 .setAlbum("AlbumTwo");1235 .setAlbum("AlbumTwo");
1075 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track4.ogg")1236 MediaFile audio4 = MediaFileBuilder("/home/username/Music/track4.ogg")
1076 .setType(AudioMedia)1237 .setType(AudioMedia)
1077 .setTitle("TitleFour")1238 .setTitle("TitleFour")
1078 .setAuthor("ArtistTwo")1239 .setAuthor("ArtistTwo")
1079 .setAlbum("AlbumThree");1240 .setAlbum("AlbumThree");
1080 MediaFile audio4 = MediaFileBuilder("/home/username/Music/track5.ogg")1241 MediaFile audio5 = MediaFileBuilder("/home/username/Music/track5.ogg")
1081 .setType(AudioMedia)1242 .setType(AudioMedia)
1082 .setTitle("TitleFive")1243 .setTitle("TitleFive")
1083 .setAuthor("ArtistOne")1244 .setAuthor("ArtistOne")
1084 .setAlbum("AlbumFour")1245 .setAlbum("AlbumFour")
1085 .setAlbumArtist("Various Artists")1246 .setAlbumArtist("Various Artists")
1086 .setTrackNumber(1);1247 .setTrackNumber(1);
1087 MediaFile audio5 = MediaFileBuilder("/home/username/Music/track6.ogg")1248 MediaFile audio6 = MediaFileBuilder("/home/username/Music/track6.ogg")
1088 .setType(AudioMedia)1249 .setType(AudioMedia)
1089 .setTitle("TitleSix")1250 .setTitle("TitleSix")
1090 .setAuthor("ArtistTwo")1251 .setAuthor("ArtistTwo")
@@ -1092,44 +1253,59 @@
1092 .setAlbumArtist("Various Artists")1253 .setAlbumArtist("Various Artists")
1093 .setTrackNumber(2);1254 .setTrackNumber(2);
10941255
1095 MediaStore store(":memory:", MS_READ_WRITE);1256 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
1096 store.insert(audio1);1257 store.insert(audio1);
1097 store.insert(audio2);1258 store.insert(audio2);
1098 store.insert(audio3);1259 store.insert(audio3);
1099 store.insert(audio4);1260 store.insert(audio4);
1100 store.insert(audio5);1261 store.insert(audio5);
11011262 store.insert(audio6);
1263
1264 check_list_songs(store);
1265
1266 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
1267 check_list_songs(store_ro);
1268
1269 store.remove(audio1.getFileName());
1270 store.remove(audio2.getFileName());
1271 store.remove(audio3.getFileName());
1272 store.remove(audio4.getFileName());
1273 store.remove(audio5.getFileName());
1274 store.remove(audio6.getFileName());
1275}
1276
1277void check_list_albums(MediaStore const &store) {
1102 Filter filter;1278 Filter filter;
1103 vector<Album> albums = store.listAlbums(filter);1279 vector<Album> albums = store.listAlbums(filter);
1104 ASSERT_EQ(4, albums.size());1280 ASSERT_EQ(4, albums.size());
1105 EXPECT_EQ("AlbumOne", albums[0].getTitle());1281 EXPECT_EQ("AlbumOne", albums[0].getTitle());
11061282
1107 // test limit1283 // test limit
1108 filter.setLimit(2);1284 filter.setLimit(2);
1109 albums = store.listAlbums(filter);1285 albums = store.listAlbums(filter);
1110 EXPECT_EQ(2, albums.size());1286 EXPECT_EQ(2, albums.size());
1111 filter.setLimit(-1);1287 filter.setLimit(-1);
11121288
1113 // Songs by artist1289 // Songs by artist
1114 filter.setArtist("ArtistOne");1290 filter.setArtist("ArtistOne");
1115 albums = store.listAlbums(filter);1291 albums = store.listAlbums(filter);
1116 EXPECT_EQ(3, albums.size());1292 EXPECT_EQ(3, albums.size());
11171293
1118 // Songs by album artist1294 // Songs by album artist
1119 filter.clear();1295 filter.clear();
1120 filter.setAlbumArtist("ArtistOne");1296 filter.setAlbumArtist("ArtistOne");
1121 albums = store.listAlbums(filter);1297 albums = store.listAlbums(filter);
1122 EXPECT_EQ(2, albums.size());1298 EXPECT_EQ(2, albums.size());
11231299
1124 // Combination1300 // Combination
1125 filter.clear();1301 filter.clear();
1126 filter.setArtist("ArtistOne");1302 filter.setArtist("ArtistOne");
1127 filter.setAlbumArtist("Various Artists");1303 filter.setAlbumArtist("Various Artists");
1128 albums = store.listAlbums(filter);1304 albums = store.listAlbums(filter);
1129 EXPECT_EQ(1, albums.size());1305 EXPECT_EQ(1, albums.size());
1130}1306}
11311307
1132TEST_F(MediaStoreTest, listArtists) {1308TEST(MediaStoreTest, listAlbums) {
1133 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")1309 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
1134 .setType(AudioMedia)1310 .setType(AudioMedia)
1135 .setTitle("TitleOne")1311 .setTitle("TitleOne")
@@ -1161,13 +1337,26 @@
1161 .setAlbumArtist("Various Artists")1337 .setAlbumArtist("Various Artists")
1162 .setTrackNumber(2);1338 .setTrackNumber(2);
11631339
1164 MediaStore store(":memory:", MS_READ_WRITE);1340 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
1165 store.insert(audio1);1341 store.insert(audio1);
1166 store.insert(audio2);1342 store.insert(audio2);
1167 store.insert(audio3);1343 store.insert(audio3);
1168 store.insert(audio4);1344 store.insert(audio4);
1169 store.insert(audio5);1345 store.insert(audio5);
11701346
1347 check_list_albums(store);
1348
1349 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
1350 check_list_albums(store_ro);
1351
1352 store.remove(audio1.getFileName());
1353 store.remove(audio2.getFileName());
1354 store.remove(audio3.getFileName());
1355 store.remove(audio4.getFileName());
1356 store.remove(audio5.getFileName());
1357}
1358
1359void check_list_artists(MediaStore const &store) {
1171 Filter filter;1360 Filter filter;
1172 vector<string> artists = store.listArtists(filter);1361 vector<string> artists = store.listArtists(filter);
1173 ASSERT_EQ(2, artists.size());1362 ASSERT_EQ(2, artists.size());
@@ -1188,7 +1377,58 @@
1188 EXPECT_EQ("Various Artists", artists[2]);1377 EXPECT_EQ("Various Artists", artists[2]);
1189}1378}
11901379
1191TEST_F(MediaStoreTest, brokenFiles) {1380TEST(MediaStoreTest, listArtists) {
1381 MediaFile audio1 = MediaFileBuilder("/home/username/Music/track1.ogg")
1382 .setType(AudioMedia)
1383 .setTitle("TitleOne")
1384 .setAuthor("ArtistOne")
1385 .setAlbum("AlbumOne")
1386 .setTrackNumber(1);
1387 MediaFile audio2 = MediaFileBuilder("/home/username/Music/track3.ogg")
1388 .setType(AudioMedia)
1389 .setTitle("TitleThree")
1390 .setAuthor("ArtistOne")
1391 .setAlbum("AlbumTwo");
1392 MediaFile audio3 = MediaFileBuilder("/home/username/Music/track4.ogg")
1393 .setType(AudioMedia)
1394 .setTitle("TitleFour")
1395 .setAuthor("ArtistTwo")
1396 .setAlbum("AlbumThree");
1397 MediaFile audio4 = MediaFileBuilder("/home/username/Music/track5.ogg")
1398 .setType(AudioMedia)
1399 .setTitle("TitleFive")
1400 .setAuthor("ArtistOne")
1401 .setAlbum("AlbumFour")
1402 .setAlbumArtist("Various Artists")
1403 .setTrackNumber(1);
1404 MediaFile audio5 = MediaFileBuilder("/home/username/Music/track6.ogg")
1405 .setType(AudioMedia)
1406 .setTitle("TitleSix")
1407 .setAuthor("ArtistTwo")
1408 .setAlbum("AlbumFour")
1409 .setAlbumArtist("Various Artists")
1410 .setTrackNumber(2);
1411
1412 MediaStore store(TEST_DIR "/mediastore.db", MS_READ_WRITE);
1413 store.insert(audio1);
1414 store.insert(audio2);
1415 store.insert(audio3);
1416 store.insert(audio4);
1417 store.insert(audio5);
1418
1419 check_list_artists(store);
1420
1421 MediaStore store_ro(TEST_DIR "/mediastore.db", MS_READ_ONLY);
1422 check_list_artists(store_ro);
1423
1424 store.remove(audio1.getFileName());
1425 store.remove(audio2.getFileName());
1426 store.remove(audio3.getFileName());
1427 store.remove(audio4.getFileName());
1428 store.remove(audio5.getFileName());
1429}
1430
1431TEST(MediaStoreTest, brokenFiles) {
1192 MediaStore store(":memory:", MS_READ_WRITE);1432 MediaStore store(":memory:", MS_READ_WRITE);
1193 std::string file = "/foo/bar/baz.mp3";1433 std::string file = "/foo/bar/baz.mp3";
1194 std::string other_file = "/foo/bar/abc.mp3";1434 std::string other_file = "/foo/bar/abc.mp3";
@@ -1214,6 +1454,12 @@
1214}1454}
12151455
1216int main(int argc, char **argv) {1456int main(int argc, char **argv) {
1457 QCoreApplication app(argc, argv);
1458
1459 MediaScannerTestUtils::DBusTest test;
1460 test.SetUp();
1217 ::testing::InitGoogleTest(&argc, argv);1461 ::testing::InitGoogleTest(&argc, argv);
1218 return RUN_ALL_TESTS();1462 auto ret_code=RUN_ALL_TESTS();
1463 std::cout << "WE'LL SEE NOW SOME ERRORS WHEN DESTROYING THE D-BUS INTERNALS. This is due bug: https://bugs.launchpad.net/dbus-cpp/+bug/1422304" << std::endl;
1464 return ret_code;
1219}1465}
12201466
=== added directory 'test/utils'
=== added file 'test/utils/DBusTest.cpp'
--- test/utils/DBusTest.cpp 1970-01-01 00:00:00 +0000
+++ test/utils/DBusTest.cpp 2015-02-16 14:24:40 +0000
@@ -0,0 +1,50 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Pete Woods <pete.woods@canonical.com>
17 */
18
19#include "DBusTest.h"
20#include "test_config.h"
21
22#include <QtTest/QSignalSpy>
23#include <libqtdbustest/QProcessDBusService.h>
24#include <QtDBus/QtDBus>
25
26using namespace MediaScannerTestUtils;
27using namespace QtDBusTest;
28
29DBusTest::DBusTest() {
30 qputenv("MEDIASCANNER_CACHEDIR", TEST_DIR);
31 DBusServicePtr dBusService(
32 new QProcessDBusService("com.canonical.MediaScanner2",
33 QDBusConnection::SessionBus, MS_DBUS_BINARY,
34 QStringList()));
35 dbus.registerService(dBusService);
36}
37
38DBusTest::~DBusTest() {
39}
40
41void DBusTest::SetUp() {
42 dbus.startServices();
43}
44
45void DBusTest::TearDown() {
46}
47
48const QDBusConnection & DBusTest::systemConnection() const {
49 return dbus.systemConnection();
50}
051
=== added file 'test/utils/DBusTest.h'
--- test/utils/DBusTest.h 1970-01-01 00:00:00 +0000
+++ test/utils/DBusTest.h 2015-02-16 14:24:40 +0000
@@ -0,0 +1,47 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Pete Woods <pete.woods@canonical.com>
17 */
18
19#include <QtCore/QCoreApplication>
20#include <QtCore/QProcess>
21
22#include <QtDBus/QtDBus>
23
24#include <libqtdbustest/DBusTestRunner.h>
25
26#ifndef USERMETRICS_TESTUTILS_TESTCOMMON_H_
27#define USERMETRICS_TESTUTILS_TESTCOMMON_H_
28
29namespace MediaScannerTestUtils {
30
31class DBusTest {
32public:
33 DBusTest();
34
35 virtual ~DBusTest();
36
37 virtual void SetUp();
38
39 virtual void TearDown();
40
41 QtDBusTest::DBusTestRunner dbus;
42
43 virtual const QDBusConnection & systemConnection() const;
44};
45
46}
47#endif // USERMETRICS_TESTUTILS_TESTCOMMON_H_

Subscribers

People subscribed via source and target branches

to all changes: