One directory with sixty scripts stopped being navigable, and the grouping is also the sandbox boundary:
Tools/unreal/ commandlets and the two map builders, with ue_common.py and ue_placement.py as the
shared imports (they need the engine)
Tools/blender/ builders, exporters, the FBX preset, the MPFB character pipeline, blender_screenshots
(they need the Blender Flatpak)
Tools/review/ the visual loop: render_screenshots.sh, judge_screenshot.py, hero_compare.py,
build_comparison_md.py, e2e_asset_check.py, hero_iterate.sh, visual_loop.py,
visual_targets.json
Tools/gen/ image and texture generation: the ComfyUI driver, deterministic texture writers,
reference fetching
Tools/input/ OS-level input injection
root _common.py, check-lfs.sh, addon_compat_probe.py, sibling_asset_audit.py, tests/
Every moved script now resolves the repository root as ../.. and puts the tools root plus its siblings on
sys.path, so 'import ue_common' still works from unreal/. The test suite bootstrap does the same for the five
folders. render_screenshots.sh takes the folder as a third argument to run_cmdlet, and the e2e driver,
hero_iterate.sh and the comparison generator were repointed.
51 README rows now link to their new location, the README gains a Layout section naming each folder's
sandbox, and the architecture notes and Blender README follow the moves.
Verified: 108 tests pass, prettier is clean, judge_screenshot.py and hero_compare.py run from their new
homes, and the e2e run was aborted mid-way (it had been rebuilding an empty DemoMap for 15 minutes) and is
being rerun against the new layout.
92 lines
3.2 KiB
Python
92 lines
3.2 KiB
Python
"""Tests for the pure parts of Tools/character_match.py."""
|
|
|
|
import os
|
|
import sys
|
|
|
|
_TOOLS = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
sys.path.insert(0, _TOOLS)
|
|
for _sub in ("review", "gen", "unreal", "blender", "input"):
|
|
sys.path.insert(0, os.path.join(_TOOLS, _sub))
|
|
|
|
|
|
import os
|
|
import sys
|
|
import unittest
|
|
|
|
from PIL import Image
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
import character_match as cm # noqa: E402
|
|
|
|
|
|
class ColourTests(unittest.TestCase):
|
|
def test_white_is_light_and_neutral(self):
|
|
light, a, b = cm.rgb_to_lab((255, 255, 255))
|
|
self.assertAlmostEqual(light, 100.0, delta=0.2)
|
|
self.assertAlmostEqual(a, 0.0, delta=0.2)
|
|
self.assertAlmostEqual(b, 0.0, delta=0.2)
|
|
|
|
def test_black_is_dark(self):
|
|
self.assertAlmostEqual(cm.rgb_to_lab((0, 0, 0))[0], 0.0, delta=0.1)
|
|
|
|
def test_identical_colours_have_no_distance(self):
|
|
self.assertAlmostEqual(cm.delta_e76(cm.rgb_to_lab((120, 90, 70)),
|
|
cm.rgb_to_lab((120, 90, 70))), 0.0, delta=1e-9)
|
|
|
|
def test_red_green_are_far_apart(self):
|
|
distance = cm.delta_e76(cm.rgb_to_lab((200, 40, 40)), cm.rgb_to_lab((40, 160, 40)))
|
|
self.assertGreater(distance, 40.0)
|
|
|
|
|
|
class MaskTests(unittest.TestCase):
|
|
def _image(self, figure_colour, background_colour):
|
|
image = Image.new("RGB", (60, 100), background_colour)
|
|
pixels = image.load()
|
|
for y in range(20, 90):
|
|
for x in range(25, 35):
|
|
pixels[x, y] = figure_colour
|
|
return image
|
|
|
|
def test_saturated_figure_on_grey_is_found(self):
|
|
mask = cm._subject_mask(self._image((150, 90, 60), (190, 190, 190)))
|
|
box = cm.bbox(mask)
|
|
self.assertIsNotNone(box)
|
|
self.assertLess(box[0], 30)
|
|
self.assertGreater(box[2], 30)
|
|
|
|
def test_grey_frame_yields_empty_mask(self):
|
|
mask = cm._subject_mask(self._image((190, 190, 190), (190, 190, 190)))
|
|
self.assertIsNone(cm.bbox(mask))
|
|
|
|
def test_stats_report_figure_proportions(self):
|
|
mask = Image.new("L", (40, 80), 0)
|
|
pixels = mask.load()
|
|
for y in range(10, 70):
|
|
for x in range(15, 25):
|
|
pixels[x, y] = 255
|
|
stats = cm.mask_stats(mask)
|
|
self.assertEqual(stats["area"], 600)
|
|
self.assertAlmostEqual(stats["aspect"], 6.0, delta=0.01)
|
|
self.assertAlmostEqual(stats["fill"], 1.0, delta=0.01)
|
|
|
|
|
|
class PaletteTests(unittest.TestCase):
|
|
def test_dominant_colour_is_reported(self):
|
|
colours = [(200, 40, 40)] * 90 + [(20, 60, 200)] * 10
|
|
palette = cm.dominant(colours, count=2)
|
|
self.assertEqual(len(palette), 2)
|
|
red, _, _ = cm.rgb_to_lab(palette[0])
|
|
self.assertGreater(red, 30.0)
|
|
|
|
def test_palette_distance_is_zero_for_the_same_palette(self):
|
|
palette = cm.dominant([(200, 40, 40)] * 50)
|
|
self.assertAlmostEqual(cm.palette_delta_e(palette, palette), 0.0, delta=1e-6)
|
|
|
|
def test_empty_palette_is_not_a_number(self):
|
|
self.assertNotEqual(cm.palette_delta_e([], [(1, 2, 3)]),
|
|
cm.palette_delta_e([], [(1, 2, 3)]))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|