Files
QtPotato/autotests/playlistmodeltest.cpp
T
tri 8c57c9ddb6
CI / build (push) Successful in 5m11s
Release / release (push) Failing after 7m17s
ci: build and test every PR, release on tags, and add AUR packages (#15)
Co-authored-by: Tri Vo Khac <git@trivk.dev>
2026-11-14 00:18:16 +07:00

139 lines
4.7 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 initTestCase()
{
// The C locale's collation is case-sensitive, so the sort order would depend on $LANG.
QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates));
}
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"