import json import math import sys import unittest from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from task_config import ( # noqa: E402 FLAT_TASK, OBSTACLE_TASK, TERRAIN_PRESETS, build_terrain_layout, deployment_metadata, navigation_candidates, validate_task_config, ) class TaskConfigTest(unittest.TestCase): def test_flat_legacy_request_does_not_override_environment(self): self.assertIsNone(validate_task_config(FLAT_TASK, {}, 42)) self.assertNotIn("terrain", deployment_metadata(FLAT_TASK, None, 42)) def test_layouts_are_bounded_finite_and_leave_flat_spawn_goal(self): for preset in (p for p in TERRAIN_PRESETS if p != "custom_boxes"): with self.subTest(preset=preset): custom = validate_task_config(OBSTACLE_TASK, {"terrainPreset": preset}, 42) layout = build_terrain_layout(custom) self.assertLessEqual(len(layout["boxes"]), 257) self.assertLess(len(json.dumps(layout)), 64 * 1024) self.assertEqual(layout["spawn"], [-5, 0, 0.32]) self.assertEqual(layout["target"], [5, 0]) for box in layout["boxes"]: self.assertTrue(all(math.isfinite(v) for v in box["pos"] + box["size"])) self.assertTrue(all(v > 0 for v in box["size"])) self.assertEqual(box["yaw"], 0) for box in layout["boxes"][1:]: self.assertGreaterEqual(box["pos"][0] - box["size"][0], -4) self.assertLessEqual(box["pos"][0] + box["size"][0], 4) def test_layout_is_deterministic_and_export_is_authoritative(self): custom = validate_task_config(OBSTACLE_TASK, {}, 42) original = build_terrain_layout(custom) self.assertEqual(original, build_terrain_layout(custom)) self.assertNotEqual(original, build_terrain_layout({**custom, "seed": 43})) metadata = deployment_metadata(OBSTACLE_TASK, custom, 42) self.assertEqual(metadata["terrain"], original) self.assertEqual(metadata["observationSize"], 47 + 32 + 2) self.assertEqual(metadata["jointNames"][0], "FL_hip_joint") self.assertEqual(metadata["navigation"]["distanceScale"], 12) self.assertTrue(metadata["sensorCfg"]["includeGround"]) self.assertEqual(metadata["navigation"]["trainingReset"], "random-connected-free-pair") def test_navigation_candidates_are_safe_connected_and_have_distant_fallbacks(self): layout = build_terrain_layout(validate_task_config(OBSTACLE_TASK, {}, 42)) candidates = navigation_candidates(layout) self.assertGreater(len(candidates["points"]), 2) self.assertEqual(len(candidates["componentStarts"]), len(candidates["fallbackPairs"])) for point in candidates["points"]: self.assertTrue(all(abs(value) <= layout["size"] / 2 - 0.55 for value in point)) for box in layout["boxes"][1:]: distance = math.hypot( max(abs(point[0] - box["pos"][0]) - box["size"][0], 0), max(abs(point[1] - box["pos"][1]) - box["size"][1], 0), ) self.assertGreater(distance, candidates["clearance"]) for first, second in candidates["fallbackPairs"]: self.assertGreaterEqual(math.dist(first, second), candidates["minDistance"]) def test_obstacle_count_is_capped_by_spacing_capacity(self): custom = validate_task_config( OBSTACLE_TASK, { "terrainParams": {"size": 8, "spacing": 3, "obstacle_count": 100}, }, 0, ) layout = build_terrain_layout(custom) self.assertEqual(layout["actualObstacleCount"], 2) if __name__ == "__main__": unittest.main()