返回 DeepSeek-Reasonix
pareto_test.go
根目录 / cmd / e2ebench / pareto_test.go
1 package main
2
3 import (
4 "strings"
5 "testing"
6 )
7
8 func TestMarkDominatedFindsTheAlarm(t *testing.T) {
9 points := []paretoPoint{
10 {label: "fast-accurate", acc: 90, ttcsMs: 30_000, solved: 9, ran: 10},
11 {label: "reasonix", acc: 70, ttcsMs: 100_000, solved: 7, ran: 10},
12 {label: "slow-accurate", acc: 95, ttcsMs: 150_000, solved: 19, ran: 20},
13 }
14 markDominated(points)
15 if points[1].dominatedBy != "fast-accurate" {
16 t.Errorf("reasonix dominatedBy = %q, want fast-accurate (more accurate and faster)", points[1].dominatedBy)
17 }
18 if points[0].dominatedBy != "" || points[2].dominatedBy != "" {
19 t.Errorf("frontier points must not be dominated: %q / %q", points[0].dominatedBy, points[2].dominatedBy)
20 }
21 }
22
23 func TestMarkDominatedIgnoresUnsolvedArms(t *testing.T) {
24 points := []paretoPoint{
25 {label: "a", acc: 50, ttcsMs: 60_000, solved: 1, ran: 2},
26 {label: "none", acc: 0, ttcsMs: 0, solved: 0, ran: 2},
27 }
28 markDominated(points)
29 if points[0].dominatedBy != "" {
30 t.Errorf("a zero-solve arm must not dominate (ttcs 0 is absence, not speed): %q", points[0].dominatedBy)
31 }
32 }
33
34 func TestPerClassWinners(t *testing.T) {
35 control := armStats{ByClass: map[string]classStats{
36 "atomic-bugfix": {Ran: 2, Solved: 2, TTCS: []int64{15_000, 17_000}},
37 "repo-exploration": {Ran: 2, Solved: 1, TTCS: []int64{20_000}},
38 }}
39 treatment := armStats{ByClass: map[string]classStats{
40 "atomic-bugfix": {Ran: 2, Solved: 2, TTCS: []int64{22_000, 24_000}},
41 "repo-exploration": {Ran: 2, Solved: 2, TTCS: []int64{30_000, 31_000}},
42 "unclassified": {Ran: 1, Solved: 1, TTCS: []int64{5_000}},
43 }}
44 got := perClassWinners([]string{"control.json", "treatment.json"}, []armStats{control, treatment})
45 for _, want := range []string{
46 "### Per-class winners",
47 "| atomic-bugfix | 100% · 17.0s | 100% · 24.0s | control |",
48 "| repo-exploration | 50% · 20.0s | 100% · 31.0s | treatment |",
49 } {
50 if !strings.Contains(got, want) {
51 t.Fatalf("per-class table missing %q:\n%s", want, got)
52 }
53 }
54 if strings.Contains(got, "unclassified") {
55 t.Fatalf("unclassified rows must not render:\n%s", got)
56 }
57 if perClassWinners([]string{"a.json"}, []armStats{control}) != "" {
58 t.Fatal("single arm has no winners to declare")
59 }
60 }
61
62 func TestParetoSectionRendersChartAndVerdicts(t *testing.T) {
63 got := paretoSection([]paretoPoint{
64 {label: "a", acc: 90, ttcsMs: 30_000, solved: 9, ran: 10},
65 {label: "b", acc: 70, ttcsMs: 100_000, solved: 7, ran: 10},
66 {label: "none", acc: 0, ttcsMs: 0, solved: 0, ran: 2},
67 })
68 for _, want := range []string{
69 "### Pareto: accuracy vs TTCS",
70 "Accuracy",
71 "→ TTCS",
72 "A=a", "✗",
73 "✅ `a` is on the Pareto frontier",
74 "⚠️ `b` is **dominated** by `a`",
75 "`none`: no solves",
76 } {
77 if !strings.Contains(got, want) {
78 t.Fatalf("pareto section missing %q:\n%s", want, got)
79 }
80 }
81 if paretoSection([]paretoPoint{{label: "solo", acc: 50, ttcsMs: 1000, solved: 1, ran: 2}}) != "" {
82 t.Fatal("a single arm has no comparison to draw")
83 }
84 }
85
85 lines GO