feat: 完善星表查询与跨版本回归验证
- 将星表名称数据收敛为 TSV/GZIP 单一数据源,补充中文名、别名、英文常用名及宿/垣区域字段 - 增加星表名称表加载校验、旧详情字段一致性校验和 GZIP 漂移检查 - 新增 StarDataByName、StarDataByNameAll、StarDataByNameIn ,统一中英文查询与重名消歧 - 优化日月食半影带、升落曲线和可见性回归测试,补充极区、拓扑及低精度场景覆盖 - 增加 Go 1.16/386 兼容门禁和测试案例,处理旧工具链的分配、拓扑、SVG字节及 ULP 差异 - 补充星表、坐标、日月食和低精度回归用例,完善测试文件与缓存忽略规则
This commit is contained in:
@@ -1,15 +1,20 @@
|
||||
package basic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// starCatalogDigestWant 解码后星表的摘要,锁定逐位一致。
|
||||
const starCatalogDigestWant = "6a538c97a35dfc9fd2ecad2268ec9a15c3efa1bf4f9ee1cff752448c9c5a7a53"
|
||||
const starCatalogDigestWant = "3c3455cdb09e1e46c5d513a6c26743c6fd1753f65754888f97ec585324af39e4"
|
||||
|
||||
func starCatalogDigest(stars []StarData) string {
|
||||
hash := sha256.New()
|
||||
@@ -31,15 +36,15 @@ func starCatalogDigest(stars []StarData) string {
|
||||
for _, v := range []float64{star.Ra, star.Dec, star.Mag, star.PmRA, star.PmDec, star.RadVel, star.RotVel, star.Pc} {
|
||||
writeUint(math.Float64bits(v))
|
||||
}
|
||||
for _, s := range []string{star.ChineseName, star.ChineseAlias, star.ChineseBayerName, star.CommonName,
|
||||
star.CommonAliasName, star.Cst, star.CstChinese} {
|
||||
for _, s := range []string{star.ChineseName, star.ChineseAlias, star.ChineseRegion, star.ChineseBayerName,
|
||||
star.CommonName, star.CommonAliasName, star.Cst, star.CstChinese} {
|
||||
writeString(s)
|
||||
}
|
||||
}
|
||||
return hex.EncodeToString(hash.Sum(nil))
|
||||
}
|
||||
|
||||
func TestStarCatalogDigestMatchesLegacyParser(t *testing.T) {
|
||||
func TestStarCatalogDigestStable(t *testing.T) {
|
||||
if err := LoadStarData(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -47,3 +52,109 @@ func TestStarCatalogDigestMatchesLegacyParser(t *testing.T) {
|
||||
t.Fatalf("star catalog digest = %s, want %s", got, starCatalogDigestWant)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStarCatalogNamesGzipMatchesSource(t *testing.T) {
|
||||
source, err := os.ReadFile("star_catalog_names.tsv")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
reader, err := gzip.NewReader(bytes.NewReader(starCatalogNamesCompressed))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
decompressed, err := io.ReadAll(reader)
|
||||
reader.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(source, decompressed) {
|
||||
t.Fatal("star_catalog_names.tsv.gz is stale; regenerate it from star_catalog_names.tsv")
|
||||
}
|
||||
}
|
||||
|
||||
// starNameLegacyCorrections 旧 .dat 详情与单一表的已知差异;新增名称不在其中。
|
||||
var starNameLegacyCorrections = map[uint16]map[string]bool{
|
||||
390: {"bayer": true, "chinese": true, "cst": true, "cstzh": true},
|
||||
565: {"chinese": true},
|
||||
585: {"chinese": true},
|
||||
1140: {"bayer": true, "chinese": true, "cst": true, "cstzh": true},
|
||||
1151: {"bayer": true, "chinese": true},
|
||||
1180: {"bayer": true, "chinese": true},
|
||||
1324: {"chinese": true},
|
||||
1387: {"chinese": true},
|
||||
1412: {"chinese": true},
|
||||
1656: {"chinese": true},
|
||||
2585: {"bayer": true, "cst": true, "cstzh": true},
|
||||
2590: {"chinese": true},
|
||||
2714: {"chinese": true},
|
||||
2878: {"chinese": true},
|
||||
3314: {"chinese": true},
|
||||
5226: {"chinese": true},
|
||||
5396: {"chinese": true},
|
||||
5533: {"bayer": true, "chinese": true, "cst": true, "cstzh": true},
|
||||
6008: {"bayer": true, "chinese": true, "cst": true, "cstzh": true},
|
||||
6554: {"chinese": true},
|
||||
6636: {"chinese": true},
|
||||
7735: {"chinese": true},
|
||||
8313: {"chinese": true},
|
||||
8556: {"chinese": true},
|
||||
8610: {"bayer": true, "chinese": true, "cst": true, "cstzh": true},
|
||||
8982: {"chinese": true},
|
||||
}
|
||||
|
||||
func TestStarCatalogNameTableMatchesLegacyDetails(t *testing.T) {
|
||||
if err := LoadStarData(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for hr, rec := range hr2name {
|
||||
for field, value := range map[string]string{
|
||||
"chinese": rec.chinese,
|
||||
"aliases": strings.Join(rec.aliases, ";"),
|
||||
"region": rec.region,
|
||||
} {
|
||||
if strings.ContainsAny(value, "[]") {
|
||||
t.Fatalf("HR %d %s has bracket qualifier %q; use the region column", hr, field, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
reader, err := gzip.NewReader(bytes.NewReader(starCatalogCompressed))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
payload, err := io.ReadAll(reader)
|
||||
reader.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, detail, _, err := decodeStarCatalogPayload(payload, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for hr, info := range detail {
|
||||
rec, ok := hr2name[hr]
|
||||
if !ok {
|
||||
t.Fatalf("HR %d has legacy details but no row in star_catalog_names.tsv", hr)
|
||||
}
|
||||
checks := []struct {
|
||||
field string
|
||||
old string
|
||||
new string
|
||||
}{
|
||||
{"chinese", info[0], rec.chinese},
|
||||
{"aliases", info[1], strings.Join(rec.aliases, ";")},
|
||||
{"bayer", info[2], rec.bayerZH},
|
||||
{"common", info[3], rec.common},
|
||||
{"cstzh", info[4], rec.cstZH},
|
||||
{"cst", info[5], rec.cst},
|
||||
}
|
||||
for _, check := range checks {
|
||||
if check.old == "" || check.old == check.new {
|
||||
continue
|
||||
}
|
||||
if starNameLegacyCorrections[hr][check.field] {
|
||||
continue
|
||||
}
|
||||
t.Fatalf("HR %d %s: legacy %q, table %q", hr, check.field, check.old, check.new)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user