MCPcopy Create free account
hub / github.com/FastLED/FastLED / check_single_test_cached

Function check_single_test_cached

ci/early_exit_cache.py:357–429  ·  view source on GitHub ↗

Check if a single named test is fully cached (build + result). Performs the full pipeline: 1. Load cached test names from introspect cache 2. Normalize test name and find a match 3. Locate the test artifact (DLL/SO) 4. Verify ninja build can be skipped (no source changes

(test_name_raw: str, build_dir: Path)

Source from the content-addressed store, hash-verified

355
356
357def check_single_test_cached(test_name_raw: str, build_dir: Path) -> bool:
358 """Check if a single named test is fully cached (build + result).
359
360 Performs the full pipeline:
361 1. Load cached test names from introspect cache
362 2. Normalize test name and find a match
363 3. Locate the test artifact (DLL/SO)
364 4. Verify ninja build can be skipped (no source changes)
365 5. Verify test result is cached and passing
366
367 This is the shared logic used by both argv_ultra_early_exit() (pre-parse_args)
368 and the post-parse_args early exit in main().
369
370 Args:
371 test_name_raw: Raw test name string (e.g., "xypath", "tests/fl/alloca").
372 build_dir: Meson build directory (e.g., .build/meson-quick/).
373
374 Returns:
375 True if the test is fully cached and can be skipped, False otherwise.
376 """
377 cached_names = load_test_names(build_dir)
378 if not cached_names:
379 return False
380
381 # Normalize: strip "tests/" prefix and convert path separators to underscores
382 name_lower = test_name_raw.lower()
383 if name_lower.startswith("tests/") or name_lower.startswith("tests\\"):
384 name_lower = name_lower[len("tests/") :]
385 name_normalized = name_lower.replace("/", "_").replace("\\", "_")
386 stem = Path(test_name_raw).stem.lower()
387
388 # Try multiple candidate names (exact, test_ prefixed, stem-only)
389 candidates = dict.fromkeys(
390 [name_normalized, f"test_{name_normalized}", stem, f"test_{stem}"]
391 )
392 cache_set = set(cached_names)
393 matched: str | None = None
394 for cn in candidates:
395 if cn in cache_set:
396 matched = cn
397 break
398 if not matched:
399 # Suffix matching: "allocator" matches "fl_stl_allocator" etc.
400 # Only accept if exactly one cached name ends with _<query> to avoid ambiguity.
401 suffix = f"_{name_normalized}"
402 suffix_matches = [n for n in cached_names if n.endswith(suffix)]
403 if len(suffix_matches) == 1:
404 matched = suffix_matches[0]
405 if not matched:
406 return False
407
408 ext = ".dll" if os.name == "nt" else ".so"
409 dll = build_dir / "tests" / f"{matched}{ext}"
410 if not dll.exists():
411 return False
412
413 # Determine the test's source directory to narrow the tests/ scan.
414 # For "tests/fl/alloca" → narrow to tests/fl/ (+ tests/ root for shared headers).

Callers 2

mainFunction · 0.90
argv_ultra_early_exitFunction · 0.85

Calls 4

load_test_namesFunction · 0.85
ninja_skipFunction · 0.85
test_cachedFunction · 0.85
setClass · 0.50

Tested by 1

mainFunction · 0.72