Skip to content

Exit 1 for an output folder that can't be created instead of crashing [patch] - #148

Merged
matt-edmondson merged 3 commits into
mainfrom
fix/125-unusable-output-folder
Oct 19, 2026
Merged

matt-edmondson merged 3 commits into
mainfrom
fix/125-unusable-output-folder

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #125

What was wrong

Arguments.TryResolveOutput rejects an --output only when it names an existing file. ProcessDirectory then calls Directory.CreateDirectory and Directory.GetFiles before its per-file try/catch, and Run has no handler. So an output folder under a file, an output folder the user isn't allowed to create, or an input folder that can't be listed ended the run with an unhandled exception and exit 134, not the documented exit 1.

Change

  • Run is now a thin Environment.Exit wrapper around a new internal static int Execute(Arguments). Execute validates, runs the batch, prints the summary and returns the exit code, so a whole run is testable without spawning a process.
  • Execute catches IOException and UnauthorizedAccessException from ProcessDirectory, prints one line in the existing Argument validation failed: format with the exception's message (which names the path), and returns ExitInvalidArguments. Only the two up-front calls can raise these, because each file's own failures are already caught and counted inside the batch. A failure on one file still gives exit 2.
  • CLAUDE.md's exit-codes section describes Execute and the new catch.

Tests

  • AnOutputFolderUnderAFileExitsWithInvalidArgumentsInsteadOfThrowing covers the issue's portable case, -o <file>/sub, and needs no permissions setup. With the catch removed it fails (the DirectoryNotFoundException escapes); with the catch it passes.
  • ExecuteReportsSuccessForAGoodRun covers the new entry point on the happy path.
  • The uncreatable-folder case (/proc/...) and the unlistable-input case need OS-specific permissions, so they have no test. They go through the same catch.
  • Locally 79/87 pass. The 8 that fail are GoldMasterTests.OutputMatchesTheGoldMaster, and they fail the same way on unchanged main in this environment, because the gold-master PNGs are Git LFS pointers and the clone has no LFS content. CI checks out LFS.

Generated by Claude Code

… [patch]

Validate only rejects an --output that is itself an existing file, so an
output under a file, one the user may not create, or an input folder that
can't be listed reached Directory.CreateDirectory / GetFiles outside the
per-file catch and ended the run with a stack trace and exit 134. Run now
delegates to a testable Execute, which reports those IO and permission
failures as an argument error and returns ExitInvalidArguments.

Fixes #125

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCSwub3LRUKDprfUt2KQ1
Comment thread IconHelper.Test/ProcessDirectoryTests.cs Fixed
Comment thread IconHelper.Test/ProcessDirectoryTests.cs Fixed
Comment thread IconHelper.Test/ProcessDirectoryTests.cs Fixed
SonarCloud's new-code coverage gate counted Run's untestable Exit branch
and Execute's unexercised validation failure path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCSwub3LRUKDprfUt2KQ1
@matt-edmondson
matt-edmondson merged commit 83842b0 into main Oct 19, 2026
11 checks passed
@matt-edmondson
matt-edmondson deleted the fix/125-unusable-output-folder branch October 19, 2026 09:46
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants