initial commit

This commit is contained in:
deeaitch committed 2026-10-01 11:53:34 -04:00
commit 90f6666986
18 files changed
+1740

No files matched your search

+40
View File
@@ -0,0 +1,40 @@
#include "../clipboardresultdialog.h"
#include <QTest>
class ClipboardResultDialogTest : public QObject {
Q_OBJECT
private slots:
void inactiveWindowDoesNotOverwriteClipboard() {
auto *clipboard = QGuiApplication::clipboard();
clipboard->setText (QStringLiteral ("original"));
ClipboardResultDialog dialog (QUrl (QStringLiteral ("https://cut.himro.ca/h")), true);
QVERIFY (!dialog.copyShortUrl());
QCOMPARE (clipboard->text(), QStringLiteral ("original"));
}
void focusCopiesAndRetryRestoresShortUrl() {
const QUrl shortUrl (QStringLiteral ("https://cut.himro.ca/h?value=a%26b#section"));
auto *clipboard = QGuiApplication::clipboard();
clipboard->setText (QStringLiteral ("original"));
ClipboardResultDialog dialog (shortUrl, true);
dialog.show();
dialog.activateWindow();
QTRY_VERIFY (dialog.isActiveWindow());
QTRY_COMPARE (clipboard->text(), shortUrl.toString (QUrl::FullyEncoded));
QVERIFY (dialog.copyStatusLabel()->text().contains (QStringLiteral ("copied")));
clipboard->setText (QStringLiteral ("other text"));
QVERIFY (dialog.copyShortUrl());
QCOMPARE (clipboard->text(), shortUrl.toString (QUrl::FullyEncoded));
dialog.accept();
QCOMPARE (clipboard->text(), shortUrl.toString (QUrl::FullyEncoded));
}
void platformsWithoutFocusRequirementCopyImmediately() {
ClipboardResultDialog dialog (QUrl (QStringLiteral ("https://cut.himro.ca/h")), false);
QVERIFY (dialog.copyShortUrl());
QCOMPARE (QGuiApplication::clipboard()->text(), QStringLiteral ("https://cut.himro.ca/h"));
}
};
QTEST_MAIN (ClipboardResultDialogTest)
#include "clipboardresultdialog_test.moc"
+7
View File
@@ -0,0 +1,7 @@
QT = core gui widgets testlib
CONFIG += console c++17 testcase
CONFIG -= app_bundle
TEMPLATE = app
TARGET = clipboardresultdialog_test
SOURCES += clipboardresultdialog_test.cpp
HEADERS += ../clipboardresultdialog.h
+52
View File
@@ -0,0 +1,52 @@
#include "../clipboardurl.h"
#include <QCoreApplication>
#include <QDebug>
int main (int argc, char **argv) {
QCoreApplication application (argc, argv);
const QUrl expected (QStringLiteral ("https://git.himro.ca/explore/repos"));
int failures = 0;
const auto check = [&failures] (bool condition, const char *description) {
if (!condition) {
qCritical() << description;
++failures;
}
};
for (const auto &text : {
"https://git.himro.ca/explore/repos",
" \nhttps://git.himro.ca/explore/repos\n ",
"'https://git.himro.ca/explore/repos'",
"\"https://git.himro.ca/explore/repos\"",
"<https://git.himro.ca/explore/repos>",
"[https://git.himro.ca/explore/repos](https://git.himro.ca/explore/repos)",
"'[Repositories](https://git.himro.ca/explore/repos)'"}) {
check (ClipboardUrl::parseText (QString::fromUtf8 (text)) == expected, text);
}
check (ClipboardUrl::parseText (QStringLiteral (
"[Other label](https://git.himro.ca/explore/repos?filter=a%26b#section)"))
== QUrl (QStringLiteral ("https://git.himro.ca/explore/repos?filter=a%26b#section")),
"Markdown must use the destination and preserve query and fragment");
check (ClipboardUrl::parseText (QStringLiteral ("[Link](https://example.com/a_(b))"))
== QUrl (QStringLiteral ("https://example.com/a_(b)")),
"Parentheses in URL paths must be preserved");
for (const auto &text : {"", "not a URL", "https://", "[Link](https://)"})
check (!ClipboardUrl::parseText (QString::fromUtf8 (text)).isValid(), text);
QMimeData mimeData;
mimeData.setText (QStringLiteral ("Repositories"));
mimeData.setUrls ({expected});
check (ClipboardUrl::fromMimeData (&mimeData) == expected,
"Browser URL MIME data must take precedence over a link label");
mimeData.clear();
mimeData.setText (expected.toString());
check (ClipboardUrl::fromMimeData (&mimeData) == expected, "Plain text fallback");
mimeData.setUrls ({QUrl (QStringLiteral ("file:///tmp/example"))});
check (ClipboardUrl::fromMimeData (&mimeData) == expected, "Unusable MIME URL fallback");
mimeData.clear();
check (!ClipboardUrl::fromMimeData (&mimeData).isValid(), "Empty clipboard");
check (!ClipboardUrl::fromMimeData (nullptr).isValid(), "Unavailable clipboard");
return failures == 0 ? 0 : 1;
}
+7
View File
@@ -0,0 +1,7 @@
QT = core
CONFIG += console c++17
CONFIG -= app_bundle
TEMPLATE = app
TARGET = clipboardurl_test
SOURCES += clipboardurl_test.cpp
HEADERS += ../clipboardurl.h
+77
View File
@@ -0,0 +1,77 @@
#include "../yourlsclient.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QSignalSpy>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTest>
#include <QUrlQuery>
class YourlsClientTest : public QObject {
Q_OBJECT
private slots:
void responses_data() {
QTest::addColumn<int> ("httpStatus");
QTest::addColumn<QString> ("status");
QTest::addColumn<QString> ("code");
QTest::addColumn<QString> ("originalUrl");
QTest::addColumn<QString> ("shortUrl");
QTest::addColumn<bool> ("success");
const QString source = QStringLiteral ("https://git.himro.ca/explore/repos?q=a%26b&next=x+y#section");
const QString shortened = QStringLiteral ("https://cut.himro.ca/h");
QTest::newRow ("created") << 200 << "success" << "" << source << shortened << true;
QTest::newRow ("duplicate") << 400 << "fail" << "error:url" << source << shortened << true;
QTest::newRow ("different-url") << 400 << "fail" << "error:url" << "https://example.com" << shortened << false;
QTest::newRow ("missing-short-url") << 400 << "fail" << "error:url" << source << "" << false;
QTest::newRow ("relative-short-url") << 400 << "fail" << "error:url" << source << "/h" << false;
QTest::newRow ("other-error") << 400 << "fail" << "error:auth" << source << shortened << false;
QTest::newRow ("server-error") << 500 << "fail" << "error:url" << source << shortened << false;
}
void responses() {
QFETCH (int, httpStatus);
QFETCH (QString, status);
QFETCH (QString, code);
QFETCH (QString, originalUrl);
QFETCH (QString, shortUrl);
QFETCH (bool, success);
QTcpServer server;
QVERIFY (server.listen (QHostAddress::LocalHost));
QByteArray requestData;
const QByteArray body = QJsonDocument (QJsonObject {
{"status", status}, {"code", code}, {"shorturl", shortUrl},
{"url", QJsonObject {{"url", originalUrl}}}
}).toJson (QJsonDocument::Compact);
connect (&server, &QTcpServer::newConnection, this, [&]() {
auto *socket = server.nextPendingConnection();
connect (socket, &QTcpSocket::readyRead, &server, [&, socket]() {
requestData += socket->readAll();
if (!requestData.contains ("\r\n\r\n"))
return;
socket->write ("HTTP/1.1 " + QByteArray::number (httpStatus)
+ " Result\r\nContent-Type: application/json\r\nContent-Length: "
+ QByteArray::number (body.size()) + "\r\nConnection: close\r\n\r\n" + body);
socket->disconnectFromHost();
});
});
YourlsClient client;
QSignalSpy succeeded (&client, &YourlsClient::shortenSucceeded);
QSignalSpy failed (&client, &YourlsClient::shortenFailed);
const QUrl source (QStringLiteral ("https://git.himro.ca/explore/repos?q=a%26b&next=x+y#section"));
client.shortenUrl ({QStringLiteral ("http://127.0.0.1:%1/api").arg (server.serverPort()),
QStringLiteral ("test-signature")}, source);
QTRY_COMPARE (succeeded.count() + failed.count(), 1);
QCOMPARE (succeeded.count(), success ? 1 : 0);
if (success)
QCOMPARE (succeeded.first().first().toUrl(), QUrl (shortUrl));
const QByteArray target = requestData.split (' ').value (1);
const QUrlQuery query (QUrl::fromEncoded (target));
// Decode the HTTP query once, as the server does, preserving URL escapes.
const QString encodedValue = query.queryItemValue (QStringLiteral ("url"), QUrl::FullyEncoded);
QCOMPARE (QUrl::fromPercentEncoding (encodedValue.toLatin1()), source.toString (QUrl::FullyEncoded));
}
};
QTEST_GUILESS_MAIN (YourlsClientTest)
#include "yourlsclient_test.moc"
+7
View File
@@ -0,0 +1,7 @@
QT = core network testlib
CONFIG += console c++17 testcase
CONFIG -= app_bundle
TEMPLATE = app
TARGET = yourlsclient_test
SOURCES += yourlsclient_test.cpp ../yourlsclient.cpp
HEADERS += ../yourlsclient.h