2026-05-15 22:34:22 +08:00
|
|
|
//go:build llm_script
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import "testing"
|
|
|
|
|
|
|
|
|
|
func TestSummarizeSignalEventTypes(t *testing.T) {
|
|
|
|
|
events := []signalModelEvent{
|
|
|
|
|
{EventType: "new_model", ModelName: "A"},
|
|
|
|
|
{EventType: "new_model", ModelName: "B"},
|
|
|
|
|
{EventType: "price_cut", ModelName: "C"},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
counts := summarizeSignalEventTypes(events)
|
|
|
|
|
if counts["new_model"] != 2 {
|
|
|
|
|
t.Fatalf("new_model 计数错误: %d", counts["new_model"])
|
|
|
|
|
}
|
|
|
|
|
if counts["price_cut"] != 1 {
|
|
|
|
|
t.Fatalf("price_cut 计数错误: %d", counts["price_cut"])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestBuildSignalPageMode(t *testing.T) {
|
|
|
|
|
if got := buildSignalPageMode(signalDailySignals{}, nil); got != "calm" {
|
|
|
|
|
t.Fatalf("平静日 page_mode 错误: %q", got)
|
|
|
|
|
}
|
|
|
|
|
if got := buildSignalPageMode(signalDailySignals{NewModels: 2, PriceChanges: 1}, nil); got != "hot" {
|
|
|
|
|
t.Fatalf("高变化日 page_mode 错误: %q", got)
|
|
|
|
|
}
|
|
|
|
|
if got := buildSignalPageMode(signalDailySignals{}, []signalModelEvent{{EventType: "official_release"}}); got != "hot" {
|
|
|
|
|
t.Fatalf("官方发布日 page_mode 错误: %q", got)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-27 18:54:32 +08:00
|
|
|
|
|
|
|
|
func TestBuildSignalPageModeTreatsVerifiedDiscoveryPromoAsHot(t *testing.T) {
|
|
|
|
|
got := buildSignalPageMode(signalDailySignals{}, []signalModelEvent{{EventType: "promo_campaign", ModelName: "GPT-5.6"}})
|
|
|
|
|
if got != "hot" {
|
|
|
|
|
t.Fatalf("已验证活动事件应触发 hot, got=%q", got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestFilterDiscoveryEventsDropsLeakAndCandidateOnly(t *testing.T) {
|
|
|
|
|
events := []signalModelEvent{
|
|
|
|
|
{EventType: "official_release", ModelName: "GPT-5.6", Priority: 120},
|
|
|
|
|
{EventType: "leak_or_rumor", ModelName: "GPT-5.6", Priority: 200},
|
|
|
|
|
{EventType: "unknown", ModelName: "Mystery", Priority: 50},
|
|
|
|
|
}
|
|
|
|
|
filtered := filterVerifiedDiscoverySignalEvents(events)
|
|
|
|
|
if len(filtered) != 1 {
|
|
|
|
|
t.Fatalf("期望仅保留 1 条正式事实事件, got=%d", len(filtered))
|
|
|
|
|
}
|
|
|
|
|
if filtered[0].EventType != "official_release" {
|
|
|
|
|
t.Fatalf("错误保留了非正式事件: %+v", filtered)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMergeVerifiedDiscoveryEventsPrefersNativeFact(t *testing.T) {
|
|
|
|
|
native := []signalModelEvent{{
|
|
|
|
|
EventType: "official_release",
|
|
|
|
|
ModelName: "GPT-5.6",
|
|
|
|
|
ProviderName: "OpenAI",
|
|
|
|
|
PrimarySource: "native_release",
|
|
|
|
|
EvidenceDetail: "native evidence",
|
|
|
|
|
Priority: 120,
|
|
|
|
|
}}
|
|
|
|
|
discovery := []signalModelEvent{{
|
|
|
|
|
EventType: "official_release",
|
|
|
|
|
ModelName: "GPT-5.6",
|
|
|
|
|
ProviderName: "OpenAI",
|
|
|
|
|
PrimarySource: "discovery_release",
|
|
|
|
|
EvidenceDetail: "discovery evidence",
|
|
|
|
|
SourceKindLabel: "官方博客",
|
|
|
|
|
Priority: 110,
|
|
|
|
|
}}
|
|
|
|
|
merged := mergeVerifiedDiscoveryEvents(native, discovery)
|
|
|
|
|
if len(merged) != 1 {
|
|
|
|
|
t.Fatalf("期望去重后只剩 1 条事件, got=%d", len(merged))
|
|
|
|
|
}
|
|
|
|
|
if merged[0].PrimarySource != "native_release" {
|
|
|
|
|
t.Fatalf("原生事实不应被 discovery 覆盖: %+v", merged[0])
|
|
|
|
|
}
|
|
|
|
|
if merged[0].SourceKindLabel != "官方博客" {
|
|
|
|
|
t.Fatalf("原生事实应补入 discovery 证据缺口: %+v", merged[0])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMergeVerifiedDiscoveryEventsDropsUnverifiedPriceNarrative(t *testing.T) {
|
|
|
|
|
native := []signalModelEvent{{EventType: "new_model", ModelName: "DeepSeek-V4-Flash", ProviderName: "DeepSeek", Priority: 80}}
|
|
|
|
|
discovery := []signalModelEvent{{EventType: "leak_or_rumor", ModelName: "DeepSeek-V4-Flash", ProviderName: "DeepSeek", Priority: 130}}
|
|
|
|
|
merged := mergeVerifiedDiscoveryEvents(native, discovery)
|
|
|
|
|
if len(merged) != 1 || merged[0].EventType != "new_model" {
|
|
|
|
|
t.Fatalf("非正式 discovery 事件不应进入正式快照: %+v", merged)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-27 22:01:20 +08:00
|
|
|
|
|
|
|
|
func TestBuildDeepSeekNewsDriftEvent(t *testing.T) {
|
|
|
|
|
row := officialImportSignatureAuditViewRow{
|
|
|
|
|
SourceKey: "deepseek_news_signature",
|
|
|
|
|
Status: "drift_detected",
|
|
|
|
|
StructureState: "changed",
|
|
|
|
|
StructureChanged: true,
|
|
|
|
|
DriftDetected: true,
|
|
|
|
|
BaselineInitialized: false,
|
|
|
|
|
StructureSHA256: "abc123",
|
|
|
|
|
}
|
|
|
|
|
event, ok := buildDeepSeekSignatureSignalEvent(row, deepseekSignatureEventConfig{
|
|
|
|
|
SourceKey: "deepseek_news_signature",
|
|
|
|
|
ModelName: "DeepSeek 官方新闻页",
|
|
|
|
|
SourceKindLabel: "官方新闻页结构变化",
|
|
|
|
|
PrimaryURL: defaultDeepSeekNewsSignalURL,
|
|
|
|
|
Audience: "a",
|
|
|
|
|
EvidenceTemplate: "news drift %s %s",
|
|
|
|
|
Baseline: "官方新闻页结构漂移",
|
|
|
|
|
Summary: "summary",
|
|
|
|
|
Priority: 117,
|
|
|
|
|
})
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatal("期望为 drift 行生成正式信号事件")
|
|
|
|
|
}
|
|
|
|
|
if event.EventType != "official_release" {
|
|
|
|
|
t.Fatalf("DeepSeek drift 应映射为 official_release, got=%q", event.EventType)
|
|
|
|
|
}
|
|
|
|
|
if event.ProviderName != "DeepSeek" || event.ModelName != "DeepSeek 官方新闻页" {
|
|
|
|
|
t.Fatalf("DeepSeek drift 事件主体错误: %+v", event)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestBuildDeepSeekPricingDriftEvent(t *testing.T) {
|
|
|
|
|
row := officialImportSignatureAuditViewRow{
|
|
|
|
|
SourceKey: "deepseek_pricing_signature",
|
|
|
|
|
Status: "drift_detected",
|
|
|
|
|
StructureState: "changed",
|
|
|
|
|
StructureChanged: true,
|
|
|
|
|
DriftDetected: true,
|
|
|
|
|
BaselineInitialized: false,
|
|
|
|
|
StructureSHA256: "pricing123",
|
|
|
|
|
}
|
|
|
|
|
event, ok := buildDeepSeekSignatureSignalEvent(row, deepseekSignatureEventConfig{
|
|
|
|
|
SourceKey: "deepseek_pricing_signature",
|
|
|
|
|
ModelName: "DeepSeek 官方价格页",
|
|
|
|
|
SourceKindLabel: "官方价格页结构变化",
|
|
|
|
|
PrimaryURL: defaultDeepSeekPricingSignalURL,
|
|
|
|
|
Audience: "a",
|
|
|
|
|
EvidenceTemplate: "pricing drift %s %s",
|
|
|
|
|
Baseline: "官方价格页结构漂移",
|
|
|
|
|
Summary: "pricing summary",
|
|
|
|
|
Priority: 116,
|
|
|
|
|
})
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatal("期望为 pricing drift 行生成正式信号事件")
|
|
|
|
|
}
|
|
|
|
|
if event.ModelName != "DeepSeek 官方价格页" || event.SourceKindLabel != "官方价格页结构变化" {
|
|
|
|
|
t.Fatalf("pricing drift 事件映射错误: %+v", event)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestBuildDeepSeekAPIPricingDriftEvent(t *testing.T) {
|
|
|
|
|
row := officialImportSignatureAuditViewRow{
|
|
|
|
|
SourceKey: "deepseek_api_pricing_signature",
|
|
|
|
|
Status: "drift_detected",
|
|
|
|
|
StructureState: "changed",
|
|
|
|
|
StructureChanged: true,
|
|
|
|
|
DriftDetected: true,
|
|
|
|
|
BaselineInitialized: false,
|
|
|
|
|
StructureSHA256: "api123",
|
|
|
|
|
}
|
|
|
|
|
event, ok := buildDeepSeekSignatureSignalEvent(row, deepseekSignatureEventConfig{
|
|
|
|
|
SourceKey: "deepseek_api_pricing_signature",
|
|
|
|
|
ModelName: "DeepSeek API 定价页",
|
|
|
|
|
SourceKindLabel: "官方 API 定价页结构变化",
|
|
|
|
|
PrimaryURL: defaultDeepSeekAPIPricingSignalURL,
|
|
|
|
|
Audience: "a",
|
|
|
|
|
EvidenceTemplate: "api drift %s %s",
|
|
|
|
|
Baseline: "官方 API 定价页结构漂移",
|
|
|
|
|
Summary: "api pricing summary",
|
|
|
|
|
Priority: 115,
|
|
|
|
|
})
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatal("期望为 api pricing drift 行生成正式信号事件")
|
|
|
|
|
}
|
|
|
|
|
if event.ModelName != "DeepSeek API 定价页" || event.SourceKindLabel != "官方 API 定价页结构变化" {
|
|
|
|
|
t.Fatalf("api pricing drift 事件映射错误: %+v", event)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestBuildDeepSeekNewsDriftEventSkipsBaselineOnly(t *testing.T) {
|
|
|
|
|
row := officialImportSignatureAuditViewRow{
|
|
|
|
|
SourceKey: "deepseek_news_signature",
|
|
|
|
|
Status: "baseline_initialized",
|
|
|
|
|
StructureState: "initial",
|
|
|
|
|
StructureChanged: false,
|
|
|
|
|
DriftDetected: false,
|
|
|
|
|
BaselineInitialized: true,
|
|
|
|
|
StructureSHA256: "abc123",
|
|
|
|
|
}
|
|
|
|
|
if _, ok := buildDeepSeekSignatureSignalEvent(row, deepseekSignatureEventConfig{SourceKey: "deepseek_news_signature"}); ok {
|
|
|
|
|
t.Fatal("baseline 初始化不应直接进入正式信号")
|
|
|
|
|
}
|
|
|
|
|
}
|