diff options
| author | godosa <godosa@godosa.eu> | 2026-10-06 23:52:03 +0200 |
|---|---|---|
| committer | godosa <godosa@godosa.eu> | 2026-10-06 23:52:03 +0200 |
| commit | 346b1c5195bffc71ceaa9262453e3c189656400b (patch) | |
| tree | 01ac0d31e2724cd6abcc689a5a228e2cbea2f6cf /tests/test_config.py | |
| download | worldgen-346b1c5195bffc71ceaa9262453e3c189656400b.tar.gz worldgen-346b1c5195bffc71ceaa9262453e3c189656400b.zip | |
worldgen: initial public history
Diffstat (limited to 'tests/test_config.py')
| -rw-r--r-- | tests/test_config.py | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..5aafbef --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,182 @@ +import shutil +import tempfile +import unittest +from pathlib import Path + +from mapgen import config as C + +from mapgen.testing import FIXTURE_TOML + +TECT = """ +[[plate]] +id = "a" +seed = [0.0, 0.0] +kind = "continental" +motion = [90.0, 3.0] +[[plate]] +id = "b" +seed = [0.0, 90.0] +kind = "oceanic" +motion = [270.0, 3.0] +""" + + +class ConfigTest(unittest.TestCase): + def setUp(self): + self.tmp = Path(tempfile.mkdtemp()) + (self.tmp / "config").mkdir() + shutil.copy(FIXTURE_TOML, self.tmp / "config" / "world.toml") + (self.tmp / "config" / "tectonics.toml").write_text(TECT) + + def tearDown(self): + shutil.rmtree(self.tmp) + + def test_loads_repo_world(self): + cfg, tect = C.load(self.tmp) + self.assertEqual(cfg["planet"]["radius_km"], 12742.0) + self.assertEqual(len(tect["plate"]), 2) + + def test_out_of_range_is_error(self): + p = self.tmp / "config" / "world.toml" + p.write_text(p.read_text().replace("tilt_deg = 20.0", "tilt_deg = 120.0")) + with self.assertRaisesRegex(C.ConfigError, "tilt_deg"): + C.load(self.tmp) + + def test_missing_key_is_error(self): + p = self.tmp / "config" / "world.toml" + p.write_text(p.read_text().replace("seed = 1296\n", "")) + with self.assertRaisesRegex(C.ConfigError, "seed"): + C.load(self.tmp) + + def test_params_merge_and_typo_guard(self): + cfg = {"erosion": {"k": 0.5}} + self.assertEqual(C.params(cfg, "erosion", {"k": 0.1, "m": 0.5}), {"k": 0.5, "m": 0.5}) + with self.assertRaisesRegex(C.ConfigError, "kk"): + C.params({"erosion": {"kk": 1}}, "erosion", {"k": 0.1}) + + def test_tectonics_validation(self): + (self.tmp / "config" / "tectonics.toml").write_text(TECT.replace('kind = "oceanic"', 'kind = "lava"')) + with self.assertRaisesRegex(C.ConfigError, "kind"): + C.load(self.tmp) + (self.tmp / "config" / "tectonics.toml").write_text(TECT.replace('id = "b"', 'id = "a"')) + with self.assertRaisesRegex(C.ConfigError, "duplicate"): + C.load(self.tmp) + + +REV = """ +[[plateau]] +name = "p1" +center = [-40.0, -18.0] +area_km2 = 3.0e6 +elongation = 1.9 +azimuth_deg = 30.0 +top_m = [1500.0, 3000.0] +[[plateau]] +name = "p2" +center = [0.0, 176.0] +area_km2 = 1.0e6 +top_m = [1000.0, 1500.0] +islands = true +[[land_patch]] +name = "fill" +center = [-10.0, 102.0] +radius_km = 2850.0 +edge_noise = 0.4 +[[zone]] +name = "R1" +field = "o2" +center = [-5.6, -118.8] +radius_km = 3200.0 +v = 1.0 +""" +ERAS = """ +[[event]] +name = "cut" +kind = "disintegrate" +center = [-10.0, 102.0] +radius_km = 3000.0 +depth_m = 3000.0 +[[event]] +name = "aura" +kind = "zone" +shape = "landmass" +seed = [-12.7, 121.5] +reach_km = [500.0, 1000.0] +edge_km = 5.0 +fields = { gravity_g = 0.35, pressure_bar = 2.0, o2_fraction = 0.35, fire_reactivity = 0.5 } +[eras] +order = ["before", "after"] +default = "after" +[eras.before] +label = "Before" +events = [] +[eras.after] +label = "After" +events = ["cut", "aura"] +""" + + +class RevisionConfigTest(unittest.TestCase): + def setUp(self): + self.tmp = Path(tempfile.mkdtemp()) + (self.tmp / "config").mkdir() + shutil.copy(FIXTURE_TOML, self.tmp / "config" / "world.toml") + self._set() + + def tearDown(self): + shutil.rmtree(self.tmp) + + def _set(self, rev=REV, eras=ERAS): + (self.tmp / "config" / "tectonics.toml").write_text(TECT + rev) + (self.tmp / "config" / "eras.toml").write_text(eras) + + def test_valid_revision_config_loads(self): + _, t = C.load(self.tmp) + self.assertEqual([p["name"] for p in t["plateau"]], ["p1", "p2"]) + self.assertEqual([e["name"] for e in C.era_events(t, "after")], ["cut", "aura"]) + self.assertEqual(C.era_events(t, "before"), []) + + def test_era_events_are_cumulative(self): + eras = ERAS.replace('order = ["before", "after"]', 'order = ["before", "mid", "after"]').replace( + '[eras.after]\nlabel = "After"\nevents = ["cut", "aura"]', + '[eras.mid]\nlabel = "Mid"\nevents = ["aura"]\n[eras.after]\nlabel = "After"\nevents = ["cut"]') + self._set(REV, eras) + _, t = C.load(self.tmp) + self.assertEqual([e["name"] for e in C.era_events(t, "mid")], ["aura"]) + self.assertEqual([e["name"] for e in C.era_events(t, "after")], ["aura", "cut"]) + with self.assertRaises(C.ConfigError): + C.era_events(t, "never") + + def test_errors_name_the_problem(self): + dup = '[[plateau]]\nname = "p1"\ncenter = [60.0, 60.0]\narea_km2 = 1e6\ntop_m = [1000.0, 2000.0]\n' + cases = [ + (REV.replace("top_m = [1500.0, 3000.0]", "top_m = [3000.0, 1500.0]"), ERAS, "top_m"), + (REV.replace("center = [0.0, 176.0]", "center = [-41.0, -10.0]"), ERAS, "apart"), + (REV + dup, ERAS, "duplicate"), + (REV.replace('field = "o2"', 'field = "heat"'), ERAS, "field"), + (REV, ERAS.replace("fire_reactivity = 0.5", "sparkle = 1.0"), "sparkle"), + (REV, ERAS.replace('default = "after"', 'default = "later"'), "default"), + (REV, ERAS.replace('events = ["cut", "aura"]', 'events = ["cut", "nope"]'), "nope"), + (REV, ERAS.replace('kind = "disintegrate"', 'kind = "flood"'), "kind"), + (REV, ERAS.replace("edge_km = 5.0\n", ""), "edge_km"), + ] + for rev, eras, needle in cases: + with self.subTest(needle=needle): + self._set(rev, eras) + with self.assertRaises(C.ConfigError) as cm: + C.load(self.tmp) + self.assertIn(needle, str(cm.exception)) + + def test_events_belong_in_eras_toml(self): + (self.tmp / "config" / "tectonics.toml").write_text(TECT + REV + ERAS) + with self.assertRaises(C.ConfigError) as cm: + C.load(self.tmp) + self.assertIn("eras.toml", str(cm.exception)) + + def test_eras_toml_is_not_part_of_the_base_inputs_key(self): + from mapgen import pipeline as P + k = P.inputs_key(self.tmp, 1) + self._set(REV, ERAS.replace("fire_reactivity = 0.5", "fire_reactivity = 0.6")) + self.assertEqual(P.inputs_key(self.tmp, 1), k, "tuning an event must not rebuild the base world") + self._set(REV.replace("v = 1.0", "v = 0.9"), ERAS) + self.assertNotEqual(P.inputs_key(self.tmp, 1), k) |
