diff --git a/src/data/api/DatasetLoadHandles.cpp b/src/data/api/DatasetLoadHandles.cpp index cd80aa8..ba23173 100644 --- a/src/data/api/DatasetLoadHandles.cpp +++ b/src/data/api/DatasetLoadHandles.cpp @@ -14,11 +14,19 @@ ApiChartLoad::ApiChartLoad(geopro::net::ApiBatch* batch, Parser parse, QObject* QObject::connect(batch, &geopro::net::ApiBatch::succeeded, this, [this](const QList& 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& 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, diff --git a/tests/data/test_dataset_load_handles.cpp b/tests/data/test_dataset_load_handles.cpp index 4dfd038..d0590c7 100644 --- a/tests/data/test_dataset_load_handles.cpp +++ b/tests/data/test_dataset_load_handles.cpp @@ -1,4 +1,5 @@ #include +#include #include #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&) -> 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) { auto* a = new FakeApiCall; auto* batch = new ApiBatch({a}, isFailure);