返回 DeepSeek-Reasonix
runway_shadow_test.go
根目录 / internal / evidence / runway_shadow_test.go
1 package evidence
2
3 import "testing"
4
5 func drainRunwayShadow(r *runwayShadow, sample OutcomeSample) int {
6 for round := 1; round <= 100; round++ {
7 if r.observe(sample).spent {
8 return round
9 }
10 }
11 return -1
12 }
13
14 func TestRunwayShadowPricesOutcomesWithoutAFixedRoundCliff(t *testing.T) {
15 var repeating runwayShadow
16 if got := drainRunwayShadow(&repeating, OutcomeSample{}); got != runwayStartBalance/runwayRoundCost {
17 t.Errorf("empty rounds lasted %d, want %d", got, runwayStartBalance/runwayRoundCost)
18 }
19
20 var exploring runwayShadow
21 if got := drainRunwayShadow(&exploring, OutcomeSample{Exploration: 1}); got != runwayStartBalance {
22 t.Errorf("exploration rounds lasted %d, want %d", got, runwayStartBalance)
23 }
24
25 for name, sample := range map[string]OutcomeSample{
26 "changing": {Churn: 1},
27 "checking": {Discriminating: 1},
28 } {
29 var productive runwayShadow
30 if got := drainRunwayShadow(&productive, sample); got != -1 {
31 t.Errorf("%s account spent after %d rounds", name, got)
32 }
33 }
34 }
35
36 func TestRunwayShadowIsBoundedAndSeparatesDryFromIdle(t *testing.T) {
37 var r runwayShadow
38 for range 100 {
39 r.observe(OutcomeSample{Discriminating: 1})
40 }
41 if got := drainRunwayShadow(&r, OutcomeSample{Exploration: 1}); got != runwayMaxBalance {
42 t.Errorf("banked account lasted %d exploration rounds, want %d", got, runwayMaxBalance)
43 }
44
45 var counts runwayShadow
46 for range 3 {
47 counts.observe(OutcomeSample{Exploration: 1})
48 }
49 state := counts.observe(OutcomeSample{})
50 if state.idle != 4 || state.dry != 1 {
51 t.Fatalf("quiet round state = %+v, want idle 4 dry 1", state)
52 }
53 state = counts.observe(OutcomeSample{Churn: 1})
54 if state.idle != 0 || state.dry != 0 {
55 t.Fatalf("change state = %+v, want cleared counters", state)
56 }
57 }
58
58 lines GO