MediaTests.cpp 23 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

23 24 25 26
#if HAVE_CONFIG_H
# include "config.h"
#endif

27
#include "Tests.h"
28

29
#include "medialibrary/IMediaLibrary.h"
30
#include "File.h"
31
#include "Media.h"
32 33 34
#include "Artist.h"
#include "Album.h"
#include "AlbumTrack.h"
35
#include "mocks/FileSystem.h"
36
#include "mocks/DiscovererCbMock.h"
37
#include "compat/Thread.h"
38
#include "Playlist.h"
39

40
class Medias : public Tests
41 42 43 44
{
};


45
TEST_F( Medias, Init )
46 47 48 49
{
    // only test for correct test fixture behavior
}

50
TEST_F( Medias, Create )
51
{
52 53 54 55 56 57 58 59
    auto m = ml->addFile( "media.avi" );
    ASSERT_NE( m, nullptr );

    ASSERT_EQ( m->playCount(), 0 );
    ASSERT_EQ( m->albumTrack(), nullptr );
    ASSERT_EQ( m->showEpisode(), nullptr );
    ASSERT_EQ( m->duration(), -1 );
    ASSERT_NE( 0u, m->insertionDate() );
60 61 62 63 64

    auto files = m->files();
    ASSERT_EQ( 1u, files.size() );
    auto f = files[0];
    ASSERT_FALSE( f->isExternal() );
65
    ASSERT_EQ( File::Type::Main, f->type() );
66 67
}

68
TEST_F( Medias, Fetch )
69
{
70
    auto f = ml->addMedia( "media.avi" );
71 72
    auto f2 = ml->media( f->id() );
    ASSERT_EQ( f->id(), f2->id() );
73
    ASSERT_EQ( f, f2 );
74 75

    // Flush cache and fetch from DB
76
    Reload();
77

78
    f2 = std::static_pointer_cast<Media>( ml->media( f->id() ) );
79
    ASSERT_EQ( f->id(), f2->id() );
80
}
81

82
TEST_F( Medias, Duration )
83
{
84
    auto f = std::static_pointer_cast<Media>( ml->addMedia( "media.avi" ) );
85
    ASSERT_EQ( f->duration(), -1 );
86

87 88 89 90
    // Use a value that checks we're using a 64bits value
    int64_t d = int64_t(1) << 40;

    f->setDuration( d );
91
    f->save();
92
    ASSERT_EQ( f->duration(), d );
93 94 95

    Reload();

96
    auto f2 = ml->media( f->id() );
97
    ASSERT_EQ( f2->duration(), d );
98
}
99

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
100
TEST_F( Medias, Thumbnail )
101
{
102
    auto f = std::static_pointer_cast<Media>( ml->addMedia( "media.avi" ) );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
103
    ASSERT_EQ( f->thumbnail(), "" );
104

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
105
    std::string newThumbnail( "/path/to/thumbnail" );
106

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
107
    f->setThumbnail( newThumbnail );
108
    f->save();
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
109
    ASSERT_EQ( f->thumbnail(), newThumbnail );
110 111 112

    Reload();

113
    auto f2 = ml->media( f->id() );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
114
    ASSERT_EQ( f2->thumbnail(), newThumbnail );
115
}
116 117 118

TEST_F( Medias, PlayCount )
{
119
    auto f = std::static_pointer_cast<Media>( ml->addMedia( "media.avi" ) );
120 121 122 123 124 125
    ASSERT_EQ( 0, f->playCount() );
    f->increasePlayCount();
    ASSERT_EQ( 1, f->playCount() );

    Reload();

126
    f = std::static_pointer_cast<Media>( ml->media( f->id() ) );
127 128
    ASSERT_EQ( 1, f->playCount() );
}
129 130 131

TEST_F( Medias, Progress )
{
132
    auto f = std::static_pointer_cast<Media>( ml->addMedia( "media.avi" ) );
133 134 135
    ASSERT_EQ( 0, f->metadata( Media::MetadataType::Progress ).integer() );
    f->setMetadata( Media::MetadataType::Progress, 123 );
    ASSERT_EQ( 123, f->metadata( Media::MetadataType::Progress ).integer() );
136
    ASSERT_TRUE( f->metadata( Media::MetadataType::Progress ).isSet() );
137 138 139 140

    Reload();

    f = ml->media( f->id() );
141
    ASSERT_EQ( 123, f->metadata( Media::MetadataType::Progress ).integer() );
142 143 144 145
}

TEST_F( Medias, Rating )
{
146
    auto f = std::static_pointer_cast<Media>( ml->addMedia( "media.avi" ) );
147 148 149
    ASSERT_FALSE( f->metadata( Media::MetadataType::Rating ).isSet() );
    f->setMetadata( Media::MetadataType::Rating, 12345 );
    ASSERT_EQ( 12345, f->metadata( Media::MetadataType::Rating ).integer() );
150
    ASSERT_TRUE( f->metadata( Media::MetadataType::Rating ).isSet() );
151 152 153 154

    Reload();

    f = ml->media( f->id() );
155
    ASSERT_EQ( 12345, f->metadata( Media::MetadataType::Rating ).integer() );
156
}
157 158 159 160 161

TEST_F( Medias, Search )
{
    for ( auto i = 1u; i <= 10u; ++i )
    {
162 163 164 165
        auto m = std::static_pointer_cast<Media>(
                    ml->addMedia( "track " + std::to_string( i ) + ".mp3" ) );
        m->setType( IMedia::Type::Video );
        m->save();
166
    }
167
    auto media = ml->searchMedia( "tra", nullptr )->all();
168 169
    ASSERT_EQ( 10u, media.size() );

170
    media = ml->searchMedia( "track 1", nullptr )->all();
171 172
    ASSERT_EQ( 2u, media.size() );

173
    media = ml->searchMedia( "grouik", nullptr )->all();
174 175
    ASSERT_EQ( 0u, media.size() );

176
    media = ml->searchMedia( "rack", nullptr )->all();
177 178 179
    ASSERT_EQ( 0u, media.size() );
}

180 181 182 183 184 185
TEST_F( Medias, SearchAndSort )
{
    for ( auto i = 1u; i <= 3u; ++i )
    {
        auto m = std::static_pointer_cast<Media>(
                    ml->addMedia( "track " + std::to_string( i ) + ".mp3" ) );
186
        m->setType( IMedia::Type::Audio );
187 188 189
        m->setDuration( 3 - i );
        m->save();
    }
190 191 192
    auto m = std::static_pointer_cast<Media>( ml->addMedia( "this pattern doesn't match.mp3" ) );
    m->setType( IMedia::Type::Audio );
    m->save();
193

194
    auto media = ml->searchMedia( "tra", nullptr )->all();
195 196 197 198 199
    ASSERT_EQ( 3u, media.size() );
    ASSERT_EQ( media[0]->title(), "track 1.mp3" );
    ASSERT_EQ( media[1]->title(), "track 2.mp3" );
    ASSERT_EQ( media[2]->title(), "track 3.mp3" );

200
    QueryParameters params { SortingCriteria::Duration, false };
201
    media = ml->searchMedia( "tra", &params )->all();
202 203 204 205 206 207
    ASSERT_EQ( 3u, media.size() );
    ASSERT_EQ( media[0]->title(), "track 3.mp3" );
    ASSERT_EQ( media[1]->title(), "track 2.mp3" );
    ASSERT_EQ( media[2]->title(), "track 1.mp3" );
}

208 209
TEST_F( Medias, SearchAfterEdit )
{
210
    auto m = std::static_pointer_cast<Media>( ml->addMedia( "media.mp3" ) );
211 212
    m->setType( IMedia::Type::Audio );
    m->save();
213

214
    auto media = ml->searchMedia( "media", nullptr )->all();
215 216
    ASSERT_EQ( 1u, media.size() );

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
217
    m->setTitleBuffered( "otters are awesome" );
218 219
    m->save();

220
    media = ml->searchMedia( "media", nullptr )->all();
221 222
    ASSERT_EQ( 0u, media.size() );

223
    media = ml->searchMedia( "otters", nullptr )->all();
224 225 226 227 228
    ASSERT_EQ( 1u, media.size() );
}

TEST_F( Medias, SearchAfterDelete )
{
229
    auto m = std::static_pointer_cast<Media>( ml->addMedia( "media.mp3" ) );
230 231
    m->setType( IMedia::Type::Audio );
    m->save();
232

233
    auto media = ml->searchMedia( "media", nullptr )->all();
234 235 236 237 238
    ASSERT_EQ( 1u, media.size() );

    auto f = m->files()[0];
    m->removeFile( static_cast<File&>( *f ) );

239
    media = ml->searchMedia( "media", nullptr )->all();
240 241
    ASSERT_EQ( 0u, media.size() );
}
242 243 244

TEST_F( Medias, SearchByLabel )
{
245
    auto m = std::static_pointer_cast<Media>( ml->addMedia( "media.mkv" ) );
246 247
    m->setType( IMedia::Type::Video );
    m->save();
248
    auto media = ml->searchMedia( "otter", nullptr )->all();
249 250 251 252 253
    ASSERT_EQ( 0u, media.size() );

    auto l = ml->createLabel( "otter" );
    m->addLabel( l );

254
    media = ml->searchMedia( "otter", nullptr )->all();
255 256 257 258 259
    ASSERT_EQ( 1u, media.size() );

    auto l2 = ml->createLabel( "pangolins" );
    m->addLabel( l2 );

260
    media = ml->searchMedia( "otter", nullptr )->all();
261 262
    ASSERT_EQ( 1u, media.size() );

263
    media = ml->searchMedia( "pangolin", nullptr )->all();
264 265 266 267
    ASSERT_EQ( 1u, media.size() );

    m->removeLabel( l );

268
    media = ml->searchMedia( "otter", nullptr )->all();
269 270
    ASSERT_EQ( 0u, media.size() );

271
    media = ml->searchMedia( "pangolin", nullptr )->all();
272 273 274 275
    ASSERT_EQ( 1u, media.size() );

    m->addLabel( l );

276
    media = ml->searchMedia( "otter", nullptr )->all();
277 278
    ASSERT_EQ( 1u, media.size() );

279
    media = ml->searchMedia( "pangolin", nullptr )->all();
280 281 282 283
    ASSERT_EQ( 1u, media.size() );

    ml->deleteLabel( l );

284
    media = ml->searchMedia( "otter", nullptr )->all();
285 286
    ASSERT_EQ( 0u, media.size() );

287
    media = ml->searchMedia( "pangolin", nullptr )->all();
288 289
    ASSERT_EQ( 1u, media.size() );
}
290 291 292 293 294 295

TEST_F( Medias, SearchTracks )
{
    auto a = ml->createAlbum( "album" );
    for ( auto i = 1u; i <= 10u; ++i )
    {
296
       auto m = std::static_pointer_cast<Media>( ml->addMedia( "track " + std::to_string( i ) + ".mp3" ) );
297
       a->addTrack( m, i, 1, 0, 0 );
298
       m->setType( IMedia::Type::Audio );
299
       m->save();
300
    }
301
    auto tracks = ml->searchMedia( "tra", nullptr )->all();
302 303
    ASSERT_EQ( 10u, tracks.size() );

304
    tracks = ml->searchMedia( "track 1", nullptr )->all();
305 306
    ASSERT_EQ( 2u, tracks.size() );

307
    tracks = ml->searchMedia( "grouik", nullptr )->all();
308 309
    ASSERT_EQ( 0u, tracks.size() );

310
    tracks = ml->searchMedia( "rack", nullptr )->all();
311 312
    ASSERT_EQ( 0u, tracks.size() );
}
313 314 315

TEST_F( Medias, Favorite )
{
316 317 318
    auto m = std::static_pointer_cast<Media>( ml->addMedia( "media.mkv" ) );
    m->setType( IMedia::Type::Video );
    m->save();
319 320 321 322 323 324 325 326 327 328
    ASSERT_FALSE( m->isFavorite() );

    m->setFavorite( true );
    ASSERT_TRUE( m->isFavorite() );

    Reload();

    m = ml->media( m->id() );
    ASSERT_TRUE( m->isFavorite() );
}
329 330 331

TEST_F( Medias, History )
{
332
    auto m = std::static_pointer_cast<Media>( ml->addMedia( "media.mkv" ) );
333

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
334
    auto history = ml->history()->all();
335 336 337 338
    ASSERT_EQ( 0u, history.size() );

    m->increasePlayCount();
    m->save();
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
339
    history = ml->history()->all();
340 341 342
    ASSERT_EQ( 1u, history.size() );
    ASSERT_EQ( m->id(), history[0]->id() );

343
    compat::this_thread::sleep_for( std::chrono::seconds{ 1 } );
344
    auto m2 = std::static_pointer_cast<Media>( ml->addMedia( "media2.mkv" ) );
345 346
    m2->increasePlayCount();

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
347
    history = ml->history()->all();
348 349 350 351
    ASSERT_EQ( 2u, history.size() );
    ASSERT_EQ( m2->id(), history[0]->id() );
    ASSERT_EQ( m->id(), history[1]->id() );
}
352

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
TEST_F( Medias, StreamHistory )
{
    auto m1 = std::static_pointer_cast<Media>( ml->addStream( "http://media.org/sample.mkv" ) );
    auto m2 = std::static_pointer_cast<Media>( ml->addStream( "http://media.org/sample2.mkv" ) );
    auto m3 = std::static_pointer_cast<Media>( ml->addMedia( "localfile.mkv" ) );

    m1->increasePlayCount();
    m2->increasePlayCount();
    m3->increasePlayCount();

    auto history = ml->streamHistory()->all();
    ASSERT_EQ( 2u, history.size() );

    history = ml->history()->all();
    ASSERT_EQ( 1u, history.size() );
}

370 371
TEST_F( Medias, ClearHistory )
{
372
    auto m = std::static_pointer_cast<Media>( ml->addMedia( "media.mkv" ) );
373

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
374
    auto history = ml->history()->all();
375 376 377 378
    ASSERT_EQ( 0u, history.size() );

    m->increasePlayCount();
    m->save();
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
379
    history = ml->history()->all();
380 381 382 383
    ASSERT_EQ( 1u, history.size() );

    ASSERT_TRUE( ml->clearHistory() );

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
384
    history = ml->history()->all();
385 386 387 388
    ASSERT_EQ( 0u, history.size() );

    Reload();

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
389
    history = ml->history()->all();
390 391 392
    ASSERT_EQ( 0u, history.size() );
}

393 394
TEST_F( Medias, SetReleaseDate )
{
395
    auto m = std::static_pointer_cast<Media>( ml->addMedia( "movie.mkv" ) );
396 397 398 399 400 401 402 403 404 405 406

    ASSERT_EQ( m->releaseDate(), 0u );
    m->setReleaseDate( 1234 );
    m->save();
    ASSERT_EQ( m->releaseDate(), 1234u );

    Reload();

    auto m2 = ml->media( m->id() );
    ASSERT_EQ( m2->releaseDate(), 1234u );
}
407 408 409

TEST_F( Medias, SortByAlpha )
{
410
    auto m1 = std::static_pointer_cast<Media>( ml->addMedia( "media1.mp3" ) );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
411
    m1->setTitleBuffered( "Abcd" );
412
    m1->setType( Media::Type::Audio );
413 414
    m1->save();

415
    auto m2 = std::static_pointer_cast<Media>( ml->addMedia( "media2.mp3" ) );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
416
    m2->setTitleBuffered( "Zyxw" );
417
    m2->setType( Media::Type::Audio );
418 419
    m2->save();

420
    auto m3 = std::static_pointer_cast<Media>( ml->addMedia( "media3.mp3" ) );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
421
    m3->setTitleBuffered( "afterA-beforeZ" );
422
    m3->setType( Media::Type::Audio );
423 424
    m3->save();

425 426
    QueryParameters params { SortingCriteria::Alpha, false };
    auto media = ml->audioFiles( &params )->all();
427
    ASSERT_EQ( 3u, media.size() );
428
    ASSERT_EQ( m1->id(), media[0]->id() );
429 430
    ASSERT_EQ( m3->id(), media[1]->id() );
    ASSERT_EQ( m2->id(), media[2]->id() );
431

432 433
    params.desc = true;
    media = ml->audioFiles( &params )->all();
434
    ASSERT_EQ( 3u, media.size() );
435
    ASSERT_EQ( m2->id(), media[0]->id() );
436 437
    ASSERT_EQ( m3->id(), media[1]->id() );
    ASSERT_EQ( m1->id(), media[2]->id() );
438 439 440 441 442 443
}

TEST_F( Medias, SortByLastModifDate )
{
    auto file1 = std::make_shared<mock::NoopFile>( "media.mkv" );
    file1->setLastModificationDate( 666 );
444
    auto m1 = ml->addFile( file1 );
445
    m1->setType( Media::Type::Video );
446
    m1->save();
447 448 449

    auto file2 = std::make_shared<mock::NoopFile>( "media2.mkv" );
    file2->setLastModificationDate( 111 );
450
    auto m2 = ml->addFile( file2 );
451
    m2->setType( Media::Type::Video );
452
    m2->save();
453

454 455
    QueryParameters params { SortingCriteria::LastModificationDate, false };
    auto media = ml->videoFiles( &params )->all();
456 457 458 459
    ASSERT_EQ( 2u, media.size() );
    ASSERT_EQ( m2->id(), media[0]->id() );
    ASSERT_EQ( m1->id(), media[1]->id() );

460 461
    params.desc = true;
    media = ml->videoFiles( &params )->all();
462 463 464 465
    ASSERT_EQ( 2u, media.size() );
    ASSERT_EQ( m2->id(), media[1]->id() );
    ASSERT_EQ( m1->id(), media[0]->id() );
}
466

467 468 469 470
TEST_F( Medias, SortByFileSize )
{
    auto file1 = std::make_shared<mock::NoopFile>( "media.mkv" );
    file1->setSize( 666 );
471
    auto m1 = ml->addFile( file1 );
472
    m1->setType( Media::Type::Video );
473
    m1->save();
474 475 476

    auto file2 = std::make_shared<mock::NoopFile>( "media2.mkv" );
    file2->setSize( 111 );
477
    auto m2 = ml->addFile( file2 );
478
    m2->setType( Media::Type::Video );
479
    m2->save();
480

481 482
    QueryParameters params { SortingCriteria::FileSize, false };
    auto media = ml->videoFiles( &params )->all();
483 484 485 486
    ASSERT_EQ( 2u, media.size() );
    ASSERT_EQ( m2->id(), media[0]->id() );
    ASSERT_EQ( m1->id(), media[1]->id() );

487 488
    params.desc = true;
    media = ml->videoFiles( &params )->all();
489 490 491 492 493
    ASSERT_EQ( 2u, media.size() );
    ASSERT_EQ( m2->id(), media[1]->id() );
    ASSERT_EQ( m1->id(), media[0]->id() );
}

494 495 496 497 498 499 500 501 502 503 504 505
TEST_F( Medias, SortByFilename )
{
    auto m1 = std::static_pointer_cast<Media>( ml->addMedia( "zzzzz.mp3" ) );
    m1->setType( Media::Type::Video );
    m1->setTitle( "aaaaa" );
    m1->save();

    auto m2 = std::static_pointer_cast<Media>( ml->addMedia( "aaaaa.mp3" ) );
    m2->setType( Media::Type::Video );
    m2->setTitle( "zzzzz" );
    m2->save();

506 507
    QueryParameters params { SortingCriteria::Filename, false };
    auto media = ml->videoFiles( &params )->all();
508 509 510 511
    ASSERT_EQ( 2u, media.size() );
    ASSERT_EQ( m2->id(), media[0]->id() );
    ASSERT_EQ( m1->id(), media[1]->id() );

512 513
    params.desc = true;
    media = ml->videoFiles( &params )->all();
514 515 516 517 518
    ASSERT_EQ( 2u, media.size() );
    ASSERT_EQ( m2->id(), media[1]->id() );
    ASSERT_EQ( m1->id(), media[0]->id() );
}

519 520
TEST_F( Medias, SetType )
{
521
    auto m1 = std::static_pointer_cast<Media>( ml->addMedia( "media1.mp3" ) );
522
    ASSERT_EQ( IMedia::Type::External, m1->type() );
523

524
    m1->setType( IMedia::Type::Video );
525 526
    m1->save();

527
    ASSERT_EQ( IMedia::Type::Video, m1->type() );
528 529 530 531

    Reload();

    auto m2 = ml->media( m1->id() );
532
    ASSERT_EQ( IMedia::Type::Video, m2->type() );
533
}
534

535 536
TEST_F( Medias, Metadata )
{
537
    auto m = ml->addMedia( "media.mp3" );
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560

    {
        const auto& md = m->metadata( Media::MetadataType::Speed );
        ASSERT_FALSE( md.isSet() );
    }

    auto res = m->setMetadata( Media::MetadataType::Speed, "foo" );
    ASSERT_TRUE( res );

    {
        const auto& md = m->metadata( Media::MetadataType::Speed );
        ASSERT_EQ( "foo", md.str() );
    }

    Reload();

    m = ml->media( m->id() );
    const auto& md = m->metadata( Media::MetadataType::Speed );
    ASSERT_EQ( "foo", md.str() );
}

TEST_F( Medias, MetadataOverride )
{
561
    auto m = ml->addMedia( "media.mp3" );
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
    auto res = m->setMetadata( Media::MetadataType::Speed, "foo" );
    ASSERT_TRUE( res );

    m->setMetadata( Media::MetadataType::Speed, "otter" );
    {
        const auto& md = m->metadata( Media::MetadataType::Speed );
        ASSERT_EQ( "otter", md.str() );
    }

    Reload();

    m = ml->media( m->id() );
    const auto& md = m->metadata( Media::MetadataType::Speed );
    ASSERT_EQ( "otter", md.str() );
}

578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
TEST_F( Medias, MetadataUnset )
{
    auto m = ml->addMedia( "media.mp3" );
    auto res = m->unsetMetadata( Media::MetadataType::ApplicationSpecific );
    ASSERT_TRUE( res );

    res = m->setMetadata( Media::MetadataType::ApplicationSpecific, "otters" );
    ASSERT_TRUE( res );

    auto& md = m->metadata( Media::MetadataType::ApplicationSpecific );
    ASSERT_TRUE( md.isSet() );
    ASSERT_EQ( "otters", md.str() );

    res = m->unsetMetadata( Media::MetadataType::ApplicationSpecific );
    ASSERT_TRUE( res );

    ASSERT_FALSE( md.isSet() );

    Reload();

    m = ml->media( m->id() );
    auto& md2 = m->metadata( Media::MetadataType::ApplicationSpecific );
    ASSERT_FALSE( md2.isSet() );
}

603 604
TEST_F( Medias, ExternalMrl )
{
605
    auto m = ml->addExternalMedia( "https://foo.bar/sea-otters.mkv" );
606 607 608 609 610
    ASSERT_NE( nullptr, m );

    ASSERT_EQ( m->title(), "sea-otters.mkv" );

    // External files shouldn't appear in listings
611
    auto videos = ml->videoFiles( nullptr )->all();
612 613
    ASSERT_EQ( 0u, videos.size() );

614
    auto audios = ml->audioFiles( nullptr )->all();
615 616 617 618 619 620 621
    ASSERT_EQ( 0u, audios.size() );

    Reload();

    auto m2 = ml->media( "https://foo.bar/sea-otters.mkv" );
    ASSERT_NE( nullptr, m2 );
    ASSERT_EQ( m->id(), m2->id() );
622 623 624 625 626 627

    auto files = m2->files();
    ASSERT_EQ( 1u, files.size() );
    auto f = files[0];
    ASSERT_TRUE( f->isExternal() );
    ASSERT_EQ( File::Type::Main, f->type() );
628 629
}

630 631
TEST_F( Medias, DuplicatedExternalMrl )
{
632 633
    auto m = ml->addExternalMedia( "http://foo.bar" );
    auto m2 = ml->addExternalMedia( "http://foo.bar" );
634 635 636 637
    ASSERT_NE( nullptr, m );
    ASSERT_EQ( nullptr, m2 );
}

638 639 640 641 642 643 644 645 646 647 648 649 650 651
TEST_F( Medias, SetTitle )
{
    auto m = ml->addMedia( "media" );
    ASSERT_EQ( "media", m->title() );
    auto res = m->setTitle( "sea otters" );
    ASSERT_TRUE( res );
    ASSERT_EQ( "sea otters", m->title() );

    Reload();

    m = ml->media( m->id() );
    ASSERT_EQ( "sea otters", m->title() );
}

652 653 654 655 656 657 658 659 660
TEST_F( Medias, Pagination )
{
    for ( auto i = 1u; i <= 9u; ++i )
    {
       auto m = std::static_pointer_cast<Media>( ml->addMedia( "track " + std::to_string( i ) + ".mp3" ) );
       m->setType( IMedia::Type::Video );
       m->save();
    }

661
    auto allMedia = ml->videoFiles( nullptr )->all();
662 663
    ASSERT_EQ( 9u, allMedia.size() );

664
    auto paginator = ml->videoFiles( nullptr );
665 666 667 668 669 670 671 672 673 674 675 676
    auto media = paginator->items( 1, 0 );
    int i = 0u;
    while( media.size() > 0 )
    {
        // Offset starts from 0; ids from 1
        ASSERT_EQ( 1u, media.size() );
        ASSERT_EQ( i + 1, media[0]->id() );
        ++i;
        media = paginator->items( 1, i );
    }
}

677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
TEST_F( Medias, SortFilename )
{
    auto m1 = std::static_pointer_cast<Media>( ml->addMedia( "AAAAB.mp3" ) );
    m1->setType( IMedia::Type::Audio );
    m1->save();

    auto m2 = std::static_pointer_cast<Media>( ml->addMedia( "aaaaa.mp3" ) );
    m2->setType( IMedia::Type::Audio );
    m2->save();

    auto m3 = std::static_pointer_cast<Media>( ml->addMedia( "BbBbB.mp3" ) );
    m3->setType( IMedia::Type::Audio );
    m3->save();

    QueryParameters params { SortingCriteria::Filename, false };
    auto media = ml->audioFiles( &params )->all();
    ASSERT_EQ( 3u, media.size() );
    ASSERT_EQ( m2->id(), media[0]->id() );
    ASSERT_EQ( m1->id(), media[1]->id() );
    ASSERT_EQ( m3->id(), media[2]->id() );

    params.desc = true;
    media = ml->audioFiles( &params )->all();
    ASSERT_EQ( 3u, media.size() );
    ASSERT_EQ( m2->id(), media[2]->id() );
    ASSERT_EQ( m1->id(), media[1]->id() );
    ASSERT_EQ( m3->id(), media[0]->id() );
}

706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
TEST_F( Medias, CreateStream )
{
    auto m1 = ml->addStream( "http://foo.bar/media.mkv" );
    ASSERT_EQ( IMedia::Type::Stream, m1->type() );
}

TEST_F( Medias, SearchExternal )
{
    auto m1 = std::static_pointer_cast<Media>( ml->addExternalMedia( "localfile.mkv" ) );
    m1->setTitle( "local otter" );
    auto m2 = std::static_pointer_cast<Media>( ml->addStream( "http://remote.file/media.asf" ) );
    m2->setTitle( "remote otter" );

    auto media = ml->searchMedia( "otter", nullptr )->all();
    ASSERT_EQ( 0u, media.size() );

    m1->setType( IMedia::Type::Video );
    m1->save();
    m2->setType( IMedia::Type::Video );
    m2->save();

    media = ml->searchMedia( "otter", nullptr )->all();
    ASSERT_EQ( 2u, media.size() );
}

731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
TEST_F( Medias, VacuumOldExternal )
{
    auto m1 = ml->addExternalMedia( "foo.avi" );
    auto m2 = ml->addExternalMedia( "bar.mp3" );
    auto s1 = ml->addStream( "http://baz.mkv" );

    auto playlist = ml->createPlaylist( "playlist" );
    playlist->append( *m1 );

    ml->outdateAllExternalMedia();

    Reload();

    m1 = ml->media( m1->id() );
    m2 = ml->media( m2->id() );
    s1 = ml->media( s1->id() );

    ASSERT_NE( nullptr, m1 );
    ASSERT_EQ( nullptr, m2 );
    ASSERT_EQ( nullptr, s1 );
}

753 754 755 756 757 758 759 760 761 762 763 764 765
class FetchMedia : public Tests
{
protected:
    static const std::string RemovableDeviceUuid;
    static const std::string RemovableDeviceMountpoint;
    std::shared_ptr<mock::FileSystemFactory> fsMock;
    std::unique_ptr<mock::WaitForDiscoveryComplete> cbMock;

    virtual void SetUp() override
    {
        unlink( "test.db" );
        fsMock.reset( new mock::FileSystemFactory );
        cbMock.reset( new mock::WaitForDiscoveryComplete );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
766
        fsMock->addFolder( "file:///a/mnt/" );
767 768 769 770 771 772 773 774
        auto device = fsMock->addDevice( RemovableDeviceMountpoint, RemovableDeviceUuid );
        device->setRemovable( true );
        fsMock->addFile( RemovableDeviceMountpoint + "removablefile.mp3" );
        Reload();
    }

    virtual void InstantiateMediaLibrary() override
    {
775
        ml.reset( new MediaLibraryWithDiscoverer );
776 777 778 779 780 781 782 783 784
    }

    virtual void Reload()
    {
        Tests::Reload( fsMock, cbMock.get() );
    }
};

const std::string FetchMedia::RemovableDeviceUuid = "{fake-removable-device}";
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
785
const std::string FetchMedia::RemovableDeviceMountpoint = "file:///a/mnt/fake-device/";
786 787 788 789

TEST_F( FetchMedia, FetchNonRemovable )
{
    ml->discover( mock::FileSystemFactory::Root );
790
    bool discovered = cbMock->waitDiscovery();
791 792 793 794 795 796 797 798 799
    ASSERT_TRUE( discovered );

    auto m = ml->media( mock::FileSystemFactory::SubFolder + "subfile.mp4" );
    ASSERT_NE( nullptr, m );
}

TEST_F( FetchMedia, FetchRemovable )
{
    ml->discover( mock::FileSystemFactory::Root );
800
    bool discovered = cbMock->waitDiscovery();
801 802 803 804 805 806 807 808 809
    ASSERT_TRUE( discovered );

    auto m = ml->media( RemovableDeviceMountpoint + "removablefile.mp3" );
    ASSERT_NE( nullptr, m );
}

TEST_F( FetchMedia, FetchRemovableUnplugged )
{
    ml->discover( mock::FileSystemFactory::Root );
810
    bool discovered = cbMock->waitDiscovery();
811 812 813 814 815
    ASSERT_TRUE( discovered );

    fsMock->unmountDevice( RemovableDeviceUuid );

    Reload();
816
    bool reloaded = cbMock->waitReload();
817 818 819 820 821
    ASSERT_TRUE( reloaded );

    auto m = ml->media( RemovableDeviceMountpoint + "removablefile.mp3" );
    ASSERT_EQ( nullptr, m );
}