From a662e9b731af81366af758410fa54bfcc1cc343e Mon Sep 17 00:00:00 2001 From: Daniel McCoy Stephenson Date: Wed, 30 Sep 2026 01:30:10 -0600 Subject: [PATCH] Throw ArgumentException for a malformed baseUrl, as documented new Uri throws UriFormatException, a FormatException rather than an ArgumentException, so a caller catching the documented ArgumentException missed it. Wrap it, keeping the original as the inner exception. Closes #3 Co-Authored-By: Claude Opus 5.5 --- src/TraceClient/TraceClient.cs | 11 ++++++++++- tests/TraceClient.Tests/TraceClientTest.cs | 12 ++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/TraceClient/TraceClient.cs b/src/TraceClient/TraceClient.cs index 7bf075c..dd3e2f1 100644 --- a/src/TraceClient/TraceClient.cs +++ b/src/TraceClient/TraceClient.cs @@ -137,7 +137,16 @@ public TraceClient(string baseUrl, string application, string version, string ke { throw new ArgumentException("version is longer than " + MaxLength + " characters", "version"); } - _endpoint = new Uri(baseUrl.Trim().TrimEnd('/') + "/api/metrics"); + try + { + _endpoint = new Uri(baseUrl.Trim().TrimEnd('/') + "/api/metrics"); + } + catch (UriFormatException malformed) + { + // UriFormatException is a FormatException, not an ArgumentException; + // rethrow so a malformed baseUrl fails the way the docs promise. + throw new ArgumentException("baseUrl is not a valid URL", "baseUrl", malformed); + } _application = application.Trim(); _version = version.Trim(); _key = key == null ? "" : key.Trim(); diff --git a/tests/TraceClient.Tests/TraceClientTest.cs b/tests/TraceClient.Tests/TraceClientTest.cs index 582ac10..6dbd83f 100644 --- a/tests/TraceClient.Tests/TraceClientTest.cs +++ b/tests/TraceClient.Tests/TraceClientTest.cs @@ -274,6 +274,18 @@ public void Constructor_RejectsAMissingBaseUrlOrApplication() Assert.Throws(() => new TraceClient("http://x", "", "1.2.3")); } + [Fact] + public void Constructor_RejectsAMalformedBaseUrlWithAnArgumentException() + { + // Exactly ArgumentException, as documented -- not the UriFormatException + // underneath, which a caller catching ArgumentException would miss. + ArgumentException thrown = Assert.Throws( + () => new TraceClient("not a url", "MyGame", "1.2.3", key: "k")); + + Assert.Equal("baseUrl", thrown.ParamName); + Assert.IsType(thrown.InnerException); + } + [Fact] public void Constructor_RejectsAMissingOrOverlongVersion() {