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