Skip to content

Commit 5b6936d

Browse files
committed
added quiet flag, more output tuning
1 parent df42242 commit 5b6936d

File tree

1 file changed

+135
-62
lines changed

1 file changed

+135
-62
lines changed

test/run-tests.py

Lines changed: 135 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -42,63 +42,75 @@
4242
TEMP_EXE_NAME = "godot-temp-portable.exe"
4343
TEMP_MARKER_NAME = "_sc_"
4444

45+
PHASE_CLEANUP = 10
46+
PHASE_PRE_IMPORT = 20
47+
PHASE_UNIT_TESTS = 30
48+
PHASE_CLEANUP_TEMP = 40 # not really a failure point, but for completeness
49+
4550
# ──────────────────────────────────────────────
4651
# Portable Temp Copy Helpers
4752
# ──────────────────────────────────────────────
48-
49-
def setup_temp_portable_godot() -> str:
53+
def setup_temp_portable_godot(quiet:bool=False, verbose:bool=False) -> str:
5054
"""Copy Godot exe + create marker for single-session portable mode."""
5155
original_path = Path(ORIGINAL_GODOT).resolve()
5256
if not original_path.is_file():
53-
print(f"Warning: Original Godot not found at '{original_path}' — using as-is.")
57+
if not quiet:
58+
print(f"Warning: Original Godot not found — using as-is.")
5459
return ORIGINAL_GODOT
5560

5661
temp_exe = Path.cwd() / TEMP_EXE_NAME
5762
temp_marker = Path.cwd() / TEMP_MARKER_NAME
5863

5964
try:
60-
print(f"Creating temporary portable copy: {temp_exe}")
65+
if not quiet:
66+
print("→ Creating portable Godot", end=" ")
6167
shutil.copy2(original_path, temp_exe)
62-
63-
print(f"Creating portable marker: {temp_marker}")
6468
temp_marker.touch(exist_ok=True)
65-
66-
# Return path to temp exe
69+
if not quiet:
70+
print("[ DONE ]")
6771
return str(temp_exe.absolute())
68-
6972
except Exception as e:
70-
print(f"Failed to setup temp portable Godot: {e}")
71-
print("Falling back to original executable (may pollute system data dirs)")
73+
if not quiet:
74+
print("[ FAILED ]")
75+
print(f"Failed to setup temp portable Godot: {e}")
7276
return ORIGINAL_GODOT
7377

7478

75-
def cleanup_temp_portable():
79+
def cleanup_temp_portable(quiet:bool=False, verbose:bool=False):
7680
"""Remove temp exe, marker, and any editor_data folder."""
7781
temp_exe = Path.cwd() / TEMP_EXE_NAME
7882
temp_marker = Path.cwd() / TEMP_MARKER_NAME
7983
editor_data = Path.cwd() / "editor_data"
8084

85+
cleaned = False
8186
for path in [temp_exe, temp_marker]:
8287
if path.exists():
8388
try:
8489
path.unlink()
85-
print(f"Cleaned: {path}")
90+
cleaned = True
91+
if verbose: print(f"Cleaned: {path}")
8692
except Exception as e:
8793
print(f"Warning: Could not delete {path}: {e}")
8894

8995
if editor_data.exists():
9096
try:
9197
shutil.rmtree(editor_data)
92-
print(f"Cleaned editor_data folder: {editor_data}")
98+
if verbose: print(f"Cleaned editor_data folder: {editor_data}")
9399
except Exception as e:
94-
print(f"Warning: Could not delete editor_data: {e}")
100+
if verbose: print(f"Warning: Could not delete editor_data: {e}")
101+
102+
if not quiet and cleaned:
103+
print("→ Cleaned [ DONE ]")
104+
105+
106+
95107

96108

97109
# ──────────────────────────────────────────────
98-
# Other Helpers (unchanged from previous)
110+
# Other Helpers
99111
# ──────────────────────────────────────────────
100112

101-
def filter_output(lines: list[str], verbose: bool) -> list[str]:
113+
def filter_output(lines: list[str], quiet:bool=False, verbose:bool=False) -> list[str]:
102114
if verbose:
103115
return [line.rstrip() for line in lines if line.strip()] # just trim, keep everything
104116
# original quiet filtering
@@ -118,8 +130,21 @@ def is_successful(output: str) -> bool:
118130
has_failed = FAILED_MARKER in output
119131
return has_end and has_passed and not has_failed
120132

133+
def cleanup_godot_cache(quiet:bool=False, verbose:bool=False):
134+
cache_dir = PROJECT_DIR / ".godot"
135+
if cache_dir.exists():
136+
if not quiet:
137+
print("→ Cleaning project cache", end=" ")
138+
try:
139+
shutil.rmtree(cache_dir, ignore_errors=True)
140+
if not quiet:
141+
print("[ DONE ]")
142+
except Exception as e:
143+
if verbose:
144+
print(f"Warning: Failed to clean .godot: {e}")
145+
elif not quiet:
146+
print("[ FAILED ]")
121147

122-
def cleanup_godot_cache():
123148
cache_dir = PROJECT_DIR / ".godot"
124149
if cache_dir.exists():
125150
print(f"Cleaning project cache: {cache_dir}")
@@ -128,8 +153,10 @@ def cleanup_godot_cache():
128153
except Exception as e:
129154
print(f"Warning: Failed to clean .godot: {e}")
130155

131-
132-
def run_godot(args: list[str], desc: str, godot_bin: str, timeout_sec: int = TIMEOUT_SEC, verbose: bool = False) -> tuple[int, str, bool]:
156+
def run_godot(
157+
args: list[str], desc: str, godot_bin: str, timeout_sec: int = TIMEOUT_SEC, quiet: bool = False,
158+
verbose: bool = False, phase_code_on_fail=None
159+
) -> tuple[int, str, bool]:
133160
print(f"\n{'─' * 10} {desc} {'─' * 10}")
134161
print(f"→ {godot_bin} {' '.join(args)}")
135162

@@ -183,89 +210,135 @@ def run_godot(args: list[str], desc: str, godot_bin: str, timeout_sec: int = TIM
183210
print(msg)
184211
return 1, msg, False
185212

186-
def pre_import_project(godot_bin: str, verbose: bool):
187-
print("\nPre-importing project (headless, short timeout)...")
188-
cleanup_godot_cache()
213+
def pre_import_project(godot_bin:str, quiet:bool=False, verbose:bool=False):
214+
if verbose:
215+
print("\nPre-importing project (headless, short timeout)...")
216+
elif not quiet: print("→ Pre-import", end=" ")
217+
218+
cleanup_godot_cache(quiet=quiet, verbose=verbose)
189219

190220
args = ["--path", str(GODOT_PROJECT), "--import", "--headless"]
191-
exit_code, output, timed_out = run_godot(args, "Pre-import", godot_bin, timeout_sec=IMPORT_TIMEOUT_SEC, verbose=verbose)
192-
221+
exit_code, output, timed_out = run_godot(
222+
args, "Pre-import", godot_bin,
223+
timeout_sec=IMPORT_TIMEOUT_SEC,
224+
verbose=verbose, quiet=quiet
225+
)
193226
if timed_out or exit_code != 0:
194227
if verbose:
195-
print("→ Pre-import failed or timed out (full output above)")
196-
else:
197-
print("→ Pre-import failed/crashed — continuing anyway")
228+
print("→ Pre-import failed or timed out — continuing anyway")
229+
elif not quiet:
230+
print("[ CRASH/FAIL ]")
231+
return False, PHASE_PRE_IMPORT
198232
else:
199-
print("→ Pre-import completed")
233+
if verbose:
234+
print("→ Pre-import completed")
235+
elif not quiet:
236+
print("[ DONE ]")
237+
return True, 0
200238

201239

202-
def run_tests(mode: str, godot_bin: str, verbose) -> bool:
240+
def run_tests(mode: str, godot_bin: str, quiet:bool=False, verbose:bool=False) -> bool:
203241
overall_success = True
242+
failed_phase = 0
204243

205-
# ── One-time preparation ──
206-
print("\nPreparing project (one-time cleanup + pre-import)...")
207-
cleanup_godot_cache() # Clean once at start
244+
if not quiet:
245+
print("Preparing project...")
246+
# ── One-time preparation ──
247+
if not quiet:
248+
print("\nPreparing project (one-time cleanup + pre-import)...")
249+
print("Preparing project...")
208250

209-
pre_import_project(godot_bin, verbose) # Attempt import once (ignore failures)
251+
ok, phase = pre_import_project(godot_bin, quiet=quiet, verbose=verbose) # Attempt import once (ignore failures)
252+
if not ok:
253+
return False # early return — we'll set exit code higher up
210254

211255
# No more cleanups after this point — let the cache persist
212256

213257
if mode in ("unit", "full"):
258+
if not quiet: print("→ Unit / headless tests")
259+
214260
args = ["--path", str(GODOT_PROJECT), "--debug", "--headless", "--quit"]
215-
_, output, timed_out = run_godot(args, "Unit / headless tests", godot_bin, verbose=verbose)
261+
exit_code, output, timed_out = run_godot(
262+
args, "Unit / headless tests", godot_bin,
263+
verbose=verbose, quiet=quiet )
216264

217265
# Summary parsing still uses full output
218266
if timed_out:
219-
print("→ Unit phase: TIMEOUT")
267+
if not quiet: print("→ Unit phase: TIMEOUT")
220268
overall_success = False
269+
failed_phase = PHASE_UNIT_TESTS
221270
elif not is_successful(output):
222-
print("→ Unit phase: did NOT detect clean success")
271+
if not quiet:
272+
print("→ Unit phase: did NOT detect clean success")
223273
overall_success = False
224-
else:
225-
print("→ Unit phase: detected PASSED")
274+
failed_phase = PHASE_UNIT_TESTS
275+
elif not quiet:
276+
# Show minimal success summary even in non-verbose
277+
lines = output.splitlines()
278+
for line in lines:
279+
if any(m in line for m in [END_MARKER, PASSED_MARKER]):
280+
print(line.strip())
281+
print("→ Unit phase: [ PASSED ]")
226282

227-
if not verbose:
228-
# Optional: print a small reminder about the known error
229-
if "ExampleInternal" in output:
230-
print(" (known non-fatal warning about 'ExampleInternal' suppressed)")
283+
if verbose:
284+
# Optional: print a small reminder about the known error
285+
if "ExampleInternal" in output:
286+
print(" (known non-fatal warning about 'ExampleInternal' suppressed)")
231287

232288
return overall_success
233289

234-
235290
# ──────────────────────────────────────────────
236291
# Main
237292
# ──────────────────────────────────────────────
238293
def main():
239294
parser = argparse.ArgumentParser(description="Run godot-cpp test suite (temp portable Godot)")
240295
parser.add_argument("--unit-only", action="store_const", const="unit", dest="mode")
241296
parser.add_argument("--verbose", action="store_true", default=False,
242-
help="Show full unfiltered Godot output + more detailed runner messages")
297+
help="Show full unfiltered Godot output")
298+
parser.add_argument("--quiet", action="store_true", default=False,
299+
help="Minimal output — only final exit code (for CI)")
243300
args = parser.parse_args()
244301

245-
mode = args.mode or "full"
302+
mode = args.mode or "full"
246303
verbose = args.verbose
304+
quiet = args.quiet
247305

248-
print(f"Original Godot: {ORIGINAL_GODOT}")
249-
print(f"Project: {GODOT_PROJECT}")
250-
print(f"Mode: {mode}")
251-
print(f"Verbose: {verbose}\n")
306+
# ── Early exit for quiet mode if we want ultra-minimal ──
307+
if quiet:
308+
# We'll suppress almost all prints later
309+
def qprint(*a, **kw): pass
310+
global print
311+
print = qprint # monkey-patch print (crude but effective for this script)
252312

253-
# Setup temp portable copy
254-
godot_bin = setup_temp_portable_godot()
313+
if quiet and verbose:
314+
print("Error: --quiet and --verbose are mutually exclusive", file=sys.stderr)
315+
sys.exit(1)
316+
317+
print(f"Godot Executable: {ORIGINAL_GODOT}")
318+
print(f"Project: {GODOT_PROJECT}")
319+
print(f"Mode: {mode}")
320+
print(f"Verbose: {verbose}\n")
255321

322+
godot_bin = setup_temp_portable_godot(quiet=quiet)
323+
324+
exit_code = 0
256325
try:
257-
all_passed = run_tests(mode, godot_bin, verbose)
326+
success = run_tests(mode, godot_bin, verbose=verbose, quiet=quiet)
327+
if not success:
328+
exit_code = 3 # default unit failure; overridden in run_tests if earlier phase
329+
except Exception as e:
330+
print(f"Runner crashed: {e}", file=sys.stderr)
331+
exit_code = 1
258332
finally:
259-
# Always cleanup temp files
260-
cleanup_temp_portable()
333+
cleanup_temp_portable(quiet=quiet, verbose=verbose)
261334

262-
print("\n" + "═" * 40)
263-
if all_passed:
264-
print("TEST SUITE PASSED")
265-
sys.exit(0)
266-
else:
267-
print("TEST SUITE FAILED")
268-
sys.exit(1)
335+
if not quiet:
336+
print("\n" + "═" * 40)
337+
status = "PASSED" if exit_code == 0 else f"FAILED (code {exit_code})"
338+
duration = f" - took {int(time.time() - start_time)}s" if 'start_time' in globals() else ""
339+
print(f"TEST SUITE {status}{duration}")
340+
341+
sys.exit(exit_code)
269342

270343

271344
if __name__ == "__main__":

0 commit comments

Comments
 (0)