044f2f4381
- 新增半解析、旧模型、自定义与多源堆叠星历实例,提供 Context、Instance、SPK 读取及状态与视位置计算 - 统一太阳、月球和行星实例接口,扩展黄经穿越、留、相位、最近角距、偕日可见、任意高度升落、轨道节点及凌日等天象查询 - 完善日月食、月掩与凌日的月缘剖面、有限盘面接触、站心修正、局地可见性、全球路径和地图输出 - 新增 SVG、GeoJSON、KML 天象输出及凌日、月掩和月缘地形相关缓存与几何求解 - 新增恒星星表导入与查询,支持 CSV、Hipparcos、BSC5、Stellarium 等格式及名称、交叉标识、锥面检索和星等过滤 - 补充 IAU 2006、地球定向、折射消光、大气观测、轨道传播及半解析行星/月球数据支持 - 将默认未来民用时标切换为 TimeScaleLeapHour,更新 2027–2400 农历速查表、中文日期解析和时区边界处理 - 增加事件基线、跨模型回归、几何边界、月缘地形和输出契约测试,完善中英文手册、示例资源、NOTICE 与忽略规则
121 lines
4.5 KiB
Go
121 lines
4.5 KiB
Go
package catalog
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"testing/fstest"
|
|
)
|
|
|
|
func TestStellariumBadFiles(t *testing.T) {
|
|
data := mustFixture(t)
|
|
bigEndianMagic := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(bigEndianMagic, stellariumMagic)
|
|
cases := map[string][]byte{
|
|
"truncated": data[:len(data)-7],
|
|
"trailing": append(append([]byte(nil), data...), 0),
|
|
"bad magic": append([]byte{1, 2, 3, 4}, data[4:]...),
|
|
"short head": data[:20],
|
|
"big endian": append(bigEndianMagic, data[4:]...),
|
|
"bad version": append(append(append([]byte(nil), data[:8]...), 1, 0, 0, 0), data[12:]...),
|
|
}
|
|
for name, input := range cases {
|
|
if _, err := ReadStellariumStars(bytes.NewReader(input), ReadOptions{Strict: true}); err == nil {
|
|
t.Fatalf("%s: strict read should fail", name)
|
|
}
|
|
}
|
|
loose, err := ReadStellariumStars(bytes.NewReader(cases["truncated"]), ReadOptions{})
|
|
if err != nil || loose.Skipped() != 1 || loose.Len() == 0 {
|
|
t.Fatalf("loose truncated read = %d entries, %d skipped, %v", loose.Len(), loose.Skipped(), err)
|
|
}
|
|
}
|
|
|
|
func TestStellariumMaxMagnitude(t *testing.T) {
|
|
data := mustFixture(t)
|
|
dir := fstest.MapFS{"stars_0_0v0_18.cat": &fstest.MapFile{Data: data}}
|
|
all, err := ReadStellariumDir(dir, StellariumOptions{}, ReadOptions{Strict: true})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
bright, err := ReadStellariumDir(dir, StellariumOptions{MaxMagnitude: 0.5}, ReadOptions{Strict: true})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if bright.Len() == 0 || bright.Len() >= all.Len() {
|
|
t.Fatalf("MaxMagnitude 0.5 kept %d of %d", bright.Len(), all.Len())
|
|
}
|
|
for _, entry := range bright.Entries() {
|
|
if entry.Magnitude > 0.5 {
|
|
t.Fatalf("%s V %.2f exceeds limit", entry.ID, entry.Magnitude)
|
|
}
|
|
}
|
|
// 文件头 mag_min = -2.00,阈值更亮时整片跳过。
|
|
none, err := ReadStellariumDir(dir, StellariumOptions{MaxMagnitude: -3}, ReadOptions{Strict: true})
|
|
if err != nil || none.Len() != 0 {
|
|
t.Fatalf("whole shard should be skipped: %d, %v", none.Len(), err)
|
|
}
|
|
}
|
|
|
|
func TestCrossIDBadLength(t *testing.T) {
|
|
data := mustFixture(t)
|
|
crossID, err := os.ReadFile("testdata/cross-id.cat")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dir := fstest.MapFS{
|
|
"stars_0_0v0_18.cat": &fstest.MapFile{Data: data},
|
|
"cross-id.cat": &fstest.MapFile{Data: crossID[:len(crossID)-3]},
|
|
}
|
|
if _, err := ReadStellariumDir(dir, StellariumOptions{CrossID: true}, ReadOptions{Strict: true}); err == nil {
|
|
t.Fatal("cross-id length not a multiple of 21 should fail in strict mode")
|
|
}
|
|
}
|
|
|
|
func TestCDSBadLines(t *testing.T) {
|
|
if _, err := ReadHipparcos2007(strings.NewReader(" 1234 garbage\n"), ReadOptions{Strict: true}); err == nil {
|
|
t.Fatal("short hip2 line should fail in strict mode")
|
|
}
|
|
loose, err := ReadHipparcos2007(strings.NewReader(" 1234 garbage\n"), ReadOptions{})
|
|
if err != nil || loose.Len() != 0 || loose.Skipped() != 1 {
|
|
t.Fatalf("loose hip2 = %d entries, %d skipped, %v", loose.Len(), loose.Skipped(), err)
|
|
}
|
|
}
|
|
|
|
// hipParallaxLine 造一条最小可解析的 hip2 定宽记录,parallax 为 43..50 列的原始文本。
|
|
func hipParallaxLine(parallax string) string {
|
|
line := []byte(strings.Repeat(" ", 160))
|
|
put := func(value string, from, to int) { copy(line[from:to], value) }
|
|
put(" 42", 0, 6)
|
|
put(" 1.00000000", 15, 28)
|
|
put(" -0.20000000", 29, 42)
|
|
put(parallax, 43, 50)
|
|
put(" -1.00000", 51, 59)
|
|
put(" -2.00000", 60, 68)
|
|
put(" -1.4600", 129, 136)
|
|
put(" 0.000", 152, 158)
|
|
return string(line)
|
|
}
|
|
|
|
func TestHipparcosNonFiniteParallax(t *testing.T) {
|
|
for _, parallax := range []string{" +Inf", " -Inf"} {
|
|
input := strings.NewReader(hipParallaxLine(parallax) + "\n")
|
|
if _, err := ReadHipparcos2007(input, ReadOptions{Strict: true}); err == nil {
|
|
t.Fatalf("parallax %q: strict mode should reject a non-finite parallax", parallax)
|
|
}
|
|
loose, err := ReadHipparcos2007(strings.NewReader(hipParallaxLine(parallax)+"\n"), ReadOptions{})
|
|
if err != nil || loose.Len() != 0 || loose.Skipped() != 1 {
|
|
t.Fatalf("parallax %q: loose = %d entries, %d skipped, %v", parallax, loose.Len(), loose.Skipped(), err)
|
|
}
|
|
}
|
|
// 有限的负视差是“按无视差处理”,不能一起被拒。
|
|
fine, err := ReadHipparcos2007(strings.NewReader(hipParallaxLine(" -1.0")+"\n"), ReadOptions{Strict: true})
|
|
if err != nil || fine.Len() != 1 {
|
|
t.Fatalf("finite negative parallax should load: len=%d err=%v", fine.Len(), err)
|
|
}
|
|
if entry, ok := fine.Lookup("HIP 42"); !ok || entry.Coordinate.ParallaxMas != 0 {
|
|
t.Fatalf("finite negative parallax should become 0: %v %v", entry.Coordinate.ParallaxMas, ok)
|
|
}
|
|
}
|