split actuators from energy storage
This commit is contained in:
@@ -5,37 +5,37 @@ from physcom.models.combination import Combination
|
||||
from physcom.models.entity import Entity, Dependency
|
||||
|
||||
|
||||
def test_compatible_ground_combo(bicycle, human_pedalling):
|
||||
"""Bicycle + Human Pedalling should be valid."""
|
||||
def test_compatible_ground_combo(bicycle, human_pedalling, food_calories):
|
||||
"""Bicycle + Human Pedalling + Food/Calories should be valid."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[bicycle, human_pedalling])
|
||||
combo = Combination(entities=[bicycle, human_pedalling, food_calories])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status != "p1_fail", f"Unexpected block: {result.violations}"
|
||||
|
||||
|
||||
def test_solar_sail_blocks_with_walking(walking, solar_sail):
|
||||
def test_solar_sail_blocks_with_walking(walking, solar_sail, solar_radiation):
|
||||
"""Walking (ground) + Solar Sail (space) should be blocked by medium mutex."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[walking, solar_sail])
|
||||
combo = Combination(entities=[walking, solar_sail, solar_radiation])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status == "p1_fail"
|
||||
assert any("mutually exclusive" in v for v in result.violations)
|
||||
|
||||
|
||||
def test_spaceship_compatible_with_solar_sail(spaceship, solar_sail):
|
||||
def test_spaceship_compatible_with_solar_sail(spaceship, solar_sail, solar_radiation):
|
||||
"""Spaceship + Solar Sail both need space/vacuum — should not conflict."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[spaceship, solar_sail])
|
||||
combo = Combination(entities=[spaceship, solar_sail, solar_radiation])
|
||||
result = resolver.resolve(combo)
|
||||
# Should not be blocked by atmosphere or medium
|
||||
medium_blocks = [v for v in result.violations if "mutually exclusive" in v]
|
||||
assert len(medium_blocks) == 0
|
||||
|
||||
|
||||
def test_nuclear_reactor_blocks_with_bicycle(bicycle, nuclear_reactor):
|
||||
"""Nuclear reactor min_mass=2000kg vs bicycle max_mass=30kg → range incompatibility."""
|
||||
def test_nuclear_drive_blocks_with_bicycle(bicycle, nuclear_thermal_drive, nuclear_fuel):
|
||||
"""Nuclear drive min_mass=1500kg + fuel min_mass=500kg vs bicycle max_mass=30kg → range incompatibility."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[bicycle, nuclear_reactor])
|
||||
combo = Combination(entities=[bicycle, nuclear_thermal_drive, nuclear_fuel])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status == "p1_fail"
|
||||
assert any("mass" in v.lower() for v in result.violations)
|
||||
@@ -50,7 +50,7 @@ def test_power_density_mismatch_blocks():
|
||||
],
|
||||
)
|
||||
power = Entity(
|
||||
name="TinyPower", dimension="power_source",
|
||||
name="TinyPower", dimension="actuator",
|
||||
dependencies=[
|
||||
Dependency("force", "power_density_w_kg", "0.01", "W/kg", "provides"),
|
||||
],
|
||||
@@ -71,7 +71,7 @@ def test_power_density_under_powered_warning():
|
||||
],
|
||||
)
|
||||
power = Entity(
|
||||
name="WeakPower", dimension="power_source",
|
||||
name="WeakPower", dimension="actuator",
|
||||
dependencies=[
|
||||
Dependency("force", "power_density_w_kg", "50", "W/kg", "provides"),
|
||||
],
|
||||
@@ -91,7 +91,7 @@ def test_requires_vs_excludes():
|
||||
dependencies=[Dependency("environment", "oxygen", "true", None, "requires")],
|
||||
)
|
||||
b = Entity(
|
||||
name="B", dimension="power_source",
|
||||
name="B", dimension="actuator",
|
||||
dependencies=[Dependency("environment", "oxygen", "true", None, "excludes")],
|
||||
)
|
||||
resolver = ConstraintResolver()
|
||||
@@ -101,21 +101,21 @@ def test_requires_vs_excludes():
|
||||
assert any("excludes" in v for v in result.violations)
|
||||
|
||||
|
||||
def test_ice_engine_blocks_with_spaceship(spaceship, ice_engine):
|
||||
def test_ice_engine_blocks_with_spaceship(spaceship, ice_engine, gasoline):
|
||||
"""ICE requires standard atmosphere, spaceship requires vacuum_or_thin → mutex."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[spaceship, ice_engine])
|
||||
combo = Combination(entities=[spaceship, ice_engine, gasoline])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status == "p1_fail"
|
||||
assert any("atmosphere" in v for v in result.violations)
|
||||
|
||||
|
||||
def test_hydrogen_bicycle_valid(bicycle, hydrogen_engine):
|
||||
def test_hydrogen_bicycle_valid(bicycle, hydrogen_engine, hydrogen):
|
||||
"""Hydrogen bike — the README's example of a plausible novel concept."""
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[bicycle, hydrogen_engine])
|
||||
combo = Combination(entities=[bicycle, hydrogen_engine, hydrogen])
|
||||
result = resolver.resolve(combo)
|
||||
# Should pass constraints (mass range is compatible: h2 min 30kg, bike max 30kg)
|
||||
# Should pass constraints (mass range is compatible: h2 engine min 25kg, bike max 30kg)
|
||||
# This is actually a borderline case — let's just verify no hard physics blocks
|
||||
range_blocks = [v for v in result.violations if "mutually exclusive" in v or "atmosphere" in v]
|
||||
assert len(range_blocks) == 0
|
||||
@@ -129,14 +129,14 @@ def test_energy_density_deficit_blocks():
|
||||
Dependency("physical", "energy_density_wh_kg", "2000", "Wh/kg", "range_min"),
|
||||
],
|
||||
)
|
||||
power = Entity(
|
||||
name="Battery", dimension="power_source",
|
||||
storage = Entity(
|
||||
name="Battery", dimension="energy_storage",
|
||||
dependencies=[
|
||||
Dependency("physical", "energy_density_wh_kg", "200", "Wh/kg", "provides"),
|
||||
],
|
||||
)
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[platform, power])
|
||||
combo = Combination(entities=[platform, storage])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status == "p1_fail"
|
||||
assert any("energy density deficit" in v for v in result.violations)
|
||||
@@ -150,14 +150,14 @@ def test_energy_density_under_density_warning():
|
||||
Dependency("physical", "energy_density_wh_kg", "400", "Wh/kg", "range_min"),
|
||||
],
|
||||
)
|
||||
power = Entity(
|
||||
name="Battery", dimension="power_source",
|
||||
storage = Entity(
|
||||
name="Battery", dimension="energy_storage",
|
||||
dependencies=[
|
||||
Dependency("physical", "energy_density_wh_kg", "200", "Wh/kg", "provides"),
|
||||
],
|
||||
)
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[platform, power])
|
||||
combo = Combination(entities=[platform, storage])
|
||||
result = resolver.resolve(combo)
|
||||
assert result.status != "p1_fail"
|
||||
assert any("under-density" in w for w in result.warnings)
|
||||
@@ -172,14 +172,14 @@ def test_energy_density_no_constraint_if_no_provider():
|
||||
],
|
||||
)
|
||||
# Solar Sail-style: no energy_density_wh_kg declared
|
||||
power = Entity(
|
||||
name="Solar Sail", dimension="power_source",
|
||||
actuator = Entity(
|
||||
name="Solar Sail", dimension="actuator",
|
||||
dependencies=[
|
||||
Dependency("force", "power_density_w_kg", "0.01", "W/kg", "provides"),
|
||||
],
|
||||
)
|
||||
resolver = ConstraintResolver()
|
||||
combo = Combination(entities=[platform, power])
|
||||
combo = Combination(entities=[platform, actuator])
|
||||
result = resolver.resolve(combo)
|
||||
density_violations = [v for v in result.violations if "energy density" in v]
|
||||
assert len(density_violations) == 0
|
||||
|
||||
Reference in New Issue
Block a user