//go:build llm_script package main import ( "bytes" "os" "path/filepath" "strings" "testing" ) func TestParseVertexPricingCatalogBuildsRecords(t *testing.T) { raw, err := os.ReadFile(filepath.Join("testdata", "vertex_pricing_sample.html")) if err != nil { t.Fatalf("读取 fixture 失败: %v", err) } records, err := parseVertexPricingCatalog(string(raw)) if err != nil { t.Fatalf("parseVertexPricingCatalog 返回错误: %v", err) } if len(records) != 4 { t.Fatalf("期望 4 条 Vertex 价格记录,实际 %d", len(records)) } if records[0].ModelName != "Gemini 3.1 Pro Preview" { t.Fatalf("首条模型名错误: %q", records[0].ModelName) } if records[1].InputPrice != 0.5 || records[1].OutputPrice != 3 { t.Fatalf("Gemini 3.1 Flash Image 定价错误: %v / %v", records[1].InputPrice, records[1].OutputPrice) } if records[2].InputPrice != 0.25 || records[2].OutputPrice != 1.5 { t.Fatalf("Gemini 3.1 Flash-Lite 定价错误: %v / %v", records[2].InputPrice, records[2].OutputPrice) } } func TestRunVertexPricingImportDryRunPrintsSummary(t *testing.T) { var out bytes.Buffer err := runVertexPricingImport(vertexPricingImportConfig{ URL: defaultVertexPricingURL, Fixture: filepath.Join("testdata", "vertex_pricing_sample.html"), DryRun: true, }, nil, &out) if err != nil { t.Fatalf("runVertexPricingImport 返回错误: %v", err) } output := out.String() for _, want := range []string{ "source=vertex-pricing-import", "models=4", "operator=Google Cloud Vertex AI", "dry_run=true", } { if !strings.Contains(output, want) { t.Fatalf("输出缺少 %q,实际: %q", want, output) } } } func TestParseVertexPricingCatalogAcceptsGenericStandardTableMarkup(t *testing.T) { raw := `

Gemini 2.5

Standard

Model Type Price
Gemini 2.5 Flash
Input (text, image, video) $0.30
Text output $2.50
` records, err := parseVertexPricingCatalog(raw) if err != nil { t.Fatalf("parseVertexPricingCatalog 返回错误: %v", err) } if len(records) != 1 { t.Fatalf("期望 1 条 Vertex 价格记录,实际 %d", len(records)) } if records[0].ModelName != "Gemini 2.5 Flash" { t.Fatalf("模型名错误: %q", records[0].ModelName) } if records[0].InputPrice != 0.3 || records[0].OutputPrice != 2.5 { t.Fatalf("价格解析错误: %v / %v", records[0].InputPrice, records[0].OutputPrice) } } func TestParseVertexPricingCatalogFallsBackToStandardTextBlocks(t *testing.T) { raw := `
### Standard
Model Type Price (/1M tokens) <= 200K input tokens Price (/1M tokens) > 200K input tokens
Gemini 2.5
Flash
Input (text, image, video) $0.54 $0.54 $0.05 $0.05
Audio Input $1.80 $1.80 $0.18 $0.18
Text output (response and reasoning) $4.50 $4.50 N/A N/A
### Flex/Batch
` records, err := parseVertexPricingCatalog(raw) if err != nil { t.Fatalf("parseVertexPricingCatalog 返回错误: %v", err) } if len(records) != 1 { t.Fatalf("期望 1 条 Vertex 价格记录,实际 %d", len(records)) } if records[0].ModelName != "Gemini 2.5 Flash" { t.Fatalf("模型名错误: %q", records[0].ModelName) } if records[0].InputPrice != 0.54 || records[0].OutputPrice != 4.5 { t.Fatalf("价格解析错误: %v / %v", records[0].InputPrice, records[0].OutputPrice) } } func TestParseVertexPricingCatalogSupportsChineseStandardTable(t *testing.T) { raw := `

Gemini 3

标准

模型 类型 价格
Gemini 3 Pro 预览版
输入(文本、图片、视频、音频) $2
文本输出(回答和推理) $12
` records, err := parseVertexPricingCatalog(raw) if err != nil { t.Fatalf("parseVertexPricingCatalog 返回错误: %v", err) } if len(records) != 1 { t.Fatalf("期望 1 条记录,实际 %d", len(records)) } if records[0].ModelName != "Gemini 3 Pro 预览版" { t.Fatalf("模型名错误: %q", records[0].ModelName) } if records[0].InputPrice != 2 || records[0].OutputPrice != 12 { t.Fatalf("价格解析错误: %v / %v", records[0].InputPrice, records[0].OutputPrice) } }