harden(data): 句柄 emit done 移出 try + catch(...) 兜底 + parse 抛异常测试(评审 I-1/M-5)
This commit is contained in:
parent
bb602e2011
commit
8cdd6679a9
|
|
@ -14,11 +14,19 @@ ApiChartLoad::ApiChartLoad(geopro::net::ApiBatch* batch, Parser parse, QObject*
|
||||||
QObject::connect(batch, &geopro::net::ApiBatch::succeeded, this,
|
QObject::connect(batch, &geopro::net::ApiBatch::succeeded, this,
|
||||||
[this](const QList<geopro::net::ApiResponse>& resps) {
|
[this](const QList<geopro::net::ApiResponse>& resps) {
|
||||||
if (aborted_) return; // §5.0
|
if (aborted_) return; // §5.0
|
||||||
|
ChartParts parts;
|
||||||
try {
|
try {
|
||||||
emit done(parse_(resps));
|
parts = parse_(resps); // 仅解析在 try 内:下游 done 处理器抛出不应误报为解析失败
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
emit failed(QString::fromUtf8(e.what()));
|
emit failed(QString::fromUtf8(e.what()));
|
||||||
|
deleteLater();
|
||||||
|
return;
|
||||||
|
} catch (...) { // 非 std 异常跨信号槽会 terminate,兜底转 failed
|
||||||
|
emit failed(QStringLiteral("解析失败:未知异常"));
|
||||||
|
deleteLater();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
emit done(parts);
|
||||||
deleteLater();
|
deleteLater();
|
||||||
});
|
});
|
||||||
QObject::connect(batch, &geopro::net::ApiBatch::failed, this,
|
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,
|
QObject::connect(batch, &geopro::net::ApiBatch::succeeded, this,
|
||||||
[this](const QList<geopro::net::ApiResponse>& resps) {
|
[this](const QList<geopro::net::ApiResponse>& resps) {
|
||||||
if (aborted_) return;
|
if (aborted_) return;
|
||||||
|
GridParts parts;
|
||||||
try {
|
try {
|
||||||
emit done(parse_(resps));
|
parts = parse_(resps); // 仅解析在 try 内:下游 done 处理器抛出不应误报为解析失败
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
emit failed(QString::fromUtf8(e.what()));
|
emit failed(QString::fromUtf8(e.what()));
|
||||||
|
deleteLater();
|
||||||
|
return;
|
||||||
|
} catch (...) {
|
||||||
|
emit failed(QStringLiteral("解析失败:未知异常"));
|
||||||
|
deleteLater();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
emit done(parts);
|
||||||
deleteLater();
|
deleteLater();
|
||||||
});
|
});
|
||||||
QObject::connect(batch, &geopro::net::ApiBatch::failed, this,
|
QObject::connect(batch, &geopro::net::ApiBatch::failed, this,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#include <stdexcept>
|
||||||
#include <QSignalSpy>
|
#include <QSignalSpy>
|
||||||
#include "api/DatasetLoadHandles.hpp"
|
#include "api/DatasetLoadHandles.hpp"
|
||||||
#include "net/FakeApiCall.hpp"
|
#include "net/FakeApiCall.hpp"
|
||||||
|
|
@ -40,6 +41,19 @@ TEST(DatasetLoadHandles, ChartLoadEmitsFailedOnBatchFailure) {
|
||||||
EXPECT_EQ(failSpy.count(), 1);
|
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 抛异常 → failed(emit done 已移出 try)
|
||||||
|
EXPECT_EQ(doneSpy.count(), 0);
|
||||||
|
EXPECT_EQ(failSpy.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(DatasetLoadHandles, GridLoadAbortSuppressesLateDone) {
|
TEST(DatasetLoadHandles, GridLoadAbortSuppressesLateDone) {
|
||||||
auto* a = new FakeApiCall;
|
auto* a = new FakeApiCall;
|
||||||
auto* batch = new ApiBatch({a}, isFailure);
|
auto* batch = new ApiBatch({a}, isFailure);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue