| package compat |
|
|
| import ( |
| "encoding/json" |
| "os" |
| "path/filepath" |
| "reflect" |
| "testing" |
|
|
| "ds2api/internal/sse" |
| "ds2api/internal/util" |
| ) |
|
|
| func TestGoCompatSSEFixtures(t *testing.T) { |
| files, err := filepath.Glob(compatPath("fixtures", "sse_chunks", "*.json")) |
| if err != nil { |
| t.Fatalf("glob fixtures failed: %v", err) |
| } |
| if len(files) == 0 { |
| t.Fatal("no sse fixtures found") |
| } |
| for _, fixturePath := range files { |
| name := trimExt(filepath.Base(fixturePath)) |
| expectedPath := compatPath("expected", "sse_"+name+".json") |
|
|
| var fixture struct { |
| Chunk map[string]any `json:"chunk"` |
| ThinkingEnable bool `json:"thinking_enabled"` |
| CurrentType string `json:"current_type"` |
| } |
| mustLoadJSON(t, fixturePath, &fixture) |
|
|
| var expected struct { |
| Parts []map[string]any `json:"parts"` |
| Finished bool `json:"finished"` |
| NewType string `json:"new_type"` |
| ContentFilter bool `json:"content_filter"` |
| ErrorMessage string `json:"error_message"` |
| } |
| mustLoadJSON(t, expectedPath, &expected) |
|
|
| raw, err := json.Marshal(fixture.Chunk) |
| if err != nil { |
| t.Fatalf("marshal fixture %s failed: %v", name, err) |
| } |
| res := sse.ParseDeepSeekContentLine(append([]byte("data: "), raw...), fixture.ThinkingEnable, fixture.CurrentType) |
| gotParts := make([]map[string]any, 0, len(res.Parts)) |
| for _, p := range res.Parts { |
| gotParts = append(gotParts, map[string]any{ |
| "text": p.Text, |
| "type": p.Type, |
| }) |
| } |
| if !reflect.DeepEqual(gotParts, expected.Parts) || |
| res.Stop != expected.Finished || |
| res.NextType != expected.NewType || |
| res.ContentFilter != expected.ContentFilter || |
| res.ErrorMessage != expected.ErrorMessage { |
| t.Fatalf("fixture %s mismatch:\n got parts=%#v finished=%v newType=%q contentFilter=%v errorMessage=%q\nwant parts=%#v finished=%v newType=%q contentFilter=%v errorMessage=%q", |
| name, gotParts, res.Stop, res.NextType, res.ContentFilter, res.ErrorMessage, |
| expected.Parts, expected.Finished, expected.NewType, expected.ContentFilter, expected.ErrorMessage) |
| } |
| } |
| } |
|
|
| func TestGoCompatTokenFixtures(t *testing.T) { |
| var fixture struct { |
| Cases []struct { |
| Name string `json:"name"` |
| Text string `json:"text"` |
| } `json:"cases"` |
| } |
| mustLoadJSON(t, compatPath("fixtures", "token_cases.json"), &fixture) |
|
|
| var expected struct { |
| Cases []struct { |
| Name string `json:"name"` |
| Tokens int `json:"tokens"` |
| } `json:"cases"` |
| } |
| mustLoadJSON(t, compatPath("expected", "token_cases.json"), &expected) |
|
|
| expectByName := map[string]int{} |
| for _, c := range expected.Cases { |
| expectByName[c.Name] = c.Tokens |
| } |
| for _, c := range fixture.Cases { |
| want, ok := expectByName[c.Name] |
| if !ok { |
| t.Fatalf("missing expected token case: %s", c.Name) |
| } |
| got := util.EstimateTokens(c.Text) |
| if got != want { |
| t.Fatalf("token fixture %s mismatch: got=%d want=%d", c.Name, got, want) |
| } |
| } |
| } |
|
|
| func mustLoadJSON(t *testing.T, path string, out any) { |
| t.Helper() |
| b, err := os.ReadFile(path) |
| if err != nil { |
| t.Fatalf("read %s failed: %v", path, err) |
| } |
| if err := json.Unmarshal(b, out); err != nil { |
| t.Fatalf("decode %s failed: %v", path, err) |
| } |
| } |
|
|
| func trimExt(name string) string { |
| if len(name) > 5 && name[len(name)-5:] == ".json" { |
| return name[:len(name)-5] |
| } |
| return name |
| } |
|
|
| func compatPath(parts ...string) string { |
| prefix := []string{"..", "..", "tests", "compat"} |
| return filepath.Join(append(prefix, parts...)...) |
| } |
|
|