99 lines
4.5 KiB
C++
99 lines
4.5 KiB
C++
#include <gtest/gtest.h>
|
||
#include <clocale>
|
||
#include <cstdint>
|
||
#include <filesystem>
|
||
#include <fstream>
|
||
#include <string>
|
||
#include "core/algo/GprVolumeBuilder.hpp"
|
||
#include "io/gpr/NormalizedRadarVolumeBridge.hpp"
|
||
#ifdef _WIN32
|
||
#include <windows.h>
|
||
#endif
|
||
namespace fs = std::filesystem;
|
||
|
||
namespace {
|
||
// 在指定目录写出一组最小可解析的规范化 .head/.data(K=4 道 M=2 通道 N=3 采样)。
|
||
void writeMinimalLine(const fs::path& head, const fs::path& data) {
|
||
{ std::ofstream f(head);
|
||
f << "SAMPLES:3\nNUMBER_OF_CH:2\nLAST_TRACE:8\nBITS:16\nENDIAN_TYPE:1\n"
|
||
"DISTANCE_INTERVAL:0.1\nTIMEWINDOW:30\nDIELECTRIC:9\n"; }
|
||
{ std::ofstream f(data, std::ios::binary);
|
||
for (int t = 0; t < 4; ++t) for (int c = 0; c < 2; ++c) for (int s = 0; s < 3; ++s) {
|
||
std::int16_t v = static_cast<std::int16_t>(t * 10 + c * 100 + s);
|
||
f.write(reinterpret_cast<const char*>(&v), 2); } }
|
||
}
|
||
} // namespace
|
||
|
||
TEST(NormalizedRadarBridge, BuildsVolumeWithExpectedAxes) {
|
||
// K=4 道, M=2 通道, N=3 采样, 无通道偏移(不插值), coarse=1。
|
||
fs::path dir = fs::temp_directory_path() / "radar_bridge_test";
|
||
fs::create_directories(dir);
|
||
{ std::ofstream f(dir / "L.head");
|
||
f << "SAMPLES:3\nNUMBER_OF_CH:2\nLAST_TRACE:8\nBITS:16\nENDIAN_TYPE:1\n"
|
||
"DISTANCE_INTERVAL:0.1\nTIMEWINDOW:30\nDIELECTRIC:9\n"; }
|
||
{ std::ofstream f(dir / "L.data", std::ios::binary);
|
||
for (int t = 0; t < 4; ++t) for (int c = 0; c < 2; ++c) for (int s = 0; s < 3; ++s) {
|
||
std::int16_t v = static_cast<std::int16_t>(t * 10 + c * 100 + s);
|
||
f.write(reinterpret_cast<const char*>(&v), 2); } }
|
||
const auto b = geopro::io::gpr::buildLineVolumeFromNormalized(
|
||
(dir).string(), "L", /*coarse=*/1, /*targetDy=*/0.0); // targetDy=0 不插值
|
||
EXPECT_EQ(b.vol.nx(), 4); // 道
|
||
EXPECT_EQ(b.vol.ny(), 2); // 通道
|
||
EXPECT_EQ(b.vol.nz(), 3); // 采样
|
||
EXPECT_DOUBLE_EQ(b.spacing[0], 0.1); // dx=DISTANCE_INTERVAL
|
||
EXPECT_GT(b.spacing[2], 0.0); // dz 由 timewindow/dielectric 求得 >0
|
||
EXPECT_NEAR(b.quant.toPhys(b.vol.at(3, 1, 2)), 132.0, b.quant.scale); // t3c1s2=30+100+2
|
||
}
|
||
|
||
// 回归:中文目录路径必须能打开渲染。app 传入的是 QString::toLocal8Bit(),即当前
|
||
// ANSI 代码页(简中=GBK)窄字节。关键复现条件——GUI app 链接 QWebEngine(Chromium)/VTK,
|
||
// 它们在启动时 setlocale(LC_ALL,"") 把 LC_CTYPE 提升为系统 UTF-8 locale;此后窄字符
|
||
// ifstream 会把 GBK 路径字节当 UTF-8 解析 → open 失败(即"打开 .head 失败")。
|
||
// 故本测试显式置 UTF-8 locale 复现该失败面,走宽字符打开(见 io/gpr/LocalPath)守护回归。
|
||
// (纯 "C" locale 下 UCRT 用 CP_ACP=GBK 解窄路径,反而不失败,无法复现——须置 UTF-8。)
|
||
TEST(NormalizedRadarBridge, OpensCjkDirectoryPathUnderUtf8Locale) {
|
||
#ifdef _WIN32
|
||
const std::wstring wname = L"radar_cjk_南同大道";
|
||
const fs::path dir = fs::temp_directory_path() / wname;
|
||
fs::remove_all(dir);
|
||
fs::create_directories(dir);
|
||
writeMinimalLine(dir / L"南同大道_000.head", dir / L"南同大道_000.data");
|
||
|
||
// 模拟 app:宽字符 → 当前 ANSI 代码页(GBK)窄字节,等价 QString::toLocal8Bit()。
|
||
auto toAcp = [](const std::wstring& w) {
|
||
const int n = ::WideCharToMultiByte(CP_ACP, 0, w.data(),
|
||
static_cast<int>(w.size()), nullptr, 0,
|
||
nullptr, nullptr);
|
||
std::string s(static_cast<std::size_t>(n), '\0');
|
||
::WideCharToMultiByte(CP_ACP, 0, w.data(), static_cast<int>(w.size()),
|
||
s.data(), n, nullptr, nullptr);
|
||
return s;
|
||
};
|
||
const std::string dirAcp = toAcp(dir.wstring());
|
||
const std::string prefixAcp = toAcp(L"南同大道_000");
|
||
|
||
// 复现 app 运行期的 UTF-8 C locale(QWebEngine/VTK 所置)——不修复则 narrow open 失败。
|
||
const char* prevC = std::setlocale(LC_ALL, nullptr);
|
||
const std::string savedC = prevC ? prevC : "C";
|
||
std::setlocale(LC_ALL, ".UTF-8");
|
||
|
||
geopro::core::BuiltI16 b;
|
||
try {
|
||
b = geopro::io::gpr::buildLineVolumeFromNormalized(
|
||
dirAcp, prefixAcp, /*coarse=*/1, /*targetDy=*/0.0);
|
||
} catch (...) {
|
||
std::setlocale(LC_ALL, savedC.c_str());
|
||
fs::remove_all(dir);
|
||
throw; // 未修复时会在此抛"打开 .head 失败"→ 测试红,正是回归守护
|
||
}
|
||
std::setlocale(LC_ALL, savedC.c_str());
|
||
|
||
EXPECT_EQ(b.vol.nx(), 4);
|
||
EXPECT_EQ(b.vol.ny(), 2);
|
||
EXPECT_EQ(b.vol.nz(), 3);
|
||
fs::remove_all(dir);
|
||
#else
|
||
GTEST_SKIP() << "中文窄路径打开问题仅 Windows 相关";
|
||
#endif
|
||
}
|