From 4dcf27102d606ec82510902f8d3d6384de48ada2 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 06:29:29 +0000 Subject: [PATCH 1/2] Report an out-of-range number for an option as a usage error [patch] int.Parse and its relatives throw OverflowException, not FormatException, for a number too large for the type, so `--count 99999999999` escaped TryApplyOptions as an unhandled exception and the tool exited 134 instead of printing the usage error and exiting 2. Fixes #69 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017vfJW5LUHQ94WSDTYRpSJV --- README.md | 4 ++-- TrayApp.Test/TrayAppBuilderTests.cs | 16 ++++++++++++++++ TrayApp/TrayAppBuilder.cs | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5a5753b..64a1ffc 100644 --- a/README.md +++ b/README.md @@ -164,8 +164,8 @@ way out. A user flicking a toggle back and forth produces one write, not one per ``` They appear in `--help` in registration order, between the tray switches and `--for`. A value handler -that throws `FormatException` or `ArgumentException` turns its message into the usage error, and the -tool exits 2 without starting. +that throws `FormatException`, `ArgumentException` or `OverflowException` (what `int.Parse` throws for a +number out of range) turns its message into the usage error, and the tool exits 2 without starting. ### Adding rows to `--status` diff --git a/TrayApp.Test/TrayAppBuilderTests.cs b/TrayApp.Test/TrayAppBuilderTests.cs index 44607aa..ff38ba2 100644 --- a/TrayApp.Test/TrayAppBuilderTests.cs +++ b/TrayApp.Test/TrayAppBuilderTests.cs @@ -4,6 +4,7 @@ namespace ktsu.TrayApp.Test; using System; using System.Collections.Generic; +using System.Globalization; using System.Threading.Tasks; using ktsu.Essentials.PersistenceProviders.InMemory; using ktsu.TrayApp; @@ -303,6 +304,21 @@ public void TryApplyOptions_WhenAHandlerRejectsTheValue_ReportsItAsAUsageError() Assert.AreEqual("'lots' is not a number.", error); } + [TestMethod] + public void TryApplyOptions_WhenAHandlerParsesAnOutOfRangeNumber_ReportsItAsAUsageError() + { + // int.Parse throws OverflowException, not FormatException, for a number too big for an int, and + // that used to escape as an unhandled exception (#69). + TrayAppDefinition app = TrayAppBuilder.Create("demo") + .Option(["--count"], "n", "How many.", value => _ = int.Parse(value, CultureInfo.InvariantCulture)) + .Build(); + + Assert.IsTrue(CommandLineParser.TryParse(["--count", "99999999999"], app.Options, out CommandLineOptions options, out _)); + Assert.IsFalse(TrayAppBuilder.TryApplyOptions(options, out string error)); + string expected = Assert.ThrowsExactly(() => int.Parse("99999999999", CultureInfo.InvariantCulture)).Message; + Assert.AreEqual(expected, error); + } + [TestMethod] public async Task RunAsync_WithHelp_PrintsUsageAndSucceeds() { diff --git a/TrayApp/TrayAppBuilder.cs b/TrayApp/TrayAppBuilder.cs index 73cf5ca..70a876c 100644 --- a/TrayApp/TrayAppBuilder.cs +++ b/TrayApp/TrayAppBuilder.cs @@ -559,7 +559,7 @@ internal static bool TryApplyOptions(CommandLineOptions options, out string erro { match.Option.Apply(match.Value); } - catch (Exception ex) when (ex is FormatException or ArgumentException) + catch (Exception ex) when (ex is FormatException or ArgumentException or OverflowException) { error = ex.Message; return false; From fb4ebf940d3668bcb5c1987ddfffa56f5ae531a2 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 06:29:44 +0000 Subject: [PATCH 2/2] Name CultureInfo in full so the #69 test adds no using line Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017vfJW5LUHQ94WSDTYRpSJV --- TrayApp.Test/TrayAppBuilderTests.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/TrayApp.Test/TrayAppBuilderTests.cs b/TrayApp.Test/TrayAppBuilderTests.cs index ff38ba2..13ea000 100644 --- a/TrayApp.Test/TrayAppBuilderTests.cs +++ b/TrayApp.Test/TrayAppBuilderTests.cs @@ -4,7 +4,6 @@ namespace ktsu.TrayApp.Test; using System; using System.Collections.Generic; -using System.Globalization; using System.Threading.Tasks; using ktsu.Essentials.PersistenceProviders.InMemory; using ktsu.TrayApp; @@ -310,12 +309,12 @@ public void TryApplyOptions_WhenAHandlerParsesAnOutOfRangeNumber_ReportsItAsAUsa // int.Parse throws OverflowException, not FormatException, for a number too big for an int, and // that used to escape as an unhandled exception (#69). TrayAppDefinition app = TrayAppBuilder.Create("demo") - .Option(["--count"], "n", "How many.", value => _ = int.Parse(value, CultureInfo.InvariantCulture)) + .Option(["--count"], "n", "How many.", value => _ = int.Parse(value, System.Globalization.CultureInfo.InvariantCulture)) .Build(); Assert.IsTrue(CommandLineParser.TryParse(["--count", "99999999999"], app.Options, out CommandLineOptions options, out _)); Assert.IsFalse(TrayAppBuilder.TryApplyOptions(options, out string error)); - string expected = Assert.ThrowsExactly(() => int.Parse("99999999999", CultureInfo.InvariantCulture)).Message; + string expected = Assert.ThrowsExactly(() => int.Parse("99999999999", System.Globalization.CultureInfo.InvariantCulture)).Message; Assert.AreEqual(expected, error); }