epoch_test.go raw
1 package epoch
2
3 import (
4 "testing"
5
6 "git.smesh.lol/gnarl-hamadryad/ratio"
7 )
8
9 func TestNew(t *testing.T) {
10 tests := []struct {
11 name string
12 decExp int
13 binExp int
14 dec int64
15 bin int64
16 period int64
17 }{
18 {"Colony", 2, 8, 100, 256, 25600},
19 {"EngineDissolveLCM", 2, 4, 100, 16, 1600},
20 {"PureBinary", 0, 10, 1, 1024, 1024},
21 {"PureDecimal", 3, 0, 1000, 1, 1000},
22 {"Unity", 0, 0, 1, 1, 1},
23 {"CryptoWalk256", 3, 1, 1000, 2, 2000},
24 }
25
26 for _, tt := range tests {
27 t.Run(tt.name, func(t *testing.T) {
28 e := New(tt.decExp, tt.binExp)
29 if e.DecFactor != tt.dec {
30 t.Errorf("DecFactor = %d, want %d", e.DecFactor, tt.dec)
31 }
32 if e.BinFactor != tt.bin {
33 t.Errorf("BinFactor = %d, want %d", e.BinFactor, tt.bin)
34 }
35 if e.Period != tt.period {
36 t.Errorf("Period = %d, want %d", e.Period, tt.period)
37 }
38 })
39 }
40 }
41
42 func TestNewPanics(t *testing.T) {
43 tests := []struct {
44 name string
45 decExp int
46 binExp int
47 }{
48 {"NegativeDec", -1, 0},
49 {"NegativeBin", 0, -1},
50 {"BinOverflow", 0, 63},
51 {"DecOverflow", 19, 0}, // 10^19 > int64 max
52 }
53
54 for _, tt := range tests {
55 t.Run(tt.name, func(t *testing.T) {
56 defer func() {
57 if r := recover(); r == nil {
58 t.Errorf("expected panic for New(%d, %d)", tt.decExp, tt.binExp)
59 }
60 }()
61 New(tt.decExp, tt.binExp)
62 })
63 }
64 }
65
66 func TestNamedEpochs(t *testing.T) {
67 tests := []struct {
68 name string
69 epoch Epoch
70 period int64
71 }{
72 {"Colony", Colony, 25600},
73 {"EngineDissolveLCM", EngineDissolveLCM, 1600},
74 {"FitnessSampling", FitnessSampling, 25600},
75 {"CryptoWalk128", CryptoWalk128, 1024},
76 {"CryptoWalk192", CryptoWalk192, 1600},
77 {"CryptoWalk256", CryptoWalk256, 2000},
78 {"EWMACap", EWMACap, 1_000_000_000},
79 }
80
81 for _, tt := range tests {
82 t.Run(tt.name, func(t *testing.T) {
83 if tt.epoch.Period != tt.period {
84 t.Errorf("Period = %d, want %d", tt.epoch.Period, tt.period)
85 }
86 })
87 }
88 }
89
90 func TestOnBoundary(t *testing.T) {
91 e := Colony // Period = 25600
92
93 tests := []struct {
94 n int64
95 want bool
96 }{
97 {0, false},
98 {1, false},
99 {100, false},
100 {256, false},
101 {25599, false},
102 {25600, true},
103 {51200, true},
104 {-25600, false},
105 }
106
107 for _, tt := range tests {
108 if got := e.OnBoundary(tt.n); got != tt.want {
109 t.Errorf("Colony.OnBoundary(%d) = %v, want %v", tt.n, got, tt.want)
110 }
111 }
112 }
113
114 func TestOnDecimal(t *testing.T) {
115 e := Colony // DecFactor = 100
116
117 tests := []struct {
118 n int64
119 want bool
120 }{
121 {0, false},
122 {99, false},
123 {100, true},
124 {200, true},
125 {256, false},
126 {25600, true},
127 }
128
129 for _, tt := range tests {
130 if got := e.OnDecimal(tt.n); got != tt.want {
131 t.Errorf("Colony.OnDecimal(%d) = %v, want %v", tt.n, got, tt.want)
132 }
133 }
134 }
135
136 func TestOnBinary(t *testing.T) {
137 e := Colony // BinFactor = 256
138
139 tests := []struct {
140 n int64
141 want bool
142 }{
143 {0, false},
144 {100, false},
145 {255, false},
146 {256, true},
147 {512, true},
148 {25600, true},
149 }
150
151 for _, tt := range tests {
152 if got := e.OnBinary(tt.n); got != tt.want {
153 t.Errorf("Colony.OnBinary(%d) = %v, want %v", tt.n, got, tt.want)
154 }
155 }
156 }
157
158 func TestPhaseAtBoundary(t *testing.T) {
159 e := Colony
160
161 // At epoch boundaries, phase is zero.
162 if p := e.Phase(0); !p.IsZero() {
163 t.Errorf("Phase(0) = %s, want 0", p)
164 }
165 if p := e.Phase(25600); !p.IsZero() {
166 t.Errorf("Phase(25600) = %s, want 0", p)
167 }
168 if p := e.Phase(51200); !p.IsZero() {
169 t.Errorf("Phase(51200) = %s, want 0", p)
170 }
171 }
172
173 func TestPhaseNonZero(t *testing.T) {
174 e := Colony
175
176 // At step 100: decimal clock at 0/100 (complete cycle), binary at 100/256.
177 // Phase = 100/256 - 0/100 = 25/64.
178 p := e.Phase(100)
179 want := ratio.New(25, 64)
180 if !p.Equal(want) {
181 t.Errorf("Phase(100) = %s, want %s", p, want)
182 }
183
184 // At step 256: binary clock at 0/256 (complete cycle), decimal at 56/100.
185 // Phase = 0/256 - 56/100 = -56/100 = -14/25.
186 p = e.Phase(256)
187 want = ratio.New(-14, 25)
188 if !p.Equal(want) {
189 t.Errorf("Phase(256) = %s, want %s", p, want)
190 }
191 }
192
193 func TestBinaryStepsPerDecimal(t *testing.T) {
194 // Colony: 256/100 = 64/25.
195 r := Colony.BinaryStepsPerDecimal()
196 want := ratio.New(64, 25)
197 if !r.Equal(want) {
198 t.Errorf("Colony.BinaryStepsPerDecimal() = %s, want %s", r, want)
199 }
200 }
201
202 func TestDecimalStepsPerBinary(t *testing.T) {
203 // Colony: 100/256 = 25/64.
204 r := Colony.DecimalStepsPerBinary()
205 want := ratio.New(25, 64)
206 if !r.Equal(want) {
207 t.Errorf("Colony.DecimalStepsPerBinary() = %s, want %s", r, want)
208 }
209 }
210
211 func TestImagPhaseAtBoundary(t *testing.T) {
212 e := Colony
213 // At epoch boundaries, both clocks are at 0, so Im = 0*0 = 0.
214 if p := e.ImagPhase(0); !p.IsZero() {
215 t.Errorf("ImagPhase(0) = %s, want 0", p)
216 }
217 if p := e.ImagPhase(25600); !p.IsZero() {
218 t.Errorf("ImagPhase(25600) = %s, want 0", p)
219 }
220 }
221
222 func TestImagPhaseAtDecBoundary(t *testing.T) {
223 e := Colony // BinFactor=256, DecFactor=100
224 // At step 100: binFrac=100/256=25/64, decFrac=0/100=0. Im=0.
225 if p := e.ImagPhase(100); !p.IsZero() {
226 t.Errorf("ImagPhase(100) = %s, want 0", p)
227 }
228 }
229
230 func TestImagPhaseNonZero(t *testing.T) {
231 e := Colony // BinFactor=256, DecFactor=100
232 // At step 50: binFrac=50/256=25/128, decFrac=50/100=1/2
233 // Im = 25/128 * 1/2 = 25/256
234 p := e.ImagPhase(50)
235 want := ratio.New(25, 256)
236 if !p.Equal(want) {
237 t.Errorf("ImagPhase(50) = %s, want %s", p, want)
238 }
239 }
240
241 func TestComplexPhase(t *testing.T) {
242 e := Colony
243 cp := e.ComplexPhase(50)
244 if !cp.Re.Equal(e.Phase(50)) {
245 t.Errorf("ComplexPhase.Re = %s, want %s", cp.Re, e.Phase(50))
246 }
247 if !cp.Im.Equal(e.ImagPhase(50)) {
248 t.Errorf("ComplexPhase.Im = %s, want %s", cp.Im, e.ImagPhase(50))
249 }
250 }
251
252 func TestString(t *testing.T) {
253 tests := []struct {
254 epoch Epoch
255 want string
256 }{
257 {Colony, "10^2×2^8=25600"},
258 {CryptoWalk128, "10^0×2^10=1024"},
259 {EWMACap, "10^9×2^0=1000000000"},
260 }
261
262 for _, tt := range tests {
263 if got := tt.epoch.String(); got != tt.want {
264 t.Errorf("String() = %q, want %q", got, tt.want)
265 }
266 }
267 }
268