harden(data): 句柄 emit done 移出 try + catch(...) 兜底 + parse 抛异常测试(评审 I-1/M-5)

This commit is contained in:
gaozheng 2026-06-11 20:31:07 +08:00
parent bb602e2011
commit 8cdd6679a9
2 changed files with 32 additions and 2 deletions

View File

@ -14,11 +14,19 @@ ApiChartLoad::ApiChartLoad(geopro::net::ApiBatch* batch, Parser parse, QObject*
QObject::connect(batch, &geopro::net::ApiBatch::succeeded, this,
[this](const QList<geopro::net::ApiResponse>& resps) {
if (aborted_) return; // §5.0
ChartParts parts;
try {
emit done(parse_(resps));
parts = parse_(resps); // 仅解析在 try 内:下游 done 处理器抛出不应误报为解析失败
} catch (const std::exception& e) {
emit failed(QString::fromUtf8(e.what()));
deleteLater();
return;
} catch (...) { // 非 std 异常跨信号槽会 terminate兜底转 failed
emit failed(QStringLiteral("解析失败:未知异常"));
deleteLater();
return;
}
emit done(parts);
deleteLater();
});
QObject::connect(batch, &geopro::net::ApiBatch::failed, this,
@ -41,11 +49,19 @@ ApiGridLoad::ApiGridLoad(geopro::net::ApiBatch* batch, Parser parse, QObject* pa
QObject::connect(batch, &geopro::net::ApiBatch::succeeded, this,
[this](const QList<geopro::net::ApiResponse>& resps) {
if (aborted_) return;
GridParts parts;
try {
emit done(parse_(resps));
parts = parse_(resps); // 仅解析在 try 内:下游 done 处理器抛出不应误报为解析失败
} catch (const std::exception& e) {
emit failed(QString::fromUtf8(e.what()));
deleteLater();
return;
} catch (...) {
emit failed(QStringLiteral("解析失败:未知异常"));
deleteLater();
return;
}
emit done(parts);
deleteLater();
});
QObject::connect(batch, &geopro::net::ApiBatch::failed, this,

View File

@ -1,4 +1,5 @@
#include <gtest/gtest.h>
#include <stdexcept>
#include <QSignalSpy>
#include "api/DatasetLoadHandles.hpp"
#include "net/FakeApiCall.hpp"
@ -40,6 +41,19 @@ TEST(DatasetLoadHandles, ChartLoadEmitsFailedOnBatchFailure) {
EXPECT_EQ(failSpy.count(), 1);
}
TEST(DatasetLoadHandles, ChartLoadEmitsFailedWhenParseThrows) {
auto* a = new FakeApiCall;
auto* batch = new ApiBatch({a}, isFailure);
auto* load = new ApiChartLoad(batch, [](const QList<ApiResponse>&) -> ChartParts {
throw std::runtime_error("parse boom");
});
QSignalSpy doneSpy(load, &ChartLoad::done);
QSignalSpy failSpy(load, &ChartLoad::failed);
a->fire(ok()); // batch 成功 → parse 抛异常 → failedemit done 已移出 try
EXPECT_EQ(doneSpy.count(), 0);
EXPECT_EQ(failSpy.count(), 1);
}
TEST(DatasetLoadHandles, GridLoadAbortSuppressesLateDone) {
auto* a = new FakeApiCall;
auto* batch = new ApiBatch({a}, isFailure);