Files
galaxy-game/internal/controller/planet_test.go
T
2026-02-06 20:08:39 +02:00

389 lines
16 KiB
Go

package controller_test
import (
"slices"
"testing"
"github.com/google/uuid"
"github.com/iliadenisov/galaxy/internal/controller"
e "github.com/iliadenisov/galaxy/internal/error"
"github.com/iliadenisov/galaxy/internal/model/game"
"github.com/iliadenisov/galaxy/internal/number"
"github.com/stretchr/testify/assert"
)
func TestRenamePlanet(t *testing.T) {
c, g := newCache()
assert.Equal(t, "Planet_0", c.MustPlanet(R0_Planet_0_num).Name)
assert.NoError(t, g.RenamePlanet(Race_0.Name, int(R0_Planet_0_num), "Home_World"))
assert.Equal(t, "Home_World", c.MustPlanet(R0_Planet_0_num).Name)
assert.ErrorContains(t,
g.RenamePlanet("UnknownRace", int(R0_Planet_0_num), "Home_World"),
e.GenericErrorText(e.ErrInputUnknownRace))
assert.ErrorContains(t,
g.RenamePlanet(Race_0.Name, -1, "Home_World"),
e.GenericErrorText(e.ErrInputPlanetNumber))
assert.ErrorContains(t,
g.RenamePlanet(Race_0.Name, 500, "Home_World"),
e.GenericErrorText(e.ErrInputEntityNotExists))
assert.ErrorContains(t,
g.RenamePlanet(Race_0.Name, int(R1_Planet_1_num), "Home_World"),
e.GenericErrorText(e.ErrInputEntityNotOwned))
}
func TestPlanetProduction(t *testing.T) {
c, g := newCache()
scienceName := "Drive_Shields"
assert.NoError(t, g.CreateScience(Race_0.Name, scienceName, 0.4, 0, 0.6, 0))
assert.Len(t, c.RaceScience(Race_0_idx), 1)
scID := c.RaceScience(Race_0_idx)[0].ID
assert.Equal(t, "-", c.PlanetProductionDisplayName(3))
pn := int(R0_Planet_0_num)
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "MAT", ""))
assert.Equal(t, game.ProductionMaterial, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Material", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "CAP", ""))
assert.Equal(t, game.ProductionCapital, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Capital", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "Weapons", "500"))
assert.Equal(t, game.ResearchWeapons, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Weapons", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "cargo", ""))
assert.Equal(t, game.ResearchCargo, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Cargo", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "SHIELDS", scienceName))
assert.Equal(t, game.ResearchShields, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Shields", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "DrivE", ""))
assert.Equal(t, game.ResearchDrive, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.Equal(t, "Drive", c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "Science", scienceName))
assert.Equal(t, game.ResearchScience, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.Nil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Equal(t, scID, *c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Equal(t, scienceName, c.PlanetProductionDisplayName(R0_Planet_0_num))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "SHIP", Race_0_Gunship))
assert.Equal(t, game.ProductionShip, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
st := c.MustShipClass(Race_0_idx, Race_0_Gunship)
assert.Equal(t, st.ID, *c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
assert.Equal(t, st.Name, c.PlanetProductionDisplayName(R0_Planet_0_num))
pn = int(R0_Planet_2_num)
assert.ErrorContains(t,
g.PlanetProduction("UnknownRace", pn, "DRIVE", ""),
e.GenericErrorText(e.ErrInputUnknownRace))
assert.ErrorContains(t,
g.PlanetProduction(Race_0.Name, pn, "Hyperdrive", ""),
e.GenericErrorText(e.ErrInputProductionInvalid))
assert.ErrorContains(t,
g.PlanetProduction(Race_0.Name, -1, "DRIVE", ""),
e.GenericErrorText(e.ErrInputPlanetNumber))
assert.ErrorContains(t,
g.PlanetProduction(Race_0.Name, 500, "DRIVE", ""),
e.GenericErrorText(e.ErrInputEntityNotExists))
assert.ErrorContains(t,
g.PlanetProduction(Race_0.Name, int(R1_Planet_1_num), "DRIVE", ""),
e.GenericErrorText(e.ErrInputEntityNotOwned))
assert.ErrorContains(t,
g.PlanetProduction(Race_0.Name, pn, "Science", ""),
e.GenericErrorText(e.ErrInputEntityTypeNameInvalid))
assert.ErrorContains(t,
g.PlanetProduction(Race_0.Name, pn, "SHIP", ""),
e.GenericErrorText(e.ErrInputEntityTypeNameInvalid))
assert.ErrorContains(t,
g.PlanetProduction(Race_0.Name, pn, "Science", "Winning"),
e.GenericErrorText(e.ErrInputEntityNotExists))
assert.ErrorContains(t,
g.PlanetProduction(Race_0.Name, pn, "SHIP", "Drone"),
e.GenericErrorText(e.ErrInputEntityNotExists))
}
func TestPlanetProductionCapacity(t *testing.T) {
c, _ := newCache()
assert.NoError(t, c.CreateShips(Race_0_idx, ShipType_Cruiser, R0_Planet_0_num, 1))
assert.Equal(t, 100., c.PlanetProductionCapacity(R0_Planet_0_num))
c.UpgradeShipGroup(0, game.TechDrive, 1.6)
assert.Equal(t, 53.125, c.PlanetProductionCapacity(R0_Planet_0_num))
}
func TestProduceShips(t *testing.T) {
c, g := newCache()
pn := int(R0_Planet_0_num)
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "SHIP", Race_0_Gunship))
assert.Equal(t, game.ProductionShip, c.MustPlanet(R0_Planet_0_num).Production.Type)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
st := c.MustShipClass(Race_0_idx, Race_0_Gunship)
assert.Equal(t, st.ID, *c.MustPlanet(R0_Planet_0_num).Production.SubjectID)
c.MustPlanet(R0_Planet_0_num).Size = 1000.
c.MustPlanet(R0_Planet_0_num).Population = 1000.
c.MustPlanet(R0_Planet_0_num).Industry = 1000.
c.MustPlanet(R0_Planet_0_num).Resources = 10.
shipMass := st.EmptyMass()
c.TurnPlanetProductions()
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 0)
assert.NotNil(t, c.MustPlanet(R0_Planet_0_num).Production.Progress)
progress := *c.MustPlanet(R0_Planet_0_num).Production.Progress
assert.InDelta(t, 0.45, progress.F(), 0.001)
assert.NoError(t, c.CreateShipType(Race_0_idx, "Drone", 1, 0, 0, 0, 0))
assert.NoError(t, c.CreateShips(Race_0_idx, "Drone", uint(pn), 7))
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 1)
assert.Equal(t, uint(7), c.ShipGroup(0).Number)
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "SHIP", "Drone"))
assert.InDelta(t, shipMass*progress.F(), c.MustPlanet(R0_Planet_0_num).Material.F(), 0.00001) // 99.(0099) material build
c.MustPlanet(R0_Planet_0_num).Material = 0
c.MustPlanet(R0_Planet_0_num).Colonists = 0
c.TurnPlanetProductions()
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 1)
assert.Equal(t, uint(106), c.ShipGroup(0).Number)
progress = *c.MustPlanet(R0_Planet_0_num).Production.Progress
assert.InDelta(t, 0.0099, progress.F(), 0.00001) // 1.(0099) drones with no CAP on planet
}
func TestProduceShip(t *testing.T) {
Drone := game.ShipType{
Name: "Drone",
Drive: 1,
Armament: 0,
Weapons: 0,
Shields: 0,
Cargo: 0,
}
BattleShip := game.ShipType{
Name: "BattleShip",
Drive: 25,
Armament: 1,
Weapons: 30,
Shields: 35,
Cargo: 0,
}
TestShipCargo1 := game.ShipType{
Name: "Cargo1",
Drive: 30.18,
Armament: 0,
Weapons: 0.,
Shields: 0.,
Cargo: 19.,
}
TestShipDROCOLZ := game.ShipType{
Name: "DROCOLZ",
Drive: 11.32,
Armament: 0,
Weapons: 0,
Shields: 0,
Cargo: 1,
}
TestShipElephant := game.ShipType{
Name: "ElEphant",
Drive: 80,
Armament: 30,
Weapons: 50,
Shields: 100,
Cargo: 0,
}
id := uuid.New()
var r uint
hw := controller.NewPlanet(0, "Planet_0", &id, 1, 1, 1000, 1000, 1000, 10, game.ProductionShip.AsType(uuid.Nil))
//
// documented data
//
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), Drone.EmptyMass())
assert.Equal(t, uint(99), r)
assert.InDelta(t, 0.0099, (*hw.Production.Progress).F(), 0.000001)
assert.Equal(t, 0.009900990099, (*hw.Production.Progress).F()) // 0.0099 % = 99.0099 mass production per turn
(&hw).Production = game.ProductionShip.AsType(uuid.Nil)
(&hw).Material = 100. // no material deficit
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), Drone.EmptyMass())
assert.Equal(t, uint(100), r)
assert.Equal(t, 0., (*hw.Production.Progress).F())
assert.Equal(t, 0., hw.Material.F())
(&hw).Production = game.ProductionShip.AsType(uuid.Nil)
(&hw).Material = 0.
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), BattleShip.EmptyMass())
assert.Equal(t, uint(1), r)
assert.InDelta(t, 0.1, (*hw.Production.Progress).F(), 0.001)
(&hw).Production = game.ProductionShip.AsType(uuid.Nil)
(&hw).Material = 900. // no material deficit
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), BattleShip.EmptyMass())
assert.Equal(t, uint(1), r)
assert.Equal(t, number.Fixed12(1./9.), (*hw.Production.Progress).F())
//
// real report data
//
dw1 := controller.NewPlanet(0, "DW2", &id, 1, 1, 500, 500, 500, 10, game.ProductionShip.AsType(uuid.Nil))
dw2 := controller.NewPlanet(0, "DW1", &id, 1, 1, 500, 500, 500, 10, game.ProductionShip.AsType(uuid.Nil))
(&dw1).Material = 0.0
r = controller.ProduceShip(&dw1, dw1.ProductionCapacity(), TestShipDROCOLZ.EmptyMass())
assert.Equal(t, uint(4), r)
assert.Equal(t, 2.272, (*dw1.Production.ProdUsed).F())
(&dw2).Material = 0.0
r = controller.ProduceShip(&dw2, dw2.ProductionCapacity(), TestShipCargo1.EmptyMass())
assert.Equal(t, uint(1), r)
assert.Equal(t, 3.282, (*dw2.Production.ProdUsed).F())
// production stopped and extra MAT released
(&dw2).ReleaseMaterial(TestShipCargo1.EmptyMass())
assert.Equal(t, 0.32495049505, (&dw2).Material.F()) // from report: 0.32
// building new ship with extra MAT
r = controller.ProduceShip(&dw2, dw2.ProductionCapacity(), TestShipDROCOLZ.EmptyMass())
assert.Equal(t, uint(4), r)
assert.Equal(t, 2.304495049505, (*dw2.Production.ProdUsed).F()) // from report: 2.3
//
// insufficient production capacity to produce single ship at one turn
//
assert.Greater(t, TestShipElephant.EmptyMass(), 100.)
// one turn
(&hw).Production = game.ProductionShip.AsType(uuid.Nil)
(&hw).Material = 0.
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), TestShipElephant.EmptyMass())
assert.Equal(t, uint(0), r)
assert.Equal(t, 0., (&hw).Material.F())
assert.InDelta(t, 0.1, (*hw.Production.Progress).F(), 0.01)
(&hw).ReleaseMaterial(TestShipElephant.EmptyMass())
assert.Equal(t, 99.009900990099, (&hw).Material.F())
// two turns
(&hw).Production = game.ProductionShip.AsType(uuid.Nil)
(&hw).Material = 0.
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), TestShipElephant.EmptyMass())
assert.Equal(t, uint(0), r)
assert.Equal(t, 0., (&hw).Material.F())
assert.InDelta(t, 0.1, (*hw.Production.Progress).F(), 0.01)
r = controller.ProduceShip(&hw, hw.ProductionCapacity(), TestShipElephant.EmptyMass())
assert.Equal(t, uint(0), r)
assert.Equal(t, 0., (&hw).Material.F())
assert.InDelta(t, 0.2, (*hw.Production.Progress).F(), 0.01)
(&hw).ReleaseMaterial(TestShipElephant.EmptyMass())
assert.Equal(t, 198.019801980198, (&hw).Material.F())
}
func TestListProducingPlanets(t *testing.T) {
c, g := newCache()
c.MustPlanet(0).Production = game.ProductionNone.AsType(uuid.Nil)
c.MustPlanet(1).Production = game.ProductionNone.AsType(uuid.Nil)
c.MustPlanet(2).Production = game.ProductionNone.AsType(uuid.Nil)
planets := slices.Collect(c.ListProducingPlanets())
assert.Len(t, planets, 0)
assert.NoError(t, g.PlanetProduction(Race_0.Name, int(R0_Planet_0_num), "CAP", ""))
planets = slices.Collect(c.ListProducingPlanets())
assert.Len(t, planets, 1)
assert.Equal(t, R0_Planet_0_num, c.MustPlanet(planets[0]).Number)
assert.NoError(t, g.PlanetProduction(Race_0.Name, int(R0_Planet_2_num), "SHIP", Race_0_Gunship))
planets = slices.Collect(c.ListProducingPlanets())
assert.Len(t, planets, 2)
assert.Equal(t, R0_Planet_2_num, c.MustPlanet(planets[0]).Number)
assert.Equal(t, R0_Planet_0_num, c.MustPlanet(planets[1]).Number)
}
func TestTurnPlanetProductions(t *testing.T) {
c, g := newCache()
assert.NoError(t, c.CreateShipType(Race_0_idx, "Drone", 1, 0, 0, 0, 0))
assert.NoError(t, g.CreateScience(Race_0.Name, "Equality", 0.25, 0.25, 0.25, 0.25))
c.MustPlanet(R0_Planet_0_num).Resources = 10.
c.MustPlanet(R0_Planet_0_num).Size = 1000.
c.MustPlanet(R0_Planet_0_num).Population = 1000.
c.MustPlanet(R0_Planet_0_num).Industry = 1000.
pn := int(R0_Planet_0_num)
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "CAP", ""))
assert.Equal(t, 0.0, c.MustPlanet(R0_Planet_0_num).Capital.F())
assert.Equal(t, 0.0, c.MustPlanet(R0_Planet_0_num).Colonists.F())
c.TurnPlanetProductions()
assert.InDelta(t, 196., c.MustPlanet(R0_Planet_0_num).Capital.F(), 0.1)
assert.Equal(t, 10.0, c.MustPlanet(R0_Planet_0_num).Colonists.F())
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "MAT", ""))
assert.Equal(t, 0.0, c.MustPlanet(R0_Planet_0_num).Material.F())
c.TurnPlanetProductions()
assert.Equal(t, 10000., c.MustPlanet(R0_Planet_0_num).Material.F())
assert.InDelta(t, 20.0, c.MustPlanet(R0_Planet_0_num).Colonists.F(), 0.000001)
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "DRIVE", ""))
assert.Equal(t, 1.1, c.Race(Race_0_idx).TechLevel(game.TechDrive))
c.TurnPlanetProductions()
assert.Equal(t, 1.3, c.Race(Race_0_idx).TechLevel(game.TechDrive))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "WEAPONS", ""))
assert.Equal(t, 1.2, c.Race(Race_0_idx).TechLevel(game.TechWeapons))
c.TurnPlanetProductions()
assert.Equal(t, 1.4, c.Race(Race_0_idx).TechLevel(game.TechWeapons))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "SHIELDS", ""))
assert.Equal(t, 1.3, c.Race(Race_0_idx).TechLevel(game.TechShields))
c.TurnPlanetProductions()
assert.Equal(t, 1.5, c.Race(Race_0_idx).TechLevel(game.TechShields))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "CARGO", ""))
assert.Equal(t, 1.4, c.Race(Race_0_idx).TechLevel(game.TechCargo))
c.TurnPlanetProductions()
assert.Equal(t, 1.6, c.Race(Race_0_idx).TechLevel(game.TechCargo))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "SCIENCE", "Equality"))
c.TurnPlanetProductions()
assert.Equal(t, 1.35, c.Race(Race_0_idx).TechLevel(game.TechDrive))
assert.Equal(t, 1.45, c.Race(Race_0_idx).TechLevel(game.TechWeapons))
assert.Equal(t, 1.55, c.Race(Race_0_idx).TechLevel(game.TechShields))
assert.Equal(t, 1.65, c.Race(Race_0_idx).TechLevel(game.TechCargo))
assert.NoError(t, g.PlanetProduction(Race_0.Name, pn, "SHIP", "Drone"))
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 0)
c.TurnPlanetProductions()
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 1)
assert.Equal(t, uint(100), c.ShipGroup(0).Number)
}