package calc_test import ( "testing" source "galaxy/calc" bridge "galaxy/core/calc" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // shipFixture is the input set passed to every parity check. Values // are picked to exercise both the typical mid-tech ship and the // invalid weapons/armament pairing path of EmptyMass / // WeaponsBlockMass. type shipFixture struct { name string drive float64 armament uint weapons float64 shields float64 cargo float64 driveTech float64 cargoTech float64 } func fixtures() []shipFixture { return []shipFixture{ { name: "all_zero", drive: 0, armament: 0, weapons: 0, shields: 0, cargo: 0, driveTech: 1, cargoTech: 1, }, { name: "typical_mid_tech", drive: 8, armament: 2, weapons: 5, shields: 3, cargo: 4, driveTech: 1.5, cargoTech: 1.2, }, { name: "heavy_armoured", drive: 3, armament: 5, weapons: 12, shields: 20, cargo: 1, driveTech: 0.8, cargoTech: 0.5, }, { name: "invalid_weapons_no_armament", drive: 5, armament: 0, weapons: 4, shields: 1, cargo: 2, driveTech: 1, cargoTech: 1, }, { name: "invalid_armament_no_weapons", drive: 5, armament: 3, weapons: 0, shields: 1, cargo: 2, driveTech: 1, cargoTech: 1, }, } } func TestDriveEffectiveParity(t *testing.T) { t.Parallel() for _, f := range fixtures() { t.Run(f.name, func(t *testing.T) { t.Parallel() want := source.DriveEffective(f.drive, f.driveTech) got := bridge.DriveEffective(f.drive, f.driveTech) assert.Equal(t, want, got) }) } } func TestEmptyMassParity(t *testing.T) { t.Parallel() for _, f := range fixtures() { t.Run(f.name, func(t *testing.T) { t.Parallel() wantMass, wantOk := source.EmptyMass(f.drive, f.weapons, f.armament, f.shields, f.cargo) gotMass, gotOk := bridge.EmptyMass(f.drive, f.weapons, f.armament, f.shields, f.cargo) assert.Equal(t, wantOk, gotOk) assert.Equal(t, wantMass, gotMass) }) } } func TestWeaponsBlockMassParity(t *testing.T) { t.Parallel() for _, f := range fixtures() { t.Run(f.name, func(t *testing.T) { t.Parallel() wantMass, wantOk := source.WeaponsBlockMass(f.weapons, f.armament) gotMass, gotOk := bridge.WeaponsBlockMass(f.weapons, f.armament) assert.Equal(t, wantOk, gotOk) assert.Equal(t, wantMass, gotMass) }) } } func TestFullMassParity(t *testing.T) { t.Parallel() cases := []struct { name string emptyMass float64 carrying float64 }{ {"zero", 0, 0}, {"empty_only", 25, 0}, {"loaded", 25, 12.5}, {"negative_carrying_clamped_by_caller", 25, -3}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { t.Parallel() want := source.FullMass(c.emptyMass, c.carrying) got := bridge.FullMass(c.emptyMass, c.carrying) assert.Equal(t, want, got) }) } } func TestSpeedParity(t *testing.T) { t.Parallel() cases := []struct { name string driveEffective float64 fullMass float64 }{ {"zero_mass_returns_zero", 12, 0}, {"negative_mass_returns_zero", 12, -1}, {"typical", 12, 30}, {"fast_light_ship", 50, 5}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { t.Parallel() want := source.Speed(c.driveEffective, c.fullMass) got := bridge.Speed(c.driveEffective, c.fullMass) assert.Equal(t, want, got) }) } } func TestCargoCapacityParity(t *testing.T) { t.Parallel() for _, f := range fixtures() { t.Run(f.name, func(t *testing.T) { t.Parallel() want := source.CargoCapacity(f.cargo, f.cargoTech) got := bridge.CargoCapacity(f.cargo, f.cargoTech) assert.Equal(t, want, got) }) } } func TestCarryingMassParity(t *testing.T) { t.Parallel() cases := []struct { name string load float64 cargoTech float64 }{ {"zero_load", 0, 1}, {"negative_load_returns_zero", -5, 1}, {"typical_high_tech", 24, 2}, {"low_tech_amplifies", 24, 0.5}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { t.Parallel() want := source.CarryingMass(c.load, c.cargoTech) got := bridge.CarryingMass(c.load, c.cargoTech) assert.Equal(t, want, got) }) } } // TestDesignerPreviewComposition exercises the exact composition the // ship-class designer performs: empty mass, full-load mass via // CarryingMass(CargoCapacity), max speed at empty, and range at full // load. Catches regressions if a future bridge tweak silently changes // the composition shape. func TestDesignerPreviewComposition(t *testing.T) { t.Parallel() const ( drive = 8.0 armament = uint(2) weapons = 5.0 shields = 3.0 cargo = 4.0 driveTech = 1.5 cargoTech = 1.2 ) emptyMass, ok := bridge.EmptyMass(drive, weapons, armament, shields, cargo) require.True(t, ok) cargoCap := bridge.CargoCapacity(cargo, cargoTech) carryAtFull := bridge.CarryingMass(cargoCap, cargoTech) fullLoadMass := bridge.FullMass(emptyMass, carryAtFull) driveEff := bridge.DriveEffective(drive, driveTech) maxSpeed := bridge.Speed(driveEff, emptyMass) rangePerTurn := bridge.Speed(driveEff, fullLoadMass) wantEmpty, _ := source.EmptyMass(drive, weapons, armament, shields, cargo) wantCap := source.CargoCapacity(cargo, cargoTech) wantCarry := source.CarryingMass(wantCap, cargoTech) wantFull := source.FullMass(wantEmpty, wantCarry) wantDE := source.DriveEffective(drive, driveTech) wantMaxSpeed := source.Speed(wantDE, wantEmpty) wantRange := source.Speed(wantDE, wantFull) assert.Equal(t, wantEmpty, emptyMass) assert.Equal(t, wantCap, cargoCap) assert.Equal(t, wantCarry, carryAtFull) assert.Equal(t, wantFull, fullLoadMass) assert.Equal(t, wantMaxSpeed, maxSpeed) assert.Equal(t, wantRange, rangePerTurn) }