Files
gxde-ai-see/tests/selftest.cpp
T
shenmo7192 3a73a8c5d1 feat(factory): 内容工厂与链接处理
- 第三栏内容工厂:按拖入类型展示动作,动作按钮本身可接收 drop
- 链接分类:http(s) 按扩展名判定图片/音视频/文档/压缩包/网页
- http 链接动作:打开、下载、另存为、复制、Markdown、复制文件名、待办、问小埃
- 非标准 scheme:尝试打开、复制;thunder 解析 base64 真实地址,magnet 解析 dn
- 文字动作:ICU 分词、正则提取链接、朗读(spd-say)、复制、待办
- 文件/图片动作:打开、提取文字(占位)、生成描述、保存图片、复制路径、待办
- Downloader:异步下载到 XDG 下载目录 / 另存为,面板 toast 提示
- TodoModel:持久化到 todo.json,供「添加到待办」使用
- 无头自测 gxde-ai-see-selftest:链接分类/分词/提取链接/动作匹配
- 合成器 portal 自测脚本 tests/portal(虚拟指针 + GTK 源/目标)
2026-10-30 20:09:01 +08:00

110 lines
4.5 KiB
C++

// SPDX-FileCopyrightText: 2026 GXDE OS Team
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Headless checks for the pure (non widget) parts of the content factory.
#include <QCoreApplication>
#include <QDebug>
#include <QTextStream>
#include "actions/texttools.h"
#include "factory/contentclassifier.h"
#include "factory/factoryactions.h"
#include "factory/linktools.h"
static int failures = 0;
static void check(bool condition, const QString &what)
{
QTextStream out(stdout);
if (condition) {
out << "PASS " << what << "\n";
} else {
out << "FAIL " << what << "\n";
++failures;
}
}
static bool hasAction(const QVector<FactoryAction> &actions, const QString &id)
{
for (const FactoryAction &action : actions) {
if (action.id == id) {
return true;
}
}
return false;
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
// http link with a video extension
const LinkInfo video = LinkTools::parse(QStringLiteral("https://example.com/media/clip.mp4"));
check(video.kind == LinkInfo::Http, "https link recognised");
check(video.extension == QStringLiteral("mp4"), "mp4 extension parsed");
check(video.fileType == QStringLiteral("video"), "mp4 classified as video");
check(hasAction(actionsFor(ContentClassifier::classifyText(QStringLiteral(
"https://example.com/media/clip.mp4"))),
QStringLiteral("download")),
"video link offers download");
check(hasAction(actionsFor(ContentClassifier::classifyText(QStringLiteral(
"https://example.com/media/clip.mp4"))),
QStringLiteral("play")),
"video link offers play");
const LinkInfo image = LinkTools::parse(QStringLiteral("https://example.com/a.png?x=1"));
check(image.fileType == QStringLiteral("image"), "png classified as image");
const LinkInfo page = LinkTools::parse(QStringLiteral("https://example.com/article"));
check(page.fileType == QStringLiteral("page"), "extensionless url is a page");
// thunder:// -> base64("AA" + url + "ZZ")
const QByteArray thunderPayload =
QByteArray("AA") + "http://example.com/file.zip" + QByteArray("ZZ");
const QString thunder =
QStringLiteral("thunder://") + QString::fromLatin1(thunderPayload.toBase64());
const LinkInfo thunderInfo = LinkTools::parse(thunder);
check(thunderInfo.kind == LinkInfo::Custom, "thunder link classified as custom");
check(thunderInfo.decodedUrl == QStringLiteral("http://example.com/file.zip"),
"thunder payload decoded");
check(hasAction(actionsFor(ContentClassifier::classifyText(thunder)),
QStringLiteral("decode")),
"thunder offers decode action");
// magnet
const LinkInfo magnet =
LinkTools::parse(QStringLiteral("magnet:?xt=urn:btih:abc&dn=Some%20File"));
check(magnet.kind == LinkInfo::Custom, "magnet classified as custom");
check(magnet.displayName == QStringLiteral("Some File"), "magnet display name parsed");
// spk://
const LinkInfo spk = LinkTools::parse(QStringLiteral("spk://store/app/com.example"));
check(spk.kind == LinkInfo::Custom, "spk link classified as custom");
// plain text is not a link
const LinkInfo text = LinkTools::parse(QStringLiteral("hello world"));
check(!text.isValid(), "plain text is not a link");
// segmentation
const QStringList words = TextTools::segment(QStringLiteral("我爱北京天安门"));
check(words.size() >= 3, "segmentation produced words");
check(words.contains(QStringLiteral("北京")), "segmentation keeps 北京 together");
// link extraction
const QStringList links = TextTools::extractLinks(
QStringLiteral("看 https://a.example/x?y=1 和 test@example.com,还有 www.b.example"));
check(links.size() == 3, QStringLiteral("extractLinks found 3 links, got %1").arg(links.size()));
// classifier
const DropContent textContent = ContentClassifier::classifyText(QStringLiteral("just words"));
check(textContent.kind == DropContent::Text, "text classified as text");
const DropContent linkContent =
ContentClassifier::classifyText(QStringLiteral("https://example.com/a.zip"));
check(linkContent.kind == DropContent::Link, "link classified as link");
check(hasAction(actionsFor(linkContent), QStringLiteral("save_as")), "link offers save as");
QTextStream(stdout) << (failures == 0 ? "ALL PASS\n" : "FAILURES\n");
return failures == 0 ? 0 : 1;
}