84 lines
3.8 KiB
Python
84 lines
3.8 KiB
Python
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()
|