diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c449bb9..ac6532c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,3 +5,19 @@ add_test(NAME TestDtoTypes COMMAND TestDtoTypes) add_executable(TestMulticastDiscovery core/TestMulticastDiscovery.cpp) target_link_libraries(TestMulticastDiscovery PRIVATE LocalSendCore Qt6::Test) add_test(NAME TestMulticastDiscovery COMMAND TestMulticastDiscovery) + +add_executable(TestTypes core/TestTypes.cpp) +target_link_libraries(TestTypes PRIVATE LocalSendCore Qt6::Test) +add_test(NAME TestTypes COMMAND TestTypes) + +add_executable(TestDevice core/TestDevice.cpp) +target_link_libraries(TestDevice PRIVATE LocalSendCore Qt6::Test) +add_test(NAME TestDevice COMMAND TestDevice) + +add_executable(TestSessionManager core/TestSessionManager.cpp) +target_link_libraries(TestSessionManager PRIVATE LocalSendCore Qt6::Test) +add_test(NAME TestSessionManager COMMAND TestSessionManager) + +add_executable(TestDtoTypesExtended core/TestDtoTypesExtended.cpp) +target_link_libraries(TestDtoTypesExtended PRIVATE LocalSendCore Qt6::Test) +add_test(NAME TestDtoTypesExtended COMMAND TestDtoTypesExtended) diff --git a/tests/core/TestDevice.cpp b/tests/core/TestDevice.cpp new file mode 100644 index 0000000..8f38be3 --- /dev/null +++ b/tests/core/TestDevice.cpp @@ -0,0 +1,89 @@ +#include +#include + +class TestDevice : public QObject +{ + Q_OBJECT + +private slots: + void testDefaultConstructor(); + void testParameterizedConstructor(); + void testDisplayNameWithAlias(); + void testDisplayNameWithoutAlias(); + void testIsHttps(); + void testEqualityByFingerprint(); + void testInequality(); +}; + +void TestDevice::testDefaultConstructor() +{ + LocalSend::Device device; + QVERIFY(device.ip.isEmpty()); + QCOMPARE(device.port, quint16(53317)); + QCOMPARE(device.protocol, LocalSend::ProtocolType::Http); + QVERIFY(device.alias.isEmpty()); + QVERIFY(device.fingerprint.isEmpty()); + QCOMPARE(device.deviceType, LocalSend::DeviceType::Desktop); + QVERIFY(!device.download); + QCOMPARE(device.discoveryMethod, LocalSend::DiscoveryMethod::Multicast); + QVERIFY(!device.lastSeen.isValid()); +} + +void TestDevice::testParameterizedConstructor() +{ + LocalSend::Device device(QStringLiteral("192.168.1.100"), 8080); + QCOMPARE(device.ip, QStringLiteral("192.168.1.100")); + QCOMPARE(device.port, quint16(8080)); +} + +void TestDevice::testDisplayNameWithAlias() +{ + LocalSend::Device device; + device.alias = QStringLiteral("My Laptop"); + QCOMPARE(device.displayName(), QStringLiteral("My Laptop")); +} + +void TestDevice::testDisplayNameWithoutAlias() +{ + LocalSend::Device device; + device.ip = QStringLiteral("192.168.1.50"); + QCOMPARE(device.displayName(), QStringLiteral("192.168.1.50")); +} + +void TestDevice::testIsHttps() +{ + LocalSend::Device httpDevice; + httpDevice.protocol = LocalSend::ProtocolType::Http; + QVERIFY(!httpDevice.isHttps()); + + LocalSend::Device httpsDevice; + httpsDevice.protocol = LocalSend::ProtocolType::Https; + QVERIFY(httpsDevice.isHttps()); +} + +void TestDevice::testEqualityByFingerprint() +{ + LocalSend::Device a; + a.fingerprint = QStringLiteral("fp123"); + a.ip = QStringLiteral("10.0.0.1"); + + LocalSend::Device b; + b.fingerprint = QStringLiteral("fp123"); + b.ip = QStringLiteral("10.0.0.2"); + + QVERIFY(a == b); +} + +void TestDevice::testInequality() +{ + LocalSend::Device a; + a.fingerprint = QStringLiteral("fp1"); + + LocalSend::Device b; + b.fingerprint = QStringLiteral("fp2"); + + QVERIFY(a != b); +} + +QTEST_MAIN(TestDevice) +#include "TestDevice.moc" diff --git a/tests/core/TestDtoTypesExtended.cpp b/tests/core/TestDtoTypesExtended.cpp new file mode 100644 index 0000000..d05c533 --- /dev/null +++ b/tests/core/TestDtoTypesExtended.cpp @@ -0,0 +1,181 @@ +#include +#include +#include +#include + +class TestDtoTypesExtended : public QObject +{ + Q_OBJECT + +private slots: + void testFileDtoMetadata(); + void testFileDtoRoundTripWithMetadata(); + void testFileDtoWithoutOptionalFields(); + void testPrepareUploadResponseDto(); + void testReceiveRequestResponseDto(); + void testMulticastDtoVersionDefault(); + void testFileDtoSizeLarge(); + void testPrepareUploadRequestDtoRoundTrip(); +}; + +void TestDtoTypesExtended::testFileDtoMetadata() +{ + LocalSend::FileDto dto; + dto.id = QStringLiteral("0"); + dto.fileName = QStringLiteral("test.txt"); + dto.size = 1024; + dto.fileType = QStringLiteral("text/plain"); + dto.metadata = LocalSend::FileDto::Metadata{ + QDateTime::fromMSecsSinceEpoch(1700000000000), + QDateTime::fromMSecsSinceEpoch(1700000001000) + }; + + QJsonObject json = dto.toJson(); + QVERIFY(json.contains(QStringLiteral("metadata"))); + QJsonObject metaObj = json[QStringLiteral("metadata")].toObject(); + QCOMPARE(metaObj[QStringLiteral("lastModified")].toVariant().toLongLong(), qint64(1700000000000)); + QCOMPARE(metaObj[QStringLiteral("lastAccessed")].toVariant().toLongLong(), qint64(1700000001000)); +} + +void TestDtoTypesExtended::testFileDtoRoundTripWithMetadata() +{ + LocalSend::FileDto dto; + dto.id = QStringLiteral("1"); + dto.fileName = QStringLiteral("doc.pdf"); + dto.size = 2048; + dto.fileType = QStringLiteral("application/pdf"); + dto.hash = QStringLiteral("abc123"); + dto.preview = QStringLiteral("base64data"); + dto.metadata = LocalSend::FileDto::Metadata{ + QDateTime::fromMSecsSinceEpoch(1700000000000), + QDateTime() + }; + + QJsonObject json = dto.toJson(); + LocalSend::FileDto parsed = LocalSend::FileDto::fromJson(json); + + QCOMPARE(parsed.id, dto.id); + QCOMPARE(parsed.fileName, dto.fileName); + QCOMPARE(parsed.size, dto.size); + QCOMPARE(parsed.fileType, dto.fileType); + QCOMPARE(parsed.hash, dto.hash); + QCOMPARE(parsed.preview, dto.preview); + QVERIFY(parsed.metadata.has_value()); + QCOMPARE(parsed.metadata->lastModified.toMSecsSinceEpoch(), qint64(1700000000000)); + QVERIFY(!parsed.metadata->lastAccessed.isValid()); +} + +void TestDtoTypesExtended::testFileDtoWithoutOptionalFields() +{ + LocalSend::FileDto dto; + dto.id = QStringLiteral("2"); + dto.fileName = QStringLiteral("simple.txt"); + dto.size = 50; + dto.fileType = QStringLiteral("text/plain"); + + QJsonObject json = dto.toJson(); + QVERIFY(!json.contains(QStringLiteral("hash"))); + QVERIFY(!json.contains(QStringLiteral("preview"))); + QVERIFY(!json.contains(QStringLiteral("metadata"))); + + LocalSend::FileDto parsed = LocalSend::FileDto::fromJson(json); + QVERIFY(!parsed.metadata.has_value()); + QVERIFY(parsed.hash.isEmpty()); + QVERIFY(parsed.preview.isEmpty()); +} + +void TestDtoTypesExtended::testPrepareUploadResponseDto() +{ + QJsonObject json; + json[QStringLiteral("sessionId")] = QStringLiteral("sess-123"); + QJsonObject filesObj; + filesObj[QStringLiteral("0")] = QStringLiteral("token-0"); + filesObj[QStringLiteral("1")] = QStringLiteral("token-1"); + json[QStringLiteral("files")] = filesObj; + + LocalSend::PrepareUploadResponseDto dto = LocalSend::PrepareUploadResponseDto::fromJson(json); + + QCOMPARE(dto.sessionId, QStringLiteral("sess-123")); + QCOMPARE(dto.files.size(), 2); + QCOMPARE(dto.files[QStringLiteral("0")], QStringLiteral("token-0")); + QCOMPARE(dto.files[QStringLiteral("1")], QStringLiteral("token-1")); +} + +void TestDtoTypesExtended::testReceiveRequestResponseDto() +{ + LocalSend::ReceiveRequestResponseDto dto; + dto.sessionId = QStringLiteral("sess-456"); + dto.cancel = false; + dto.destinationPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/file0.txt")); + dto.destinationPaths.insert(QStringLiteral("1"), QStringLiteral("/tmp/file1.txt")); + + QJsonObject json = dto.toJson(); + QCOMPARE(json[QStringLiteral("sessionId")].toString(), QStringLiteral("sess-456")); + QCOMPARE(json[QStringLiteral("cancel")].toBool(), false); + + QJsonObject pathsObj = json[QStringLiteral("destinationPaths")].toObject(); + QCOMPARE(pathsObj.size(), 2); + QCOMPARE(pathsObj[QStringLiteral("0")].toString(), QStringLiteral("/tmp/file0.txt")); +} + +void TestDtoTypesExtended::testMulticastDtoVersionDefault() +{ + LocalSend::MulticastDto dto; + dto.alias = QStringLiteral("Test"); + dto.fingerprint = QStringLiteral("fp1"); + + QJsonObject json = dto.toJson(); + QCOMPARE(json[QStringLiteral("version")].toString(), QString(LocalSend::PROTOCOL_VERSION)); +} + +void TestDtoTypesExtended::testFileDtoSizeLarge() +{ + LocalSend::FileDto dto; + dto.id = QStringLiteral("big"); + dto.fileName = QStringLiteral("big.iso"); + dto.size = Q_INT64_C(4700000000); + dto.fileType = QStringLiteral("application/x-iso9660-image"); + + QJsonObject json = dto.toJson(); + LocalSend::FileDto parsed = LocalSend::FileDto::fromJson(json); + QCOMPARE(parsed.size, Q_INT64_C(4700000000)); +} + +void TestDtoTypesExtended::testPrepareUploadRequestDtoRoundTrip() +{ + LocalSend::PrepareUploadRequestDto dto; + dto.info.alias = QStringLiteral("Alice"); + dto.info.fingerprint = QStringLiteral("fp-alice"); + dto.info.port = 53317; + dto.info.protocol = LocalSend::ProtocolType::Https; + + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("photo.jpg"); + f1.size = 3000000; + f1.fileType = QStringLiteral("image/jpeg"); + dto.files.insert(QStringLiteral("0"), f1); + + LocalSend::FileDto f2; + f2.id = QStringLiteral("1"); + f2.fileName = QStringLiteral("notes.txt"); + f2.size = 500; + f2.fileType = QStringLiteral("text/plain"); + f2.hash = QStringLiteral("sha256abc"); + dto.files.insert(QStringLiteral("1"), f2); + + QJsonObject json = dto.toJson(); + LocalSend::PrepareUploadRequestDto parsed = LocalSend::PrepareUploadRequestDto::fromJson(json); + + QCOMPARE(parsed.info.alias, QStringLiteral("Alice")); + QCOMPARE(parsed.info.fingerprint, QStringLiteral("fp-alice")); + QCOMPARE(parsed.info.port, quint16(53317)); + QCOMPARE(parsed.info.protocol, LocalSend::ProtocolType::Https); + QCOMPARE(parsed.files.size(), 2); + QCOMPARE(parsed.files[QStringLiteral("0")].fileName, QStringLiteral("photo.jpg")); + QCOMPARE(parsed.files[QStringLiteral("0")].size, qint64(3000000)); + QCOMPARE(parsed.files[QStringLiteral("1")].hash, QStringLiteral("sha256abc")); +} + +QTEST_MAIN(TestDtoTypesExtended) +#include "TestDtoTypesExtended.moc" diff --git a/tests/core/TestSessionManager.cpp b/tests/core/TestSessionManager.cpp new file mode 100644 index 0000000..00933cf --- /dev/null +++ b/tests/core/TestSessionManager.cpp @@ -0,0 +1,552 @@ +#include +#include +#include + +class TestSessionManager : public QObject +{ + Q_OBJECT + +private slots: + void testCreateReceiveSession(); + void testAcceptReceiveSession(); + void testDeclineReceiveSession(); + void testCancelReceiveSession(); + void testReceiveProgress(); + void testCompleteReceiveFile(); + void testCompleteAllReceiveFiles(); + void testFailReceiveFile(); + void testCreateSendSession(); + void testSetSendSessionTokens(); + void testStartSendSession(); + void testSendProgress(); + void testCompleteSendFile(); + void testCompleteAllSendFiles(); + void testCancelSendSession(); + void testHasSessionQueries(); + void testGenerateToken(); + void testDeclineRemovesSession(); + void testSetSendSessionTokensRekeys(); +}; + +void TestSessionManager::testCreateReceiveSession() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device sender; + sender.ip = QStringLiteral("10.0.0.1"); + sender.alias = QStringLiteral("Sender"); + + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + LocalSend::FileDto f2; + f2.id = QStringLiteral("1"); + f2.fileName = QStringLiteral("b.txt"); + f2.size = 200; + files.insert(QStringLiteral("1"), f2); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::receiveSessionCreated); + QString sessionId = mgr.createReceiveSession(sender, files); + + QVERIFY(!sessionId.isEmpty()); + QCOMPARE(spy.count(), 1); + + LocalSend::ReceiveSession session = mgr.receiveSession(sessionId); + QCOMPARE(session.sessionId, sessionId); + QCOMPARE(session.sender.alias, QStringLiteral("Sender")); + QCOMPARE(session.files.size(), 2); + QCOMPARE(session.status, LocalSend::SessionStatus::Waiting); + QVERIFY(!session.files[QStringLiteral("0")].token.isEmpty()); + QVERIFY(!session.files[QStringLiteral("1")].token.isEmpty()); +} + +void TestSessionManager::testAcceptReceiveSession() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device sender; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + QString sessionId = mgr.createReceiveSession(sender, files); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::receiveSessionAccepted); + QMap destPaths; + destPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + mgr.acceptReceiveSession(sessionId, destPaths); + + QCOMPARE(spy.count(), 1); + QList args = spy.takeFirst(); + QCOMPARE(args.at(0).toString(), sessionId); + + LocalSend::ReceiveSession session = mgr.receiveSession(sessionId); + QCOMPARE(session.status, LocalSend::SessionStatus::Sending); + QCOMPARE(session.files[QStringLiteral("0")].destinationPath, QStringLiteral("/tmp/a.txt")); + + auto tokens = args.at(1).value>(); + QVERIFY(!tokens.value(QStringLiteral("0")).isEmpty()); +} + +void TestSessionManager::testDeclineReceiveSession() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device sender; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + QString sessionId = mgr.createReceiveSession(sender, files); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::receiveSessionDeclined); + mgr.declineReceiveSession(sessionId); + + QCOMPARE(spy.count(), 1); + QVERIFY(!mgr.hasReceiveSession(sessionId)); +} + +void TestSessionManager::testCancelReceiveSession() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device sender; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + QString sessionId = mgr.createReceiveSession(sender, files); + QMap destPaths; + destPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + mgr.acceptReceiveSession(sessionId, destPaths); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::receiveSessionCanceled); + mgr.cancelReceiveSession(sessionId); + + QCOMPARE(spy.count(), 1); + QVERIFY(!mgr.hasReceiveSession(sessionId)); +} + +void TestSessionManager::testReceiveProgress() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device sender; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 1000; + files.insert(QStringLiteral("0"), f1); + + QString sessionId = mgr.createReceiveSession(sender, files); + QMap destPaths; + destPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + mgr.acceptReceiveSession(sessionId, destPaths); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::receiveProgress); + mgr.updateReceiveProgress(sessionId, QStringLiteral("0"), 500); + + QCOMPARE(spy.count(), 1); + double progress = spy.takeFirst().at(2).toDouble(); + QVERIFY(qFuzzyCompare(progress, 0.5)); +} + +void TestSessionManager::testCompleteReceiveFile() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device sender; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 1000; + files.insert(QStringLiteral("0"), f1); + + QString sessionId = mgr.createReceiveSession(sender, files); + QMap destPaths; + destPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + mgr.acceptReceiveSession(sessionId, destPaths); + + mgr.updateReceiveProgress(sessionId, QStringLiteral("0"), 1000); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::receiveSessionCompleted); + mgr.completeReceiveFile(sessionId, QStringLiteral("0")); + + QCOMPARE(spy.count(), 1); + QVERIFY(!mgr.hasReceiveSession(sessionId)); +} + +void TestSessionManager::testCompleteAllReceiveFiles() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device sender; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + LocalSend::FileDto f2; + f2.id = QStringLiteral("1"); + f2.fileName = QStringLiteral("b.txt"); + f2.size = 200; + files.insert(QStringLiteral("1"), f2); + + QString sessionId = mgr.createReceiveSession(sender, files); + QMap destPaths; + destPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + destPaths.insert(QStringLiteral("1"), QStringLiteral("/tmp/b.txt")); + mgr.acceptReceiveSession(sessionId, destPaths); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::receiveSessionCompleted); + + mgr.completeReceiveFile(sessionId, QStringLiteral("0")); + QCOMPARE(spy.count(), 0); + QVERIFY(mgr.hasReceiveSession(sessionId)); + + mgr.completeReceiveFile(sessionId, QStringLiteral("1")); + QCOMPARE(spy.count(), 1); + QVERIFY(!mgr.hasReceiveSession(sessionId)); +} + +void TestSessionManager::testFailReceiveFile() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device sender; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 1000; + files.insert(QStringLiteral("0"), f1); + + QString sessionId = mgr.createReceiveSession(sender, files); + + mgr.failReceiveFile(sessionId, QStringLiteral("0")); + + LocalSend::ReceiveSession session = mgr.receiveSession(sessionId); + QCOMPARE(session.files[QStringLiteral("0")].status, LocalSend::FileStatus::Failed); +} + +void TestSessionManager::testCreateSendSession() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device target; + target.ip = QStringLiteral("10.0.0.2"); + target.alias = QStringLiteral("Receiver"); + + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("c.txt"); + f1.size = 500; + files.insert(QStringLiteral("0"), f1); + + QMap localPaths; + localPaths.insert(QStringLiteral("0"), QStringLiteral("/home/user/c.txt")); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::sendSessionCreated); + QString sessionId = mgr.createSendSession(target, files, localPaths); + + QVERIFY(!sessionId.isEmpty()); + QCOMPARE(spy.count(), 1); + + LocalSend::SendSession session = mgr.sendSession(sessionId); + QCOMPARE(session.sessionId, sessionId); + QCOMPARE(session.target.alias, QStringLiteral("Receiver")); + QCOMPARE(session.files.size(), 1); + QCOMPARE(session.files[QStringLiteral("0")].localPath, QStringLiteral("/home/user/c.txt")); + QCOMPARE(session.status, LocalSend::SessionStatus::Waiting); +} + +void TestSessionManager::testSetSendSessionTokens() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device target; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + QMap localPaths; + localPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + + QString origSessionId = mgr.createSendSession(target, files, localPaths); + + QString responseSessionId = QStringLiteral("server-session-123"); + QMap tokens; + tokens.insert(QStringLiteral("0"), QStringLiteral("token-abc")); + + mgr.setSendSessionTokens(origSessionId, responseSessionId, tokens); + + QVERIFY(!mgr.hasSendSession(origSessionId)); + QVERIFY(mgr.hasSendSession(responseSessionId)); + + LocalSend::SendSession session = mgr.sendSession(responseSessionId); + QCOMPARE(session.sessionId, responseSessionId); + QCOMPARE(session.files[QStringLiteral("0")].token, QStringLiteral("token-abc")); +} + +void TestSessionManager::testStartSendSession() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device target; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + QMap localPaths; + localPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + + QString sessionId = mgr.createSendSession(target, files, localPaths); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::sendSessionStarted); + mgr.startSendSession(sessionId); + + QCOMPARE(spy.count(), 1); + LocalSend::SendSession session = mgr.sendSession(sessionId); + QCOMPARE(session.status, LocalSend::SessionStatus::Sending); +} + +void TestSessionManager::testSendProgress() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device target; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 2000; + files.insert(QStringLiteral("0"), f1); + + QMap localPaths; + localPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + + QString sessionId = mgr.createSendSession(target, files, localPaths); + mgr.startSendSession(sessionId); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::sendProgress); + mgr.updateSendProgress(sessionId, QStringLiteral("0"), 1000); + + QCOMPARE(spy.count(), 1); + double progress = spy.takeFirst().at(2).toDouble(); + QVERIFY(qFuzzyCompare(progress, 0.5)); +} + +void TestSessionManager::testCompleteSendFile() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device target; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 1000; + files.insert(QStringLiteral("0"), f1); + + QMap localPaths; + localPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + + QString sessionId = mgr.createSendSession(target, files, localPaths); + mgr.startSendSession(sessionId); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::sendSessionCompleted); + mgr.completeSendFile(sessionId, QStringLiteral("0")); + + QCOMPARE(spy.count(), 1); + QVERIFY(!mgr.hasSendSession(sessionId)); +} + +void TestSessionManager::testCompleteAllSendFiles() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device target; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + LocalSend::FileDto f2; + f2.id = QStringLiteral("1"); + f2.fileName = QStringLiteral("b.txt"); + f2.size = 200; + files.insert(QStringLiteral("1"), f2); + + QMap localPaths; + localPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + localPaths.insert(QStringLiteral("1"), QStringLiteral("/tmp/b.txt")); + + QString sessionId = mgr.createSendSession(target, files, localPaths); + mgr.startSendSession(sessionId); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::sendSessionCompleted); + + mgr.completeSendFile(sessionId, QStringLiteral("0")); + QCOMPARE(spy.count(), 0); + + mgr.completeSendFile(sessionId, QStringLiteral("1")); + QCOMPARE(spy.count(), 1); + QVERIFY(!mgr.hasSendSession(sessionId)); +} + +void TestSessionManager::testCancelSendSession() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device target; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + QMap localPaths; + localPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + + QString sessionId = mgr.createSendSession(target, files, localPaths); + mgr.startSendSession(sessionId); + + QSignalSpy spy(&mgr, &LocalSend::SessionManager::sendSessionCanceled); + mgr.cancelSendSession(sessionId); + + QCOMPARE(spy.count(), 1); + QVERIFY(!mgr.hasSendSession(sessionId)); +} + +void TestSessionManager::testHasSessionQueries() +{ + LocalSend::SessionManager mgr; + + QVERIFY(!mgr.hasReceiveSession(QStringLiteral("nonexistent"))); + QVERIFY(!mgr.hasSendSession(QStringLiteral("nonexistent"))); + + LocalSend::Device sender; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + QString recvSessionId = mgr.createReceiveSession(sender, files); + QVERIFY(mgr.hasReceiveSession(recvSessionId)); + + QMap localPaths; + localPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + QString sendSessionId = mgr.createSendSession(sender, files, localPaths); + QVERIFY(mgr.hasSendSession(sendSessionId)); + + LocalSend::ReceiveSession emptyRecv = mgr.receiveSession(QStringLiteral("nope")); + QVERIFY(emptyRecv.sessionId.isEmpty()); + + LocalSend::SendSession emptySend = mgr.sendSession(QStringLiteral("nope")); + QVERIFY(emptySend.sessionId.isEmpty()); +} + +void TestSessionManager::testGenerateToken() +{ + LocalSend::SessionManager mgr; + + QString token1 = mgr.generateToken(); + QString token2 = mgr.generateToken(); + + QVERIFY(!token1.isEmpty()); + QVERIFY(!token2.isEmpty()); + QVERIFY(token1 != token2); +} + +void TestSessionManager::testDeclineRemovesSession() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device sender; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + QString sessionId = mgr.createReceiveSession(sender, files); + QVERIFY(mgr.hasReceiveSession(sessionId)); + + mgr.declineReceiveSession(sessionId); + QVERIFY(!mgr.hasReceiveSession(sessionId)); +} + +void TestSessionManager::testSetSendSessionTokensRekeys() +{ + LocalSend::SessionManager mgr; + + LocalSend::Device target; + QMap files; + LocalSend::FileDto f1; + f1.id = QStringLiteral("0"); + f1.fileName = QStringLiteral("a.txt"); + f1.size = 100; + files.insert(QStringLiteral("0"), f1); + + LocalSend::FileDto f2; + f2.id = QStringLiteral("1"); + f2.fileName = QStringLiteral("b.txt"); + f2.size = 200; + files.insert(QStringLiteral("1"), f2); + + QMap localPaths; + localPaths.insert(QStringLiteral("0"), QStringLiteral("/tmp/a.txt")); + localPaths.insert(QStringLiteral("1"), QStringLiteral("/tmp/b.txt")); + + QString origId = mgr.createSendSession(target, files, localPaths); + + QString newId = QStringLiteral("response-session-id"); + QMap tokens; + tokens.insert(QStringLiteral("0"), QStringLiteral("tok0")); + tokens.insert(QStringLiteral("1"), QStringLiteral("tok1")); + + mgr.setSendSessionTokens(origId, newId, tokens); + + QVERIFY(!mgr.hasSendSession(origId)); + QVERIFY(mgr.hasSendSession(newId)); + + LocalSend::SendSession session = mgr.sendSession(newId); + QCOMPARE(session.sessionId, newId); + QCOMPARE(session.files[QStringLiteral("0")].token, QStringLiteral("tok0")); + QCOMPARE(session.files[QStringLiteral("1")].token, QStringLiteral("tok1")); + QCOMPARE(session.files[QStringLiteral("0")].localPath, QStringLiteral("/tmp/a.txt")); + QCOMPARE(session.files[QStringLiteral("1")].localPath, QStringLiteral("/tmp/b.txt")); +} + +QTEST_MAIN(TestSessionManager) +#include "TestSessionManager.moc" diff --git a/tests/core/TestTypes.cpp b/tests/core/TestTypes.cpp new file mode 100644 index 0000000..b98a843 --- /dev/null +++ b/tests/core/TestTypes.cpp @@ -0,0 +1,82 @@ +#include +#include + +class TestTypes : public QObject +{ + Q_OBJECT + +private slots: + void testDeviceTypeToString(); + void testDeviceTypeFromString(); + void testDeviceTypeRoundTrip(); + void testDeviceTypeFromStringUnknown(); + void testProtocolTypeToString(); + void testProtocolTypeFromString(); + void testProtocolTypeRoundTrip(); + void testProtocolTypeFromStringUnknown(); +}; + +void TestTypes::testDeviceTypeToString() +{ + QCOMPARE(LocalSend::deviceTypeToString(LocalSend::DeviceType::Mobile), QStringLiteral("mobile")); + QCOMPARE(LocalSend::deviceTypeToString(LocalSend::DeviceType::Desktop), QStringLiteral("desktop")); + QCOMPARE(LocalSend::deviceTypeToString(LocalSend::DeviceType::Web), QStringLiteral("web")); + QCOMPARE(LocalSend::deviceTypeToString(LocalSend::DeviceType::Headless), QStringLiteral("headless")); + QCOMPARE(LocalSend::deviceTypeToString(LocalSend::DeviceType::Server), QStringLiteral("server")); +} + +void TestTypes::testDeviceTypeFromString() +{ + QCOMPARE(LocalSend::deviceTypeFromString(QStringLiteral("mobile")), LocalSend::DeviceType::Mobile); + QCOMPARE(LocalSend::deviceTypeFromString(QStringLiteral("desktop")), LocalSend::DeviceType::Desktop); + QCOMPARE(LocalSend::deviceTypeFromString(QStringLiteral("web")), LocalSend::DeviceType::Web); + QCOMPARE(LocalSend::deviceTypeFromString(QStringLiteral("headless")), LocalSend::DeviceType::Headless); + QCOMPARE(LocalSend::deviceTypeFromString(QStringLiteral("server")), LocalSend::DeviceType::Server); +} + +void TestTypes::testDeviceTypeRoundTrip() +{ + const QList types = { + LocalSend::DeviceType::Mobile, + LocalSend::DeviceType::Desktop, + LocalSend::DeviceType::Web, + LocalSend::DeviceType::Headless, + LocalSend::DeviceType::Server, + }; + for (const auto& type : types) { + QCOMPARE(LocalSend::deviceTypeFromString(LocalSend::deviceTypeToString(type)), type); + } +} + +void TestTypes::testDeviceTypeFromStringUnknown() +{ + QCOMPARE(LocalSend::deviceTypeFromString(QStringLiteral("unknown")), LocalSend::DeviceType::Desktop); + QCOMPARE(LocalSend::deviceTypeFromString(QString()), LocalSend::DeviceType::Desktop); +} + +void TestTypes::testProtocolTypeToString() +{ + QCOMPARE(LocalSend::protocolTypeToString(LocalSend::ProtocolType::Http), QStringLiteral("http")); + QCOMPARE(LocalSend::protocolTypeToString(LocalSend::ProtocolType::Https), QStringLiteral("https")); +} + +void TestTypes::testProtocolTypeFromString() +{ + QCOMPARE(LocalSend::protocolTypeFromString(QStringLiteral("http")), LocalSend::ProtocolType::Http); + QCOMPARE(LocalSend::protocolTypeFromString(QStringLiteral("https")), LocalSend::ProtocolType::Https); +} + +void TestTypes::testProtocolTypeRoundTrip() +{ + QCOMPARE(LocalSend::protocolTypeFromString(LocalSend::protocolTypeToString(LocalSend::ProtocolType::Http)), LocalSend::ProtocolType::Http); + QCOMPARE(LocalSend::protocolTypeFromString(LocalSend::protocolTypeToString(LocalSend::ProtocolType::Https)), LocalSend::ProtocolType::Https); +} + +void TestTypes::testProtocolTypeFromStringUnknown() +{ + QCOMPARE(LocalSend::protocolTypeFromString(QStringLiteral("ftp")), LocalSend::ProtocolType::Http); + QCOMPARE(LocalSend::protocolTypeFromString(QString()), LocalSend::ProtocolType::Http); +} + +QTEST_MAIN(TestTypes) +#include "TestTypes.moc"