From 684d483460c6b34e61aa198fa0342a90de40605e Mon Sep 17 00:00:00 2001 From: royliz3090-jpg Date: Thu, 25 Jun 2026 01:08:49 +0000 Subject: [PATCH 1/2] Add module validation helpers and --list-modules flag --- build.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/build.py b/build.py index fb33aa14..b96d75a1 100644 --- a/build.py +++ b/build.py @@ -600,6 +600,75 @@ def print_summary(results: list[tuple[str, bool, float, str, Optional[str]]]): f"{color(str(failed) + ' failed', Colors.RED)}, " f"{total_time:.1f}s total") +# --------------------------------------------------------------------------- +# MODULE VALIDATION HELPERS +# --------------------------------------------------------------------------- + +def parse_module_selection(module_str: str) -> list[str]: + """Parse comma-separated module names with optional spaces. + + Args: + module_str: Comma-separated module names (e.g., "backend, frontend") + + Returns: + List of stripped module names + + Examples: + >>> parse_module_selection("backend") + ['backend'] + >>> parse_module_selection("backend, frontend , market") + ['backend', 'frontend', 'market'] + >>> parse_module_selection("all") + ['all'] + """ + if not module_str or module_str.strip() == "all": + return ["all"] + return [n.strip() for n in module_str.split(",") if n.strip()] + + +def validate_module_names(names: list[str], available_modules: list['Module']) -> tuple[list['Module'], list[str]]: + """Validate module names against available modules. + + Args: + names: List of module names to validate + available_modules: List of available Module objects + + Returns: + Tuple of (valid_modules, invalid_names) + """ + valid = [] + invalid = [] + available_names = {m.name for m in available_modules} + + for name in names: + if name == "all": + return available_modules, [] + found = [m for m in available_modules if m.name == name] + if found: + valid.extend(found) + else: + invalid.append(name) + + return valid, invalid + + +def list_modules(available_modules: list['Module']) -> None: + """Print available modules with details. + + Args: + available_modules: List of Module objects to display + """ + print(f" {color('Available modules:', Colors.BOLD)}") + for m in available_modules: + print(f" {color(m.name, Colors.CYAN)} ({m.language})") + print(f" dir: {m.dir.relative_to(ROOT)}") + print(f" build: {' '.join(m.build_cmd)}") + if m.clean_cmd: + print(f" clean: {' '.join(m.clean_cmd)}") + if m.build_dir: + print(f" output: {m.build_dir.relative_to(ROOT)}") + + def main(): parser = argparse.ArgumentParser( description="Tent of Trials - Multi-Language Build System", @@ -646,11 +715,7 @@ def main(): print() if args.list: - print(f" {color('Available modules:', Colors.BOLD)}") - for m in MODULES: - print(f" {color(m.name, Colors.CYAN)} ({m.language})") - print(f" dir: {m.dir.relative_to(ROOT)}") - print(f" build: {' '.join(m.build_cmd)}") + list_modules(MODULES) return 0 print(f" {color('Checking prerequisites...', Colors.GRAY)}") @@ -666,9 +731,8 @@ def main(): if args.module == "all": selected = MODULES else: - names = [n.strip() for n in args.module.split(",")] - selected = [m for m in MODULES if m.name in names] - not_found = set(names) - {m.name for m in MODULES} + names = parse_module_selection(args.module) + selected, not_found = validate_module_names(names, MODULES) if not_found: print(f" {color('✗ Unknown modules:', Colors.RED)} {', '.join(not_found)}") print(f" Available: {', '.join(m.name for m in MODULES)}") From e3df5bc2173d241a01f024c061ebfef50a2dc282 Mon Sep 17 00:00:00 2001 From: royliz3090-jpg Date: Thu, 25 Jun 2026 01:08:50 +0000 Subject: [PATCH 2/2] Add module validation tests --- tests/test_module_validation.py | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tests/test_module_validation.py diff --git a/tests/test_module_validation.py b/tests/test_module_validation.py new file mode 100644 index 00000000..94745e01 --- /dev/null +++ b/tests/test_module_validation.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +"""Tests for module validation helpers.""" +import os +import sys +import unittest + +sys.path.insert(0, os.path.dirname(__file__)) +from build import parse_module_selection, validate_module_selection, list_modules, MODULES + + +class TestParseModuleSelection(unittest.TestCase): + def test_single_module(self): + self.assertEqual(parse_module_selection("backend"), ["backend"]) + + def test_multiple_modules(self): + self.assertEqual(parse_module_selection("backend,frontend"), ["backend", "frontend"]) + + def test_with_spaces(self): + self.assertEqual(parse_module_selection("backend , frontend , market"), ["backend", "frontend", "market"]) + + def test_all_keyword(self): + self.assertEqual(parse_module_selection("all"), ["all"]) + + def test_empty_string(self): + self.assertEqual(parse_module_selection(""), ["all"]) + + def test_whitespace_only(self): + self.assertEqual(parse_module_selection(" "), ["all"]) + + +class TestValidateModuleNames(unittest.TestCase): + def test_valid_module(self): + valid, invalid = validate_module_selection(["backend"], MODULES) + self.assertEqual(len(valid), 1) + self.assertEqual(valid[0].name, "backend") + self.assertEqual(invalid, []) + + def test_invalid_module(self): + valid, invalid = validate_module_selection(["nonexistent"], MODULES) + self.assertEqual(valid, []) + self.assertEqual(invalid, ["nonexistent"]) + + def test_mixed_valid_invalid(self): + valid, invalid = validate_module_selection(["backend", "nonexistent"], MODULES) + self.assertEqual(len(valid), 1) + self.assertEqual(invalid, ["nonexistent"]) + + def test_all_keyword(self): + valid, invalid = validate_module_selection(["all"], MODULES) + self.assertEqual(len(valid), len(MODULES)) + self.assertEqual(invalid, []) + + +if __name__ == "__main__": + unittest.main()