From 42b2cbd86e2f812c389c7a750cca6d4e4e85783e Mon Sep 17 00:00:00 2001 From: Daniel McCoy Stephenson Date: Tue, 6 Oct 2026 01:51:39 -0600 Subject: [PATCH] Document the installId ArgumentException; test Json's name and tag-value limits The constructor summary said it throws only for baseUrl, application and version problems, but an installId longer than MaxLength throws too. The MaxLength summary now says the version and installation ID are held to it. Json's name-too-long and tag-value-too-long reasons had no direct test; two characterization tests pin their wording and the at-the-limit case. Co-Authored-By: Claude Opus 5.5 --- src/TraceClient/TraceClient.cs | 10 ++++--- tests/TraceClient.Tests/TraceClientTest.cs | 32 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/TraceClient/TraceClient.cs b/src/TraceClient/TraceClient.cs index 06241b6..4b48f7a 100644 --- a/src/TraceClient/TraceClient.cs +++ b/src/TraceClient/TraceClient.cs @@ -76,7 +76,8 @@ public sealed class TraceClient : IDisposable /// The most tags the server accepts on one report. public const int MaxTags = 32; - /// The longest application, name, tag key or tag value the server accepts, in UTF-16 chars. + /// The longest application, name, tag key or tag value the server accepts, in UTF-16 chars. + /// The program's version and installation ID are tag values too, so the constructor rejects either past it. public const int MaxLength = 255; /// Environment variable that turns reporting off: off, false, 0, no. @@ -122,9 +123,10 @@ public sealed class TraceClient : IDisposable /// , reporting to the trace server at /// . Throws only for a /// missing or malformed , a missing - /// , or a missing or - /// one longer than characters -- programming errors, - /// not runtime ones. + /// , a missing or + /// one longer than characters, or an + /// longer than characters -- + /// programming errors, not runtime ones. /// /// The trace server, e.g. https://trace.danielstephenson.dev. /// The program's name, exactly as its key was issued for. diff --git a/tests/TraceClient.Tests/TraceClientTest.cs b/tests/TraceClient.Tests/TraceClientTest.cs index 6dbd83f..92b6300 100644 --- a/tests/TraceClient.Tests/TraceClientTest.cs +++ b/tests/TraceClient.Tests/TraceClientTest.cs @@ -453,6 +453,38 @@ public void Json_RejectsATagKeyLongerThanTheLimitAndNamesOnlyItsStart() Assert.Null(body); } + [Fact] + public void Json_RejectsANameLongerThanTheLimitButNotOneAtIt() + { + string longest = new string('n', TraceClient.MaxLength); + string tooLong = new string('n', TraceClient.MaxLength + 1); + + string problem = TraceClient.Json("App", tooLong, null, null, out string rejected); + + Assert.Equal("name longer than " + TraceClient.MaxLength + " characters", problem); + Assert.Null(rejected); + Assert.Null(TraceClient.Json("App", longest, null, null, out string accepted)); + Assert.Contains(longest, accepted); + } + + [Fact] + public void Json_RejectsATagValueLongerThanTheLimitAndNamesItsKey() + { + // The reason names the key, not the value: the value is what ran + // away, and the key is what the program can find in its source. + string tooLongValue = new string('v', TraceClient.MaxLength + 1); + string longestValue = new string('v', TraceClient.MaxLength); + + string problem = TraceClient.Json("App", "n", null, + new Dictionary { { "level", tooLongValue } }, out string body); + + Assert.Equal("tag level longer than " + TraceClient.MaxLength + " characters", problem); + Assert.Null(body); + Assert.Null(TraceClient.Json("App", "n", null, + new Dictionary { { "level", longestValue } }, out string accepted)); + Assert.Contains("\"level\":\"" + longestValue + "\"", accepted); + } + [Fact] public void Quote_EscapesCarriageReturnAndEveryOtherControlCharacter() {