mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
257a19caaa
As part of #1532 it was identified that long running file transfers could get lost deep in the chatlog. This could result in unexpected use of bandwidth over time if users lose track of old/large transfers. This commit updates the files form to show in progress file transfers and offer a way to control them. * FilesForm now works on ToxFiles instead of finished file paths * FilesForm widgets have been replaced with an MV tree view with depth 1. The existing QListWidget did not provide us the controls to render more complex items. The use of delegates allows us to efficiently draw progress bars and controls * getHumanReadableSize has been extracted from FileTransferWidget into a more general utils file
283 lines
7.7 KiB
C++
283 lines
7.7 KiB
C++
/*
|
|
Copyright © 2021 by The qTox Project Contributors
|
|
|
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
|
|
|
qTox is libre software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
qTox is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "src/widget/form/filesform.h"
|
|
#include "src/friendlist.h"
|
|
#include "src/model/friend.h"
|
|
|
|
#include <QTest>
|
|
#include <limits>
|
|
|
|
class TestFileTransferList : public QObject
|
|
{
|
|
Q_OBJECT
|
|
private slots:
|
|
|
|
void testFileTransferListConversion();
|
|
void testEditorActionConversion();
|
|
|
|
void testFileName();
|
|
// NOTE: Testing contact return requires a lookup in FriendList which goes
|
|
// down a large dependency chain that is not linked to this test
|
|
// void testContact();
|
|
void testProgress();
|
|
void testSize();
|
|
void testSpeed();
|
|
void testStatus();
|
|
void testControl();
|
|
void testAvatarIgnored();
|
|
void testMultipleFiles();
|
|
void testFileRemoval();
|
|
};
|
|
|
|
using namespace FileTransferList;
|
|
|
|
void TestFileTransferList::testFileTransferListConversion()
|
|
{
|
|
Model model;
|
|
for (int i = 0; i < model.columnCount(); ++i) {
|
|
QVERIFY(toFileTransferListColumn(i) != Column::invalid);
|
|
}
|
|
QCOMPARE(toFileTransferListColumn(100), Column::invalid);
|
|
}
|
|
|
|
void TestFileTransferList::testEditorActionConversion()
|
|
{
|
|
QCOMPARE(toEditorAction(static_cast<int>(EditorAction::pause)), EditorAction::pause);
|
|
QCOMPARE(toEditorAction(static_cast<int>(EditorAction::cancel)), EditorAction::cancel);
|
|
QCOMPARE(toEditorAction(55), EditorAction::invalid);
|
|
}
|
|
|
|
void TestFileTransferList::testFileName()
|
|
{
|
|
Model model;
|
|
|
|
ToxFile file;
|
|
file.fileKind = TOX_FILE_KIND_DATA;
|
|
file.fileName = "Test";
|
|
model.onFileUpdated(file);
|
|
|
|
const auto idx = model.index(0, static_cast<int>(Column::fileName));
|
|
const auto fileName = idx.data();
|
|
|
|
QCOMPARE(fileName.toString(), QString("Test"));
|
|
}
|
|
|
|
void TestFileTransferList::testProgress()
|
|
{
|
|
Model model;
|
|
|
|
ToxFile file(0, 0, "", "", 1000, ToxFile::FileDirection::SENDING);
|
|
file.progress.addSample(100, QTime(1, 0, 0));
|
|
model.onFileUpdated(file);
|
|
|
|
const auto idx = model.index(0, static_cast<int>(Column::progress));
|
|
const auto progress = idx.data();
|
|
|
|
// Progress should be in percent units, 100/1000 == 10
|
|
QCOMPARE(progress.toFloat(), 10.0f);
|
|
}
|
|
|
|
void TestFileTransferList::testSize()
|
|
{
|
|
Model model;
|
|
|
|
ToxFile file(0, 0, "", "", 1000, ToxFile::FileDirection::SENDING);
|
|
model.onFileUpdated(file);
|
|
|
|
const auto idx = model.index(0, static_cast<int>(Column::size));
|
|
auto size = idx.data();
|
|
|
|
// Size should be a human readable string
|
|
QCOMPARE(size.toString(), QString("1000B"));
|
|
|
|
// 1GB + a little to avoid floating point inaccuracy
|
|
file = ToxFile(0, 0, "", "", 1024 * 1024 * 1024 + 2, ToxFile::FileDirection::SENDING);
|
|
model.onFileUpdated(file);
|
|
size = idx.data();
|
|
QCOMPARE(size.toString(), QString("1.00GiB"));
|
|
}
|
|
|
|
void TestFileTransferList::testSpeed()
|
|
{
|
|
Model model;
|
|
|
|
ToxFile file(0, 0, "", "", 1024 * 1024, ToxFile::FileDirection::SENDING);
|
|
file.progress.addSample(100 * 1024, QTime(1, 0, 0));
|
|
file.progress.addSample(200 * 1024, QTime(1, 0, 1));
|
|
model.onFileUpdated(file);
|
|
|
|
const auto idx = model.index(0, static_cast<int>(Column::speed));
|
|
const auto speed = idx.data();
|
|
|
|
// Speed should be a human readable string
|
|
QCOMPARE(speed.toString(), QString("100KiB/s"));
|
|
}
|
|
|
|
void TestFileTransferList::testStatus()
|
|
{
|
|
Model model;
|
|
|
|
ToxFile file(0, 0, "", "", 1024 * 1024, ToxFile::FileDirection::SENDING);
|
|
file.status = ToxFile::TRANSMITTING;
|
|
model.onFileUpdated(file);
|
|
|
|
const auto idx = model.index(0, static_cast<int>(Column::status));
|
|
auto status = idx.data();
|
|
|
|
QCOMPARE(status.toString(), QString("Transmitting"));
|
|
|
|
file.status = ToxFile::PAUSED;
|
|
file.pauseStatus.remotePause();
|
|
model.onFileUpdated(file);
|
|
status = idx.data();
|
|
|
|
QCOMPARE(status.toString(), QString("Remote paused"));
|
|
|
|
file.status = ToxFile::PAUSED;
|
|
file.pauseStatus.localPause();
|
|
file.pauseStatus.remoteResume();
|
|
model.onFileUpdated(file);
|
|
status = idx.data();
|
|
|
|
QCOMPARE(status.toString(), QString("Paused"));
|
|
}
|
|
|
|
void TestFileTransferList::testControl()
|
|
{
|
|
Model model;
|
|
bool cancelCalled = false;
|
|
bool pauseCalled = false;
|
|
|
|
QObject::connect(&model, &Model::cancel, [&] (ToxFile file) {
|
|
cancelCalled = true;
|
|
});
|
|
|
|
QObject::connect(&model, &Model::togglePause, [&] (ToxFile file) {
|
|
pauseCalled = true;
|
|
});
|
|
|
|
ToxFile file(0, 0, "", "", 1024 * 1024, ToxFile::FileDirection::SENDING);
|
|
file.status = ToxFile::TRANSMITTING;
|
|
model.onFileUpdated(file);
|
|
|
|
const auto idx = model.index(0, static_cast<int>(Column::control));
|
|
model.setData(idx, static_cast<int>(EditorAction::pause));
|
|
|
|
QVERIFY(pauseCalled);
|
|
QVERIFY(!cancelCalled);
|
|
|
|
pauseCalled = false;
|
|
model.setData(idx, static_cast<int>(EditorAction::cancel));
|
|
QVERIFY(!pauseCalled);
|
|
QVERIFY(cancelCalled);
|
|
|
|
file.status = ToxFile::TRANSMITTING;
|
|
model.onFileUpdated(file);
|
|
// True if paused
|
|
QCOMPARE(idx.data().toBool(), false);
|
|
|
|
file.status = ToxFile::PAUSED;
|
|
file.pauseStatus.localPause();
|
|
model.onFileUpdated(file);
|
|
// True if _local_ paused
|
|
QCOMPARE(idx.data().toBool(), true);
|
|
}
|
|
|
|
void TestFileTransferList::testAvatarIgnored()
|
|
{
|
|
Model model;
|
|
|
|
ToxFile file;
|
|
file.fileKind = TOX_FILE_KIND_AVATAR;
|
|
model.onFileUpdated(file);
|
|
|
|
QCOMPARE(model.rowCount(), 0);
|
|
}
|
|
|
|
void TestFileTransferList::testMultipleFiles()
|
|
{
|
|
Model model;
|
|
|
|
ToxFile file;
|
|
file.resumeFileId = QByteArray();
|
|
file.fileKind = TOX_FILE_KIND_DATA;
|
|
file.status = ToxFile::TRANSMITTING;
|
|
file.fileName = "a";
|
|
model.onFileUpdated(file);
|
|
|
|
// File map keys off resume file ID
|
|
file.resumeFileId = QByteArray("asdfasdf");
|
|
file.fileName = "b";
|
|
model.onFileUpdated(file);
|
|
|
|
QCOMPARE(model.rowCount(), 2);
|
|
|
|
auto idx = model.index(0, static_cast<int>(Column::fileName));
|
|
QCOMPARE(idx.data().toString(), QString("a"));
|
|
|
|
idx = model.index(1, static_cast<int>(Column::fileName));
|
|
QCOMPARE(idx.data().toString(), QString("b"));
|
|
|
|
// File name should be updated instead of inserting a new file since the
|
|
// resume file ID is the same
|
|
file.fileName = "c";
|
|
model.onFileUpdated(file);
|
|
QCOMPARE(model.rowCount(), 2);
|
|
QCOMPARE(idx.data().toString(), QString("c"));
|
|
}
|
|
|
|
void TestFileTransferList::testFileRemoval()
|
|
{
|
|
// Model should keep files in the list if they are finished, but not if they
|
|
// were broken or canceled
|
|
|
|
Model model;
|
|
|
|
ToxFile file;
|
|
file.fileKind = TOX_FILE_KIND_DATA;
|
|
file.status = ToxFile::TRANSMITTING;
|
|
model.onFileUpdated(file);
|
|
|
|
QCOMPARE(model.rowCount(), 1);
|
|
|
|
file.status = ToxFile::BROKEN;
|
|
model.onFileUpdated(file);
|
|
QCOMPARE(model.rowCount(), 0);
|
|
|
|
file.status = ToxFile::TRANSMITTING;
|
|
model.onFileUpdated(file);
|
|
QCOMPARE(model.rowCount(), 1);
|
|
|
|
file.status = ToxFile::CANCELED;
|
|
model.onFileUpdated(file);
|
|
QCOMPARE(model.rowCount(), 0);
|
|
|
|
file.status = ToxFile::TRANSMITTING;
|
|
model.onFileUpdated(file);
|
|
QCOMPARE(model.rowCount(), 1);
|
|
|
|
file.status = ToxFile::FINISHED;
|
|
model.onFileUpdated(file);
|
|
QCOMPARE(model.rowCount(), 1);
|
|
}
|
|
|
|
QTEST_GUILESS_MAIN(TestFileTransferList)
|
|
#include "filesform_test.moc"
|