#!/usr/bin/env python3 import importlib.util import unittest from pathlib import Path from engine import maze MODULE_PATH = Path(__file__).resolve().parent / "tools" / "level_editor.py" SPEC = importlib.util.spec_from_file_location("level_editor_module", MODULE_PATH) level_editor = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(level_editor) class LevelEditorLogicTests(unittest.TestCase): def test_compute_canvas_layout_scales_to_viewport(self): layout = level_editor.compute_canvas_layout( maze.LEVEL_WIDTH, maze.LEVEL_HEIGHT, 1200, 900, level_editor.DEFAULT_CELL_SIZE, True, ) self.assertGreater(layout["cell_size"], level_editor.DEFAULT_CELL_SIZE) self.assertAlmostEqual(layout["cell_size"], (900 - level_editor.VIEWPORT_PADDING * 2) / maze.LEVEL_HEIGHT) self.assertAlmostEqual(layout["origin_y"], level_editor.VIEWPORT_PADDING) self.assertGreater(layout["origin_x"], 0) def test_compute_canvas_layout_centers_manual_zoom(self): layout = level_editor.compute_canvas_layout( maze.LEVEL_WIDTH, maze.LEVEL_HEIGHT, 1000, 800, 16, False, ) self.assertEqual(layout["cell_size"], 16) self.assertGreater(layout["origin_x"], 0) self.assertGreater(layout["origin_y"], 0) def test_fit_level_to_dat_size_centers_small_map(self): source = [ [maze.MAP_WALL, maze.MAP_EMPTY], [maze.MAP_TUNNEL, maze.MAP_EMPTY], ] fitted = level_editor.fit_level_to_dat_size(source) self.assertEqual(len(fitted), maze.LEVEL_HEIGHT) self.assertEqual(len(fitted[0]), maze.LEVEL_WIDTH) start_x = (maze.LEVEL_WIDTH - len(source[0])) // 2 start_y = (maze.LEVEL_HEIGHT - len(source)) // 2 self.assertEqual(fitted[start_y][start_x], maze.MAP_WALL) self.assertEqual(fitted[start_y][start_x + 1], maze.MAP_EMPTY) self.assertEqual(fitted[start_y + 1][start_x], maze.MAP_TUNNEL) self.assertEqual(fitted[start_y + 1][start_x + 1], maze.MAP_EMPTY) def test_compute_level_stats_reports_spawnable_default_level(self): level = maze.create_level() stats = level_editor.compute_level_stats(level) self.assertEqual(stats["width"], maze.LEVEL_WIDTH) self.assertEqual(stats["height"], maze.LEVEL_HEIGHT) self.assertEqual(stats["border_openings"], 0) self.assertEqual(stats["component_count"], 1) self.assertGreater(stats["spawnable_count"], 0) self.assertEqual(stats["warnings"], []) def test_compute_level_stats_flags_unusable_map(self): level = [[maze.MAP_WALL for _ in range(maze.LEVEL_WIDTH)] for _ in range(maze.LEVEL_HEIGHT)] stats = level_editor.compute_level_stats(level) self.assertEqual(stats["traversable_count"], 0) self.assertEqual(stats["spawnable_count"], 0) self.assertIn("nessuna cella attraversabile", stats["warnings"]) self.assertIn("nessuna cella EMPTY: niente spawn e niente armi", stats["warnings"]) def test_missing_tkinter_is_reported_cleanly(self): if level_editor.TKINTER_IMPORT_ERROR is None: level_editor.ensure_tkinter_available() return with self.assertRaises(RuntimeError): level_editor.ensure_tkinter_available() if __name__ == "__main__": unittest.main()