#include #include #include #include #include "api/DatasetLoadHandles.hpp" #include "model/detail/DetailPayloads.hpp" #include "net/FakeApiCall.hpp" using namespace geopro::data; using geopro::net::ApiBatch; using geopro::net::ApiResponse; using geopro::net::test::FakeApiCall; using geopro::core::ScatterPayload; namespace { ApiResponse ok() { ApiResponse r; r.code = 200; r.httpStatus = 200; return r; } ApiResponse bad() { ApiResponse r; r.code = 500; r.httpStatus = 200; r.msg = QStringLiteral("boom"); return r; } auto isFailure = [](const ApiResponse& r) { return r.code != 200 || !r.rawError.isEmpty(); }; } // ── 通用详情句柄 ApiDetailLoad(tab 引擎):done(QVariant) / failed / abort 闸门 ── TEST(DatasetLoadHandles, DetailLoadEmitsDoneWithPayloadOnSuccess) { auto* a = new FakeApiCall; auto* b = new FakeApiCall; auto* batch = new ApiBatch({a, b}, isFailure); auto* load = new ApiDetailLoad(batch, [](const QList& resps) { ScatterPayload p; p.scatter.v = std::vector(static_cast(resps.size()), 0.0); // 携带可校验状态 return QVariant::fromValue(p); }); QSignalSpy doneSpy(load, &DetailLoad::done); a->fire(ok()); b->fire(ok()); ASSERT_EQ(doneSpy.count(), 1); QVariant payload = doneSpy.takeFirst().at(0).value(); ASSERT_TRUE(payload.canConvert()); EXPECT_EQ(payload.value().scatter.v.size(), 2u); // round-trip 还原字段 } TEST(DatasetLoadHandles, DetailLoadEmitsFailedOnBatchFailure) { auto* a = new FakeApiCall; auto* batch = new ApiBatch({a}, isFailure); auto* load = new ApiDetailLoad(batch, [](const QList&) { return QVariant{}; }); QSignalSpy failSpy(load, &DetailLoad::failed); a->fire(bad()); EXPECT_EQ(failSpy.count(), 1); } TEST(DatasetLoadHandles, DetailLoadEmitsFailedWhenParseThrows) { auto* a = new FakeApiCall; auto* batch = new ApiBatch({a}, isFailure); auto* load = new ApiDetailLoad(batch, [](const QList&) -> QVariant { throw std::runtime_error("parse boom"); }); QSignalSpy doneSpy(load, &DetailLoad::done); QSignalSpy failSpy(load, &DetailLoad::failed); a->fire(ok()); // batch 成功 → parse 抛 → failed(done 已移出 try) EXPECT_EQ(doneSpy.count(), 0); EXPECT_EQ(failSpy.count(), 1); } TEST(DatasetLoadHandles, DetailLoadAbortSuppressesLateDone) { auto* a = new FakeApiCall; auto* batch = new ApiBatch({a}, isFailure); auto* load = new ApiDetailLoad(batch, [](const QList&) { return QVariant{}; }); QSignalSpy doneSpy(load, &DetailLoad::done); load->abort(); a->fire(ok()); // 迟到 EXPECT_EQ(doneSpy.count(), 0); // 双闸门 }