Repository navigation
Testing
Loky edited this page Oct 14, 2026
·
7 revisions
Last run (v0.17.2): 31 suites, 250 tests, 0 failures (Godot 4.7.2, Windows).
Two layers: automated tests for the pure logic (GdUnit4: no real git process, no scene) and a manual regression checklist for everything that needs the editor or a real remote.
- Parsers and helpers are static or
RefCounted: text in, data out (GitStatusParser,GitDiffParser,GitRemote.web_url(),GitotUi.sync_symbol()...). - Panels take their widgets by constructor injection, and their text rules are static helpers (
GitotBranchPanel,GitotLfsPanel,GithubPanel._header_text()), so the wording is tested without building a scene. - Result handlers (
GitotBranchResults,GitotSyncResults,GitotResultRouter) are built withnullpanels and anullengine; a test only drives the paths that never reach them, so a missing guard crashes the test instead of passing silently. - A test that needs a collaborator gets a fake or
null:GitLfsruns on a realGitEnginethat never executes a command (the test emitscommand_completeditself);GitotPushFlowgetsnullfor the engine, orchestrator and tag panel, because the code under test never reaches them. - Nothing touches your global git config, your
git lfs install, the network or a real repository. The only disk I/O isGitIgnore, in a scratch folder underuser://, never in the project.
| Suite | Tests | Covers |
|---|---|---|
git_status_parser_test |
12 |
status --porcelain=v2: untracked, staged / unstaged / both, deleted, conflict, spaces, quoted non-ASCII paths, ignored and malformed lines, status args skip optional locks |
git_diff_parser_test |
14 | Gutter hunks (added, modified, pure deletion), full diff viewer (hunks, files, malformed headers, a content line that looks like a file header), --name-status
|
git_log_parser_test |
4 | Entries, order, malformed lines, blank input |
git_branch_parser_test |
8 | Current / other / remote branches, the origin/HEAD alias skipped, separator inside a subject, order |
git_stash_parser_test |
8 | Custom and default (WIP) subjects, index from the selector, slashes and colons in names, a malformed line does not shift indices |
git_lfs_parser_test |
20 |
git lfs version parsing (version, other output), ls-files --json (local, pointer-only, defaults, non-ASCII), .gitattributes patterns (CRLF, empty), local / remote merge by oid, summary counts and sizes |
git_path_test |
11 | Git's quoted paths to real UTF-8: octal bytes, tab, quote, backslash, empty, name-list results (reliable flag) |
| Suite | Tests | Covers |
|---|---|---|
git_engine_test |
13 | Which commands take the write lock (push and pull yes, fetch and tag push no), init / remote add, per-call on_done (callback plus broadcast, also for a refused remote delete), latest-wins reads (a superseded read is not broadcast, its on_done still runs) |
git_remote_test |
8 |
owner/repo parsing, web_url() (accepted forms, refused unsafe forms), remote-URL decoding, remote URL validation |
git_ref_test |
4 | Branch-name safety (shell metacharacters, leading -), tag-name rules |
git_runner_test |
21 | Log parsing (only the final exit marker counts), Windows output re-decoding, shell string and exit marker, shell-safety whitelist, quoted-path check and combined refusal, a dropped write still completes (-1), the network write lock, long path lists split in chunks and chunk outputs merged |
git_sync_orchestrator_test |
4 |
plan_push(): normal, behind (blocked, never forced), diverged (force confirmation) |
git_lfs_test |
9 | LFS state machine (no binary, not initialized, ready), transitions, pattern guards (empty, option-like, Godot text formats, catch-all like *), teardown, merge with the upstream list, a failed local read reports failure |
gitot_regex_test |
3 | One compiled RegEx per pattern (same instance on reuse, distinct per pattern, matches) |
git_ignore_test |
4 | Default .gitignore written only when missing, never overwrites, unwritable folder, template content |
| Suite | Tests | Covers |
|---|---|---|
gitot_repo_state_test |
6 | Sync state, changed signal only on a real change, no-origin default, label fallbacks |
gitot_settings_test |
6 | Every numeric setting clamped to its range (timeout minimum, 0 MB valid), pass-through values, ranges and defaults consistent, confirmations on by default, Output echo on by default |
gitot_logger_test |
4 | The one failure shape: error, git's raw message, hint; [ escaped for every level; every level has a style |
gitot_result_router_test |
12 | Commit summary (file list dropped, hook output skipped), stash and pop lines, a failed status or log repaints nothing, origin state, remote add success and failure, stage / unstage failure and success lines |
gitot_branch_results_test |
9 | Every branch command dispatched, silent failed branch list, switch / create / delete failure text, current-branch answer (unborn branch / detached) |
gitot_sync_results_test |
14 | Every sync command dispatched, push / pull / force-push lines, label fallbacks, failure shape, timeout hint, a pull moves HEAD and a push does not, ahead/behind state (the startup read is silent, later changes are logged), tag push |
gitot_commit_flow_test |
5 | Pushed = upstream and nothing ahead, amend confirmation rule (pushed always asks), amend arguments (keep or replace the message), empty message commits nothing, amend toggle wording |
gitot_push_flow_test |
2 | No origin asks for a remote; with an origin it does not |
gitot_dock_test |
2 | Focus-in refresh cooldown (3 s), first focus-in is never skipped |
| Suite | Tests | Covers |
|---|---|---|
gitot_ui_test |
14 | Sync key / symbol / color / counts / tooltips, ellipsize, scope label, push tooltip, amend confirmation texts |
gitot_diff_panel_test |
5 | Raw diff to hunks (first file, binary / empty), truncation logged only over the cap, line-number width grows past 999 |
gitot_diff_gutter_test |
4 | Gutter added once per editor, teardown() hides it and clears its markers, a re-enabled plugin reuses it, a freed editor is skipped |
gitot_branch_panel_test |
12 | Fold title, row annotation (local / remote copy), status text with counts, sync tooltips |
gitot_lfs_panel_test |
6 | State text, setup steps, dashboard stats (empty, zero counters, bracket escaping) |
github_panel_test |
5 | Issues header: repo, open / Bug / High priority counts, no count, before any fetch; github.com-only remote detection; dirty count from the parsed status |
github_issue_parser_test |
1 |
count_where(): exact match only, Urgent is not High, empty list |
- One file per class:
test/<class_snake_case>_test.gd,extends GdUnitTestSuite, a header comment saying what the suite covers. - One behavior per test, named for it (
test_behind_only_is_blocked_never_forced), not for the function. - A bug fix comes with the test that would have caught it (the failed branch list that crashed outside a repository, the unborn branch shown as detached, the failed status shown as a clean tree).
- GdUnit runs tests in a separate game process, where
EditorInterfacedoes not exist: a class whose constructor reads the editor theme (GitotStatusTree) cannot be built in a test. Keep the logic in static helpers or plain objects. - Security rules are tested from both sides, accepted and refused inputs: remote URLs, branch and tag names, shell arguments,
web_url()(no token in a link). - No test may start a real git process. In
git_lfs_test, never emitLFS_VERSIONwith exit 0 orLFS_INSTALL: both makeGitLfsrun one.
The editor flows are checked by hand with a regression-checklist before each release: lifecycle, stage, commit / sync, no repository / first push (Initialize repository, remote URL prompt), status line link, stash, branches, tags, history, gutter, GitHub Issues (including the header counts), output messages, settings.
- Git LFS against a real LFS remote (Install LFS, real push / pull / prune, the not-installed views).
- Git older than 2.32, and a project inside a repository subfolder.
- Linux, macOS, and code pages other than Windows-1252.