133 lines
4.5 KiB
C++
133 lines
4.5 KiB
C++
// SPDX-FileCopyrightText: 2026 Tri Vo Khac
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include "playlistmodel.h"
|
|
|
|
#include <QFile>
|
|
#include <QProcess>
|
|
#include <QSignalSpy>
|
|
#include <QStandardPaths>
|
|
#include <QTemporaryDir>
|
|
#include <QTest>
|
|
|
|
using namespace Qt::Literals::StringLiterals;
|
|
|
|
class PlaylistModelTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private:
|
|
static void touch(const QTemporaryDir &dir, const QString &name)
|
|
{
|
|
QFile file(dir.filePath(name));
|
|
QVERIFY(file.open(QIODevice::WriteOnly));
|
|
}
|
|
|
|
static QStringList names(const PlaylistModel &model)
|
|
{
|
|
QStringList result;
|
|
for (int i = 0; i < model.rowCount(); ++i) {
|
|
result.append(model.data(model.index(i), PlaylistModel::NameRole).toString());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private Q_SLOTS:
|
|
void sortsEpisodesNaturallyAndSkipsOtherFiles()
|
|
{
|
|
QTemporaryDir dir;
|
|
for (const QString &name : {u"Show - 10.mkv"_s, u"show - 2.mkv"_s, u"Show - 1.mkv"_s, u"notes.txt"_s, u"Show - 1.srt"_s, u"theme.mp3"_s}) {
|
|
touch(dir, name);
|
|
}
|
|
|
|
const QList<QUrl> urls = PlaylistModel::mediaFilesIn(dir.path());
|
|
QStringList fileNames;
|
|
for (const QUrl &url : urls) {
|
|
fileNames.append(url.fileName());
|
|
}
|
|
QCOMPARE(fileNames, (QStringList{u"Show - 1.mkv"_s, u"show - 2.mkv"_s, u"Show - 10.mkv"_s, u"theme.mp3"_s}));
|
|
}
|
|
|
|
void openFileLoadsSiblingsAndPlaysTheFile()
|
|
{
|
|
QTemporaryDir dir;
|
|
for (const QString &name : {u"Ep 1.mkv"_s, u"Ep 2.mkv"_s, u"Ep 3.mkv"_s}) {
|
|
touch(dir, name);
|
|
}
|
|
|
|
PlaylistModel model;
|
|
QSignalSpy played(&model, &PlaylistModel::playRequested);
|
|
const QUrl second = QUrl::fromLocalFile(dir.filePath(u"Ep 2.mkv"_s));
|
|
model.openFile(second, true);
|
|
|
|
QCOMPARE(names(model), (QStringList{u"Ep 1.mkv"_s, u"Ep 2.mkv"_s, u"Ep 3.mkv"_s}));
|
|
QCOMPARE(model.playingIndex(), 1);
|
|
QCOMPARE(played.count(), 1);
|
|
QCOMPARE(played.first().first().toUrl(), second);
|
|
|
|
model.openFile(second, false);
|
|
QCOMPARE(names(model), (QStringList{u"Ep 2.mkv"_s}));
|
|
}
|
|
|
|
void nextAndPreviousStopAtTheEndsUnlessWrapping()
|
|
{
|
|
PlaylistModel model;
|
|
model.append({QUrl(u"https://example.com/a"_s), QUrl(u"https://example.com/b"_s)});
|
|
model.play(1);
|
|
|
|
QVERIFY(!model.playNext());
|
|
QCOMPARE(model.playingIndex(), 1);
|
|
QVERIFY(model.playNext(true));
|
|
QCOMPARE(model.playingIndex(), 0);
|
|
QVERIFY(!model.playPrevious());
|
|
QVERIFY(model.playPrevious(true));
|
|
QCOMPARE(model.playingIndex(), 1);
|
|
}
|
|
|
|
void playingIndexFollowsRemoveAndMove()
|
|
{
|
|
PlaylistModel model;
|
|
model.append({QUrl(u"https://example.com/a"_s), QUrl(u"https://example.com/b"_s), QUrl(u"https://example.com/c"_s)});
|
|
model.play(1);
|
|
|
|
model.move(1, 2);
|
|
QCOMPARE(model.playingIndex(), 2);
|
|
model.move(0, 2);
|
|
QCOMPARE(model.playingIndex(), 1);
|
|
model.remove(0);
|
|
QCOMPARE(model.playingIndex(), 0);
|
|
model.remove(0);
|
|
QCOMPARE(model.playingIndex(), -1);
|
|
QCOMPARE(model.count(), 1);
|
|
}
|
|
|
|
void titleAndDurationRoles()
|
|
{
|
|
const QString ffmpeg = QStandardPaths::findExecutable(u"ffmpeg"_s);
|
|
if (ffmpeg.isEmpty()) {
|
|
QSKIP("ffmpeg is needed to make a sample file");
|
|
}
|
|
QTemporaryDir dir;
|
|
const QString path = dir.filePath(u"Show.S01E02.The.Tone.1080p.WEB.mka"_s);
|
|
QProcess process;
|
|
process.start(ffmpeg, {u"-v"_s, u"error"_s, u"-f"_s, u"lavfi"_s, u"-i"_s, u"sine=duration=2"_s, path});
|
|
QVERIFY(process.waitForFinished());
|
|
QCOMPARE(process.exitCode(), 0);
|
|
|
|
PlaylistModel model;
|
|
QSignalSpy changed(&model, &QAbstractItemModel::dataChanged);
|
|
model.append({QUrl::fromLocalFile(path), QUrl(u"https://example.com/a"_s)});
|
|
QCOMPARE(model.data(model.index(0), PlaylistModel::TitleRole).toString(), u"S01E02 · The Tone"_s);
|
|
QCOMPARE(model.data(model.index(1), PlaylistModel::TitleRole).toString(), u"https://example.com/a"_s);
|
|
QCOMPARE(model.data(model.index(1), PlaylistModel::DurationRole).toDouble(), -1.0);
|
|
|
|
QTRY_COMPARE(changed.count(), 1);
|
|
QCOMPARE(changed.first().at(2).value<QList<int>>(), QList<int>{PlaylistModel::DurationRole});
|
|
QVERIFY(qAbs(model.data(model.index(0), PlaylistModel::DurationRole).toDouble() - 2) < 0.1);
|
|
}
|
|
};
|
|
|
|
QTEST_GUILESS_MAIN(PlaylistModelTest)
|
|
|
|
#include "playlistmodeltest.moc"
|