2023-04-02 16:59:26 +02:00
|
|
|
|
#include "common/LinkParser.hpp"
|
|
|
|
|
|
2024-07-20 12:06:23 +02:00
|
|
|
|
#include "common/Literals.hpp"
|
2024-05-05 15:01:07 +02:00
|
|
|
|
#include "Test.hpp"
|
2024-04-21 22:52:44 +02:00
|
|
|
|
|
2023-04-02 16:59:26 +02:00
|
|
|
|
#include <QString>
|
|
|
|
|
#include <QStringList>
|
|
|
|
|
|
|
|
|
|
using namespace chatterino;
|
2024-07-20 12:06:23 +02:00
|
|
|
|
using namespace literals;
|
2023-04-02 16:59:26 +02:00
|
|
|
|
|
2023-04-23 00:58:37 +02:00
|
|
|
|
struct Case {
|
2024-07-14 11:17:42 +02:00
|
|
|
|
// -Wmissing-field-initializers complains otherwise
|
|
|
|
|
// NOLINTBEGIN(readability-redundant-member-init)
|
2023-04-23 00:58:37 +02:00
|
|
|
|
QString protocol{};
|
|
|
|
|
QString host{};
|
|
|
|
|
QString rest{};
|
2024-07-14 11:17:42 +02:00
|
|
|
|
// NOLINTEND(readability-redundant-member-init)
|
2023-04-23 00:58:37 +02:00
|
|
|
|
|
|
|
|
|
void check() const
|
|
|
|
|
{
|
2024-07-14 11:17:42 +02:00
|
|
|
|
QStringList prefixes{
|
|
|
|
|
"", "_", "__", "<", "<<", "<_<", "(((", "<*_~(", "**", "~~",
|
|
|
|
|
};
|
|
|
|
|
QStringList suffixes{
|
2024-07-21 16:00:12 +02:00
|
|
|
|
"", ">", "?", "!", ".", ",", ":", "*", "~",
|
|
|
|
|
">>", "?!.", "~~,*!?", "**", ").", "),", ",)", ")),.", ")?",
|
2024-07-14 11:17:42 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (const auto &prefix : prefixes)
|
|
|
|
|
{
|
|
|
|
|
for (const auto &suffix : suffixes)
|
|
|
|
|
{
|
|
|
|
|
checkSingle(prefix, suffix);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void checkSingle(const QString &prefix, const QString &suffix) const
|
|
|
|
|
{
|
|
|
|
|
auto link = this->protocol + this->host + this->rest;
|
|
|
|
|
auto input = prefix + link + suffix;
|
|
|
|
|
auto p = linkparser::parse(input);
|
|
|
|
|
ASSERT_TRUE(p.has_value()) << input;
|
|
|
|
|
|
|
|
|
|
if (!p)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(p->link, link);
|
|
|
|
|
ASSERT_EQ(p->protocol, this->protocol);
|
|
|
|
|
ASSERT_EQ(p->host, this->host);
|
|
|
|
|
ASSERT_EQ(p->rest, this->rest);
|
|
|
|
|
ASSERT_EQ(p->prefix(input), prefix);
|
|
|
|
|
ASSERT_EQ(p->suffix(input), suffix);
|
|
|
|
|
ASSERT_EQ(p->hasPrefix(input), !prefix.isEmpty());
|
|
|
|
|
ASSERT_EQ(p->hasSuffix(input), !suffix.isEmpty());
|
2023-04-23 00:58:37 +02:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-04-02 16:59:26 +02:00
|
|
|
|
TEST(LinkParser, parseDomainLinks)
|
|
|
|
|
{
|
2023-04-23 00:58:37 +02:00
|
|
|
|
const QList<Case> cases = {
|
|
|
|
|
{"https://", "chatterino.com"},
|
|
|
|
|
{"http://", "chatterino.com"},
|
|
|
|
|
{"", "chatterino.com"},
|
|
|
|
|
{"", "wiki.chatterino.com"},
|
|
|
|
|
{"https://", "wiki.chatterino.com"},
|
|
|
|
|
{"http://", "chatterino.co.uk"},
|
|
|
|
|
{"http://", "a.io"},
|
|
|
|
|
{"", "chatterino.com", ":80"},
|
|
|
|
|
{"", "wiki.chatterino.com", ":80"},
|
|
|
|
|
{"", "wiki.chatterino.com", ":80/foo/bar"},
|
2024-07-23 23:38:17 +02:00
|
|
|
|
{"", "wiki.chatterino.com", ":80?foo"},
|
|
|
|
|
{"", "wiki.chatterino.com", ":80#foo"},
|
2023-04-23 00:58:37 +02:00
|
|
|
|
{"", "wiki.chatterino.com", "/:80?foo/bar"},
|
|
|
|
|
{"", "wiki.chatterino.com", "/127.0.0.1"},
|
|
|
|
|
{"", "a.b.c.chatterino.com"},
|
|
|
|
|
{"https://", "a.b.c.chatterino.com", "/foo"},
|
|
|
|
|
{"http://", "chatterino.com", "?foo"},
|
|
|
|
|
{"http://", "xd.chatterino.com", "/#?foo"},
|
|
|
|
|
{"", "chatterino.com", "#foo"},
|
|
|
|
|
{"", "1.com"},
|
|
|
|
|
{"", "127.0.0.1.com"},
|
|
|
|
|
{"https://", "127.0.0.1.com"},
|
2023-05-07 14:15:36 +02:00
|
|
|
|
{"https://", "http.cat", "/200"},
|
|
|
|
|
{"https://", "http.cat"},
|
|
|
|
|
{"", "http.cat", ":8080"},
|
|
|
|
|
{"", "http.cat"},
|
|
|
|
|
{"", "https.cat"},
|
|
|
|
|
{"", "httpsd.cat"},
|
|
|
|
|
{"", "http.cat", "/200"},
|
2024-07-21 16:00:12 +02:00
|
|
|
|
{"", "http.cat", "/200()"},
|
|
|
|
|
{"", "a.com", "?()"},
|
|
|
|
|
{"", "a.com", "#()"},
|
2024-07-14 11:17:42 +02:00
|
|
|
|
{"", "a.com", "/__my_user__"},
|
2024-07-20 12:06:23 +02:00
|
|
|
|
{"", "a.b.c.-._.1.com", ""},
|
|
|
|
|
{"", "0123456789.com", ""},
|
|
|
|
|
{"", "ABCDEFGHIJKLMNOPQRSTUVWXYZ.com", ""},
|
|
|
|
|
{"", "abcdefghijklmnopqrstuvwxyz.com", ""},
|
2024-07-21 16:00:12 +02:00
|
|
|
|
{"", "example.com", "/foo(bar)"},
|
|
|
|
|
{"", "example.com", "/foo((bar))"},
|
|
|
|
|
{"", "example.com", "/(f)(o)(o)(b)(a)r"},
|
|
|
|
|
{"", "example.com", "/foobar()()"},
|
|
|
|
|
{"", "example.com", "/foobar()(())baz"},
|
|
|
|
|
{"", "example.com", "/(foo)"},
|
|
|
|
|
{"", "example.com", "/()"},
|
2024-07-20 12:06:23 +02:00
|
|
|
|
// non-ASCII characters are allowed
|
|
|
|
|
{"", u"köln.de"_s, ""},
|
|
|
|
|
{"", u"ü.com"_s, ""},
|
|
|
|
|
{"", u"─.com"_s, ""},
|
2023-04-23 00:58:37 +02:00
|
|
|
|
// test case-insensitiveness
|
|
|
|
|
{"HtTpS://", "127.0.0.1.CoM"},
|
|
|
|
|
{"HTTP://", "XD.CHATTERINO.COM", "/#?FOO"},
|
|
|
|
|
{"HTTPS://", "wikI.chatterino.com"},
|
|
|
|
|
{"", "chatterino.Org", "#foo"},
|
|
|
|
|
{"", "CHATTERINO.com", ""},
|
2023-04-02 16:59:26 +02:00
|
|
|
|
};
|
|
|
|
|
|
2023-04-23 00:58:37 +02:00
|
|
|
|
for (const auto &c : cases)
|
2023-04-02 16:59:26 +02:00
|
|
|
|
{
|
2023-04-23 00:58:37 +02:00
|
|
|
|
c.check();
|
2023-04-02 16:59:26 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(LinkParser, parseIpv4Links)
|
|
|
|
|
{
|
2023-04-23 00:58:37 +02:00
|
|
|
|
const QList<Case> cases = {
|
|
|
|
|
{"https://", "127.0.0.1"},
|
|
|
|
|
{"http://", "127.0.0.1"},
|
|
|
|
|
{"", "127.0.0.1"},
|
|
|
|
|
{"", "127.0.0.1", ":8080"},
|
|
|
|
|
{"", "255.255.255.255"},
|
|
|
|
|
{"", "0.0.0.0"},
|
|
|
|
|
{"", "1.1.1.1"},
|
|
|
|
|
{"", "001.001.01.1"},
|
|
|
|
|
{"", "123.246.87.0"},
|
|
|
|
|
{"", "196.168.4.2", "/foo"},
|
|
|
|
|
{"", "196.168.4.2", "?foo"},
|
|
|
|
|
{"http://", "196.168.4.0", "#foo"},
|
|
|
|
|
{"", "196.168.4.0", "/?#foo"},
|
|
|
|
|
{"", "196.168.4.0", "#?/foo"},
|
|
|
|
|
// test case-insensitiveness
|
|
|
|
|
{"HTTP://", "196.168.4.0", "#Foo"},
|
|
|
|
|
{"HTTPS://", "196.168.4.0", "#Foo"},
|
|
|
|
|
{"htTp://", "127.0.0.1"},
|
|
|
|
|
{"httpS://", "127.0.0.1"},
|
|
|
|
|
|
2023-04-02 16:59:26 +02:00
|
|
|
|
};
|
|
|
|
|
|
2023-04-23 00:58:37 +02:00
|
|
|
|
for (const auto &c : cases)
|
2023-04-02 16:59:26 +02:00
|
|
|
|
{
|
2023-04-23 00:58:37 +02:00
|
|
|
|
c.check();
|
2023-04-02 16:59:26 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(LinkParser, doesntParseInvalidIpv4Links)
|
|
|
|
|
{
|
|
|
|
|
const QStringList inputs = {
|
2024-07-23 23:38:17 +02:00
|
|
|
|
"196.162.a.1",
|
2023-04-23 16:56:39 +02:00
|
|
|
|
// U+0660 - in category "number digits"
|
|
|
|
|
QStringLiteral("٠.٠.٠.٠"),
|
2023-04-02 16:59:26 +02:00
|
|
|
|
"https://127.0.0.",
|
|
|
|
|
"http://127.0.01",
|
|
|
|
|
"127.0.0000.1",
|
|
|
|
|
"1.",
|
|
|
|
|
".127.0.0.1",
|
|
|
|
|
"1.2",
|
|
|
|
|
"1",
|
|
|
|
|
"1.2.3",
|
2023-04-23 00:58:37 +02:00
|
|
|
|
"htt://256.255.255.255",
|
|
|
|
|
"aliens://256.255.255.255",
|
2023-04-23 16:56:39 +02:00
|
|
|
|
"256.255.255.255",
|
|
|
|
|
"http://256.255.255.255",
|
|
|
|
|
"255.256.255.255",
|
|
|
|
|
"255.255.256.255",
|
|
|
|
|
"255.255.255.256",
|
2024-07-14 11:17:42 +02:00
|
|
|
|
":127.0.0.1",
|
|
|
|
|
">1.2.3.4",
|
|
|
|
|
"?196.162.8.1",
|
|
|
|
|
"!196.162.8.1",
|
|
|
|
|
".196.162.8.1",
|
|
|
|
|
",196.162.8.1",
|
|
|
|
|
":196.162.8.1",
|
|
|
|
|
"+196.162.8.1",
|
|
|
|
|
"196.162.8.1<",
|
|
|
|
|
"196.162.8.1(())",
|
|
|
|
|
"196.162.8.1(",
|
|
|
|
|
"196.162.8.1(!",
|
2024-07-20 12:06:23 +02:00
|
|
|
|
"127.1.1;.com",
|
2024-07-23 23:38:17 +02:00
|
|
|
|
"127.0.-.1",
|
|
|
|
|
"127...",
|
|
|
|
|
"1.1.1.",
|
|
|
|
|
"1.1.1.:80",
|
2023-04-02 16:59:26 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (const auto &input : inputs)
|
|
|
|
|
{
|
2024-07-14 11:17:42 +02:00
|
|
|
|
auto p = linkparser::parse(input);
|
|
|
|
|
ASSERT_FALSE(p.has_value()) << input;
|
2023-04-02 16:59:26 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(LinkParser, doesntParseInvalidLinks)
|
|
|
|
|
{
|
|
|
|
|
const QStringList inputs = {
|
|
|
|
|
"h://foo.com",
|
|
|
|
|
"spotify:1234",
|
|
|
|
|
"ftp://chatterino.com",
|
|
|
|
|
"ftps://chatterino.com",
|
|
|
|
|
"spotify://chatterino.com",
|
|
|
|
|
"httpsx://chatterino.com",
|
|
|
|
|
"https:chatterino.com",
|
2023-04-23 00:58:37 +02:00
|
|
|
|
"https:/chatterino.com",
|
|
|
|
|
"http:/chatterino.com",
|
|
|
|
|
"htp://chatterino.com",
|
2023-04-02 16:59:26 +02:00
|
|
|
|
"/chatterino.com",
|
|
|
|
|
"word",
|
|
|
|
|
".",
|
|
|
|
|
"/",
|
|
|
|
|
"#",
|
|
|
|
|
":",
|
|
|
|
|
"?",
|
|
|
|
|
"a",
|
|
|
|
|
"://chatterino.com",
|
|
|
|
|
"//chatterino.com",
|
2023-05-07 14:15:36 +02:00
|
|
|
|
"http://pn.",
|
|
|
|
|
"http://pn./",
|
|
|
|
|
"https://pn./",
|
|
|
|
|
"pn./",
|
|
|
|
|
"pn.",
|
2024-07-23 23:38:17 +02:00
|
|
|
|
"pn.:80",
|
|
|
|
|
"pn./foo",
|
|
|
|
|
"pn.#foo",
|
|
|
|
|
"pn.?foo",
|
2023-05-07 14:15:36 +02:00
|
|
|
|
"http/chatterino.com",
|
|
|
|
|
"http/wiki.chatterino.com",
|
|
|
|
|
"http:cat.com",
|
|
|
|
|
"https:cat.com",
|
|
|
|
|
"http:/cat.com",
|
|
|
|
|
"http:/cat.com",
|
|
|
|
|
"https:/cat.com",
|
2024-07-14 11:17:42 +02:00
|
|
|
|
"chatterino.com-",
|
|
|
|
|
"<<>>",
|
|
|
|
|
">><<",
|
|
|
|
|
"a.com>><<",
|
|
|
|
|
"~~a.com()",
|
|
|
|
|
"https://chatterino.com><https://chatterino.com",
|
|
|
|
|
"<https://chatterino.com><https://chatterino.com>",
|
2024-07-20 12:06:23 +02:00
|
|
|
|
"chatterino.com><chatterino.com",
|
|
|
|
|
"https://chatterino.com><chatterino.com",
|
|
|
|
|
"<chatterino.com><chatterino.com>",
|
|
|
|
|
"<https://chatterino.com><chatterino.com>",
|
|
|
|
|
"info@example.com",
|
|
|
|
|
"user:pass@example.com",
|
|
|
|
|
":.com",
|
|
|
|
|
"a:.com",
|
|
|
|
|
"1:.com",
|
|
|
|
|
"[a].com",
|
|
|
|
|
"`a`.com",
|
|
|
|
|
"{a}.com",
|
|
|
|
|
"a.com:pass@example.com",
|
|
|
|
|
"@@@.com",
|
|
|
|
|
"%%%.com",
|
|
|
|
|
"*.com",
|
2024-07-21 16:00:12 +02:00
|
|
|
|
"example.com(foo)",
|
|
|
|
|
"example.com()",
|
2023-04-02 16:59:26 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (const auto &input : inputs)
|
|
|
|
|
{
|
2024-07-14 11:17:42 +02:00
|
|
|
|
auto p = linkparser::parse(input);
|
|
|
|
|
ASSERT_FALSE(p.has_value()) << input;
|
2023-04-02 16:59:26 +02:00
|
|
|
|
}
|
|
|
|
|
}
|