geopro/tests/controller/test_dataset_detail_control...

178 lines
7.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <gtest/gtest.h>
#include <QSignalSpy>
#include <QVariant>
#include "DatasetDetailController.hpp"
#include "DatasetDetailTab.hpp"
#include "IDatasetChartStrategy.hpp"
#include "repo/IAsyncDatasetRepository.hpp"
#include "api/DatasetLoadHandles.hpp"
using namespace geopro;
namespace {
// 反演策略桩:散点(非 lazy) + 网格(lazy) 两页签。
struct InversionStrategy : controller::IDatasetChartStrategy {
std::string ddCode() const override { return "dd_inversion_data"; }
std::vector<controller::TabSpec> tabs() const override {
return {
{QStringLiteral("原数据"), controller::ViewKind::Scatter,
QStringLiteral("inversion.scatter"), /*lazy*/ false, /*paginated*/ false},
{QStringLiteral("网格数据"), controller::ViewKind::FilledContour,
QStringLiteral("inversion.grid"), /*lazy*/ true, /*paginated*/ false},
};
}
};
// 单页签策略桩(仅一个非 lazy 页签)。
struct SingleTabStrategy : controller::IDatasetChartStrategy {
std::string ddCode() const override { return "dd_scatter_only"; }
std::vector<controller::TabSpec> tabs() const override {
return {{QStringLiteral("散点"), controller::ViewKind::Scatter,
QStringLiteral("scatter.only"), /*lazy*/ false, /*paginated*/ false}};
}
};
// 注册了反演策略的注册表(多数用例复用)。
controller::ChartStrategyRegistry makeInversionRegistry() {
controller::ChartStrategyRegistry reg;
reg.add(std::make_unique<InversionStrategy>());
return reg;
}
// 桩详情句柄:不声明 Q_OBJECT —— 发射继承自 data::DetailLoad 的信号、override abort。
struct StubDetailLoad : data::DetailLoad {
bool aborted = false;
void abort() override { aborted = true; }
void fireDone() { emit done(QVariant{}); }
void fireFailed() { emit failed(QStringLiteral("x")); }
};
// 桩仓储:每个 loaderKey 都造一个新句柄,记录最近一个用于 fire。
struct StubAsyncRepo : data::IAsyncDatasetRepository {
StubDetailLoad* last = nullptr;
data::DetailLoad* loadAsync(const std::string&, const std::string&) override {
last = new StubDetailLoad;
return last;
}
};
} // namespace
TEST(DatasetDetailController, OpenEmitsDatasetOpenedWithTabsAndDdCode) {
StubAsyncRepo repo;
auto reg = makeInversionRegistry();
controller::DatasetDetailController c(repo, reg);
QSignalSpy spy(&c, &controller::DatasetDetailController::datasetOpened);
c.openDataset("ds1", "dd_inversion_data", "名称");
ASSERT_EQ(spy.count(), 1);
const auto args = spy.takeFirst();
EXPECT_EQ(args.at(0).toString(), QStringLiteral("ds1"));
EXPECT_EQ(args.at(1).toString(), QStringLiteral("dd_inversion_data")); // ddCode 透传
EXPECT_EQ(args.at(2).toString(), QStringLiteral("名称"));
}
TEST(DatasetDetailController, OpenLoadsNonLazyTabsOnly) {
StubAsyncRepo repo;
auto reg = makeInversionRegistry();
controller::DatasetDetailController c(repo, reg);
QSignalSpy started(&c, &controller::DatasetDetailController::tabLoadStarted);
c.openDataset("ds1", "dd_inversion_data");
// 反演tab0 非 lazy 自动加载tab1 lazy 不加载。
ASSERT_EQ(started.count(), 1);
EXPECT_EQ(started.takeFirst().at(1).toInt(), 0);
}
TEST(DatasetDetailController, EmitsTabReadyOnDone) {
StubAsyncRepo repo;
auto reg = makeInversionRegistry();
controller::DatasetDetailController c(repo, reg);
QSignalSpy spy(&c, &controller::DatasetDetailController::tabReady);
c.openDataset("ds1", "dd_inversion_data");
repo.last->fireDone();
ASSERT_EQ(spy.count(), 1);
EXPECT_EQ(spy.takeFirst().at(1).toInt(), 0); // tabIndex 0
}
TEST(DatasetDetailController, EmitsLoadFailedOnFailed) {
StubAsyncRepo repo;
auto reg = makeInversionRegistry();
controller::DatasetDetailController c(repo, reg);
QSignalSpy spy(&c, &controller::DatasetDetailController::loadFailed);
c.openDataset("ds1", "dd_inversion_data");
repo.last->fireFailed();
EXPECT_EQ(spy.count(), 1);
}
TEST(DatasetDetailController, UnsupportedTypeFailsImmediately) {
StubAsyncRepo repo;
auto reg = makeInversionRegistry(); // 注册了反演,但未注册 dd_other
controller::DatasetDetailController c(repo, reg);
QSignalSpy spy(&c, &controller::DatasetDetailController::loadFailed);
c.openDataset("ds1", "dd_other");
EXPECT_EQ(spy.count(), 1);
EXPECT_EQ(repo.last, nullptr); // 未发起加载
}
// 空注册表 → 任意 ddCode 都不支持 → loadFailed不发起加载。
TEST(DatasetDetailController, EmptyRegistryFailsAnyType) {
StubAsyncRepo repo;
controller::ChartStrategyRegistry reg; // 空
controller::DatasetDetailController c(repo, reg);
QSignalSpy spy(&c, &controller::DatasetDetailController::loadFailed);
c.openDataset("ds1", "dd_inversion_data");
EXPECT_EQ(spy.count(), 1);
EXPECT_EQ(repo.last, nullptr);
}
// 越界 tabIndex → loadTab 静默不加载。
TEST(DatasetDetailController, LoadTabOutOfRangeDoesNothing) {
StubAsyncRepo repo;
auto reg = makeInversionRegistry();
controller::DatasetDetailController c(repo, reg);
c.loadTab("ds1", "dd_inversion_data", 99);
EXPECT_EQ(repo.last, nullptr);
}
// lazy 页签经 loadTab 触发后加载。
TEST(DatasetDetailController, LoadTabLazyTabStartsLoad) {
StubAsyncRepo repo;
auto reg = makeInversionRegistry();
controller::DatasetDetailController c(repo, reg);
QSignalSpy ready(&c, &controller::DatasetDetailController::tabReady);
c.loadTab("ds1", "dd_inversion_data", 1); // lazy 网格页
ASSERT_NE(repo.last, nullptr);
repo.last->fireDone();
ASSERT_EQ(ready.count(), 1);
EXPECT_EQ(ready.takeFirst().at(1).toInt(), 1);
}
TEST(DatasetDetailController, AbortsPreviousOnSameSlotReload) {
StubAsyncRepo repo;
auto reg = makeInversionRegistry();
controller::DatasetDetailController c(repo, reg);
c.loadTab("dsA", "dd_inversion_data", 0);
StubDetailLoad* a = repo.last;
c.loadTab("dsB", "dd_inversion_data", 0); // 同槽位替换
EXPECT_TRUE(a->aborted); // 旧句柄被 abort
}
TEST(DatasetDetailController, DropsLateSignalFromAbortedLoad) {
StubAsyncRepo repo;
auto reg = makeInversionRegistry();
controller::DatasetDetailController c(repo, reg);
QSignalSpy spy(&c, &controller::DatasetDetailController::tabReady);
c.loadTab("dsA", "dd_inversion_data", 0);
StubDetailLoad* a = repo.last;
c.loadTab("dsB", "dd_inversion_data", 0); // 同槽位替换
StubDetailLoad* b = repo.last;
a->fireDone(); // 旧句柄迟到 → 身份比对丢弃
EXPECT_EQ(spy.count(), 0);
b->fireDone(); // 当前句柄 → 正常
EXPECT_EQ(spy.count(), 1);
}
TEST(DatasetDetailController, FocusEmitsFocusRequested) {
StubAsyncRepo repo;
auto reg = makeInversionRegistry();
controller::DatasetDetailController c(repo, reg);
QSignalSpy spy(&c, &controller::DatasetDetailController::focusRequested);
c.focusDataset("ds1");
ASSERT_EQ(spy.count(), 1);
EXPECT_EQ(spy.takeFirst().at(0).toString(), QStringLiteral("ds1"));
}