134 lines
5.5 KiB
C++
134 lines
5.5 KiB
C++
#include <gtest/gtest.h>
|
||
|
||
#include <cmath>
|
||
|
||
#include <QJsonObject>
|
||
|
||
#include "panels/chart/ScatterDataOps.hpp"
|
||
|
||
using namespace geopro::app;
|
||
using geopro::core::ScatterField;
|
||
|
||
TEST(ScatterDataOps, ValueTypeFromCode) {
|
||
EXPECT_EQ(scatterValueTypeFromCode(QStringLiteral("linearity")), ScatterValueType::Linearity);
|
||
EXPECT_EQ(scatterValueTypeFromCode(QStringLiteral("inverse")), ScatterValueType::Inverse);
|
||
EXPECT_EQ(scatterValueTypeFromCode(QStringLiteral("logarithm")), ScatterValueType::Logarithm);
|
||
// 未知回退线性。
|
||
EXPECT_EQ(scatterValueTypeFromCode(QStringLiteral("xyz")), ScatterValueType::Linearity);
|
||
}
|
||
|
||
TEST(ScatterDataOps, ApplyValueTypeLinearIsIdentity) {
|
||
std::vector<double> v{1.0, 10.0, 100.0};
|
||
auto out = applyScatterValueType(v, ScatterValueType::Linearity);
|
||
ASSERT_EQ(out.size(), 3u);
|
||
EXPECT_DOUBLE_EQ(out[0], 1.0);
|
||
EXPECT_DOUBLE_EQ(out[2], 100.0);
|
||
}
|
||
|
||
TEST(ScatterDataOps, ApplyValueTypeInverse) {
|
||
std::vector<double> v{2.0, 0.0, -4.0};
|
||
auto out = applyScatterValueType(v, ScatterValueType::Inverse);
|
||
EXPECT_DOUBLE_EQ(out[0], 0.5);
|
||
EXPECT_DOUBLE_EQ(out[1], 0.0); // v==0 → 保持 0(避免 inf)
|
||
EXPECT_DOUBLE_EQ(out[2], -0.25);
|
||
}
|
||
|
||
TEST(ScatterDataOps, ApplyValueTypeLog) {
|
||
std::vector<double> v{100.0, 0.0, -5.0};
|
||
auto out = applyScatterValueType(v, ScatterValueType::Logarithm);
|
||
EXPECT_DOUBLE_EQ(out[0], 2.0); // log10(100)
|
||
EXPECT_DOUBLE_EQ(out[1], 0.0); // v<=0 → 保持原值
|
||
EXPECT_DOUBLE_EQ(out[2], -5.0); // v<=0 → 保持原值
|
||
}
|
||
|
||
TEST(ScatterDataOps, CollectIdsForHideTakesVisible) {
|
||
ScatterField f;
|
||
f.id = {"a", "b", "c", ""};
|
||
f.displayStatus = {0, 1, 0, 0}; // a,c 可见;b 隐藏;空 id 跳过
|
||
// 隐藏:取可见点(a, c)。
|
||
auto hideIds = collectScatterIds(f, /*hide*/ true);
|
||
ASSERT_EQ(hideIds.size(), 2);
|
||
EXPECT_EQ(hideIds.at(0).toString().toStdString(), "a");
|
||
EXPECT_EQ(hideIds.at(1).toString().toStdString(), "c");
|
||
}
|
||
|
||
TEST(ScatterDataOps, CollectIdsForShowTakesHidden) {
|
||
ScatterField f;
|
||
f.id = {"a", "b", "c"};
|
||
f.displayStatus = {0, 1, 1}; // b,c 隐藏
|
||
auto showIds = collectScatterIds(f, /*hide*/ false);
|
||
ASSERT_EQ(showIds.size(), 2);
|
||
EXPECT_EQ(showIds.at(0).toString().toStdString(), "b");
|
||
EXPECT_EQ(showIds.at(1).toString().toStdString(), "c");
|
||
}
|
||
|
||
TEST(ScatterDataOps, FilterBodyFields) {
|
||
auto body = buildScatterFilterBody(QStringLiteral("ds1"), QStringLiteral("R0"), -10.5, 200.0);
|
||
EXPECT_EQ(body.value("sourceDsObjectId").toString().toStdString(), "ds1");
|
||
EXPECT_EQ(body.value("sourceVFieldCode").toString().toStdString(), "R0");
|
||
EXPECT_DOUBLE_EQ(body.value("min").toDouble(), -10.5);
|
||
EXPECT_DOUBLE_EQ(body.value("max").toDouble(), 200.0);
|
||
}
|
||
|
||
TEST(ScatterDataOps, SaveRawDataBodyNewHasName) {
|
||
auto body = buildSaveRawDataBody(QStringLiteral("ds1"), /*operationType*/ 1,
|
||
QStringLiteral("新数据"));
|
||
EXPECT_EQ(body.value("dsId").toString().toStdString(), "ds1");
|
||
EXPECT_EQ(body.value("operationType").toInt(), 1);
|
||
EXPECT_TRUE(body.contains("name"));
|
||
EXPECT_EQ(body.value("name").toString().toStdString(), std::string("新数据"));
|
||
}
|
||
|
||
TEST(ScatterDataOps, SaveRawDataBodyOverwriteOmitsName) {
|
||
auto body = buildSaveRawDataBody(QStringLiteral("ds1"), /*operationType*/ 0,
|
||
QStringLiteral("ignored"));
|
||
EXPECT_EQ(body.value("operationType").toInt(), 0);
|
||
EXPECT_FALSE(body.contains("name")); // 覆盖不带 name
|
||
}
|
||
|
||
TEST(ScatterDataOps, ToggledDisplayStatus) {
|
||
// 0=显示 → 1=隐藏;1=隐藏 → 0=显示(对照原版 record.displayStatus ? 0 : 1)。
|
||
EXPECT_EQ(toggledDisplayStatus(0), 1);
|
||
EXPECT_EQ(toggledDisplayStatus(1), 0);
|
||
EXPECT_EQ(toggledDisplayStatus(2), 0); // 非 0 视为隐藏 → 显示
|
||
}
|
||
|
||
TEST(ScatterDataOps, HistogramBinsCountInRange) {
|
||
// 0..10 均匀 11 个点,min=0 max=10 分 5 箱(宽 2):
|
||
// [0,2):0,1 → 2;[2,4):2,3 → 2;[4,6):4,5 → 2;[6,8):6,7 → 2;[8,10]:8,9,10 → 3(末箱右闭)。
|
||
std::vector<double> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||
auto h = buildScatterHistogram(v, 0.0, 10.0, 5);
|
||
ASSERT_EQ(h.counts.size(), 5u);
|
||
EXPECT_DOUBLE_EQ(h.step, 2.0);
|
||
EXPECT_EQ(h.counts[0], 2);
|
||
EXPECT_EQ(h.counts[1], 2);
|
||
EXPECT_EQ(h.counts[2], 2);
|
||
EXPECT_EQ(h.counts[3], 2);
|
||
EXPECT_EQ(h.counts[4], 3); // 末箱含恰等于 max 的点
|
||
}
|
||
|
||
TEST(ScatterDataOps, HistogramSkipsOutOfRangeAndNonFinite) {
|
||
std::vector<double> v{-5, 0, 5, 10, 15, std::nan("")};
|
||
auto h = buildScatterHistogram(v, 0.0, 10.0, 2);
|
||
ASSERT_EQ(h.counts.size(), 2u);
|
||
// 区间外(-5,15)与 NaN 跳过;保留 0,5,10。
|
||
// [0,5):0 → 1;[5,10]:5,10 → 2。
|
||
EXPECT_EQ(h.counts[0], 1);
|
||
EXPECT_EQ(h.counts[1], 2);
|
||
}
|
||
|
||
TEST(ScatterDataOps, HistogramDegenerateReturnsEmpty) {
|
||
std::vector<double> v{1, 2, 3};
|
||
EXPECT_TRUE(buildScatterHistogram(v, 5.0, 5.0, 10).counts.empty()); // min==max
|
||
EXPECT_TRUE(buildScatterHistogram(v, 0.0, 10.0, 0).counts.empty()); // binCount<=0
|
||
}
|
||
|
||
TEST(ScatterDataOps, CountInRangeClosedInterval) {
|
||
std::vector<double> v{0, 5, 10, 15, -3, std::nan("")};
|
||
// 闭区间 [0,10]:0,5,10 计入;15、-3 区间外;NaN 跳过。
|
||
EXPECT_EQ(countScatterInRange(v, 0.0, 10.0), 3);
|
||
EXPECT_EQ(countScatterInRange(v, 5.0, 5.0), 1); // 单点闭区间
|
||
EXPECT_EQ(countScatterInRange(v, 10.0, 0.0), 0); // max<min → 0
|
||
EXPECT_EQ(countScatterInRange(v, 100.0, 200.0), 0); // 全在区间外
|
||
}
|