264 lines
8.9 KiB
Python
264 lines
8.9 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
from typeguard import typechecked
|
|
|
|
from ci.util.test_types import TestArgs
|
|
|
|
|
|
def _python_test_exists(test_name: str) -> bool:
|
|
"""Check if a Python test file exists for the given test name"""
|
|
# Check for the test file in ci/tests directory
|
|
tests_dir = Path("ci/tests")
|
|
|
|
# Try various naming patterns for Python tests
|
|
possible_names = [
|
|
f"test_{test_name}.py",
|
|
f"{test_name}.py",
|
|
]
|
|
|
|
for name in possible_names:
|
|
test_file = tests_dir / name
|
|
if test_file.exists():
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def parse_args(args: Optional[list[str]] = None) -> TestArgs:
|
|
"""Parse command line arguments"""
|
|
parser = argparse.ArgumentParser(description="Run FastLED tests")
|
|
parser.add_argument(
|
|
"--cpp",
|
|
action="store_true",
|
|
help="Run C++ tests only (equivalent to --unit --examples, suppresses Python tests)",
|
|
)
|
|
parser.add_argument("--unit", action="store_true", help="Run C++ unit tests only")
|
|
parser.add_argument("--py", action="store_true", help="Run Python tests only")
|
|
parser.add_argument(
|
|
"test",
|
|
type=str,
|
|
nargs="?",
|
|
default=None,
|
|
help="Specific test to run (Python or C++)",
|
|
)
|
|
|
|
# Create mutually exclusive group for compiler selection
|
|
compiler_group = parser.add_mutually_exclusive_group()
|
|
compiler_group.add_argument(
|
|
"--clang", action="store_true", help="Use Clang compiler"
|
|
)
|
|
compiler_group.add_argument(
|
|
"--gcc", action="store_true", help="Use GCC compiler (default on non-Windows)"
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--clean", action="store_true", help="Clean build before compiling"
|
|
)
|
|
parser.add_argument(
|
|
"--no-interactive",
|
|
action="store_true",
|
|
help="Force non-interactive mode (no confirmation prompts)",
|
|
)
|
|
parser.add_argument(
|
|
"--interactive",
|
|
action="store_true",
|
|
help="Enable interactive mode (allows confirmation prompts)",
|
|
)
|
|
parser.add_argument(
|
|
"--verbose",
|
|
"-v",
|
|
action="store_true",
|
|
help="Enable verbose output showing all test details",
|
|
)
|
|
parser.add_argument(
|
|
"--show-compile",
|
|
action="store_true",
|
|
help="Show compilation commands and output",
|
|
)
|
|
parser.add_argument(
|
|
"--show-link",
|
|
action="store_true",
|
|
help="Show linking commands and output",
|
|
)
|
|
parser.add_argument(
|
|
"--quick", action="store_true", help="Enable quick mode with FASTLED_ALL_SRC=1"
|
|
)
|
|
parser.add_argument(
|
|
"--no-stack-trace",
|
|
action="store_true",
|
|
help="Disable stack trace dumping on timeout",
|
|
)
|
|
parser.add_argument(
|
|
"--check",
|
|
action="store_true",
|
|
help="Enable static analysis (IWYU, clang-tidy) - auto-enables --cpp and --clang",
|
|
)
|
|
parser.add_argument(
|
|
"--examples",
|
|
nargs="*",
|
|
help="Run example compilation tests only (optionally specify example names). Use with --full for complete compilation + linking + execution",
|
|
)
|
|
parser.add_argument(
|
|
"--no-pch",
|
|
action="store_true",
|
|
help="Disable precompiled headers (PCH) when running example compilation tests",
|
|
)
|
|
parser.add_argument(
|
|
"--unity",
|
|
action="store_true",
|
|
help="Enable UNITY build mode for examples - compile all source files as a single unit for improved performance",
|
|
)
|
|
parser.add_argument(
|
|
"--no-unity",
|
|
action="store_true",
|
|
help="Disable unity builds for cpp tests and examples",
|
|
)
|
|
parser.add_argument(
|
|
"--full",
|
|
action="store_true",
|
|
help="Run full integration tests including compilation + linking + program execution",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--no-parallel",
|
|
action="store_true",
|
|
help="Force sequential test execution",
|
|
)
|
|
parser.add_argument(
|
|
"--unity-chunks",
|
|
type=int,
|
|
default=1,
|
|
help="Number of unity chunks when building libfastled.a (default: 1)",
|
|
)
|
|
parser.add_argument(
|
|
"--debug",
|
|
action="store_true",
|
|
help="Enable debug mode for C++ unit tests (e.g., full debug symbols)",
|
|
)
|
|
parser.add_argument(
|
|
"--qemu",
|
|
nargs="+",
|
|
help="Run examples in QEMU emulation. Usage: --qemu esp32s3 [example_names...]",
|
|
)
|
|
|
|
parsed_args = parser.parse_args(args)
|
|
|
|
# Convert argparse.Namespace to TestArgs dataclass
|
|
test_args = TestArgs(
|
|
cpp=parsed_args.cpp,
|
|
unit=parsed_args.unit,
|
|
py=parsed_args.py,
|
|
test=parsed_args.test,
|
|
clang=parsed_args.clang,
|
|
gcc=parsed_args.gcc,
|
|
clean=parsed_args.clean,
|
|
no_interactive=parsed_args.no_interactive,
|
|
interactive=parsed_args.interactive,
|
|
verbose=parsed_args.verbose,
|
|
show_compile=parsed_args.show_compile,
|
|
show_link=parsed_args.show_link,
|
|
quick=parsed_args.quick,
|
|
no_stack_trace=parsed_args.no_stack_trace,
|
|
check=parsed_args.check,
|
|
examples=parsed_args.examples,
|
|
no_pch=parsed_args.no_pch,
|
|
unity=parsed_args.unity,
|
|
no_unity=parsed_args.no_unity,
|
|
full=parsed_args.full,
|
|
no_parallel=parsed_args.no_parallel,
|
|
unity_chunks=parsed_args.unity_chunks,
|
|
debug=parsed_args.debug,
|
|
qemu=parsed_args.qemu,
|
|
)
|
|
|
|
# Auto-enable --py or --cpp mode when a specific test is provided
|
|
if test_args.test:
|
|
# Check if this is a Python test first
|
|
if _python_test_exists(test_args.test):
|
|
# This is a Python test - enable Python mode
|
|
if not test_args.py and not test_args.cpp:
|
|
test_args.py = True
|
|
print(
|
|
f"Auto-enabled --py mode for specific Python test: {test_args.test}"
|
|
)
|
|
else:
|
|
# This is not a Python test - assume it's a C++ test
|
|
if not test_args.cpp and not test_args.py:
|
|
test_args.cpp = True
|
|
print(f"Auto-enabled --cpp mode for specific test: {test_args.test}")
|
|
# Also enable --unit when a specific C++ test is provided without any other flags
|
|
if (
|
|
not test_args.unit
|
|
and not test_args.examples
|
|
and not test_args.py
|
|
and not test_args.full
|
|
):
|
|
test_args.unit = True
|
|
print(f"Auto-enabled --unit mode for specific test: {test_args.test}")
|
|
|
|
# Auto-enable --verbose when running unit tests (disabled)
|
|
# if test_args.unit and not test_args.verbose:
|
|
# test_args.verbose = True
|
|
# print("Auto-enabled --verbose mode for unit tests")
|
|
|
|
# Auto-enable --cpp and --clang when --check is provided
|
|
if test_args.check:
|
|
if not test_args.cpp:
|
|
test_args.cpp = True
|
|
print("Auto-enabled --cpp mode for static analysis (--check)")
|
|
if not test_args.clang and not test_args.gcc:
|
|
test_args.clang = True
|
|
print("Auto-enabled --clang compiler for static analysis (--check)")
|
|
|
|
# Auto-enable --cpp and --quick when --examples is provided
|
|
if test_args.examples is not None:
|
|
if not test_args.cpp:
|
|
test_args.cpp = True
|
|
print("Auto-enabled --cpp mode for example compilation (--examples)")
|
|
if not test_args.quick:
|
|
test_args.quick = True
|
|
print(
|
|
"Auto-enabled --quick mode for faster example compilation (--examples)"
|
|
)
|
|
|
|
# Handle --full flag behavior
|
|
if test_args.full:
|
|
if test_args.examples is not None:
|
|
# --examples --full: Run examples with full compilation+linking+execution
|
|
print("Full examples mode: compilation + linking + program execution")
|
|
else:
|
|
# --full alone: Run integration tests
|
|
if not test_args.cpp:
|
|
test_args.cpp = True
|
|
print("Auto-enabled --cpp mode for full integration tests (--full)")
|
|
print("Full integration tests: compilation + linking + program execution")
|
|
|
|
# Default to Clang on Windows unless --gcc is explicitly passed
|
|
if sys.platform == "win32" and not test_args.gcc and not test_args.clang:
|
|
test_args.clang = True
|
|
print("Windows detected: defaulting to Clang compiler (use --gcc to override)")
|
|
elif test_args.gcc:
|
|
print("Using GCC compiler")
|
|
elif test_args.clang:
|
|
print("Using Clang compiler")
|
|
|
|
# Validate conflicting arguments
|
|
if test_args.no_interactive and test_args.interactive:
|
|
print(
|
|
"Error: --interactive and --no-interactive cannot be used together",
|
|
file=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
|
|
# Set NO_PARALLEL environment variable if --no-parallel is used
|
|
if test_args.no_parallel:
|
|
os.environ["NO_PARALLEL"] = "1"
|
|
print("Forcing sequential execution (NO_PARALLEL=1)")
|
|
|
|
return test_args
|