From 65697c58606b8c86c713ae1bed41a962f681e6e9 Mon Sep 17 00:00:00 2001 From: Chris Wolfgang <210299580+Chris-Wolfgang@users.noreply.github.com> Date: Sat, 27 Jun 2026 22:09:26 -0400 Subject: [PATCH] chore(review): trivial fixes from AI code-review pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Batch of low-risk fixes surfaced by the v0.3.3 AI code-review pass (#128). Larger findings are filed as separate Tier-2 sub-issues. Source — XML doc + small wording - Result.cs: class summaries reworded so they no longer claim the types are only produced by Try.Run (they're also used directly as repository / validation return types). - Result.cs: Failure() exception message now matches the protected ctor wording ("cannot be null, empty, or whitespace.") and the exception cref blocks point at . - Result.cs: added to Success() / Failure() factories; Result.Success(value) now documents its + ; the private Result.Value getter's mentions throw-on- failure inline (was only in ), and the text is a complete sentence. - Try.cs: RunAsync summary now says "asynchronously" (parity with the Action variant); Run summary differentiates from Run by mentioning the return value. Tests — naming convention drift - ResultTests.cs: two tests whose names said "throw_Invalid- OperationException" actually assert ArgumentException; renamed to match observed behavior. - RunFuncTests.cs: 8 PascalCase test names migrated to the CLAUDE.md canonical snake_case Method_when_condition_expected_result pattern; the one named FunctionNullableInt_WithExceptionThrowingFunction_ReturnsDefault actually verifies Value-access throws on failed result and is renamed accordingly. csproj hygiene - src csproj: added per Directory.Build.props's per-repo expectation; normalized mixed-tabs/spaces indent. - tests csproj: dropped dead netcoreapp3.1 block (netcoreapp3.1 is not in , so the group never matched); dropped stale 0.3.0 (test project is IsPackable=false, the version field was unused). Examples - FSharp.DotNet8.Example/Program.fs: module name said FSharp.DotNet462.Example — copy-paste bug from the F#/.NET 4.6.2 sibling; renamed to FSharp.DotNet8.Example. Docs - docs/DOCFX-VERSION-PICKER.md: stripped a "no DateTime-Extensions paths leak" cross-repo reference that was carried over from the canonical fanout; replaced with generic wording. Out-of-scope follow-ups filed as Tier-2 sub-issues of #128: - xunit.runner.visualstudio 3.0.0 + xunit 2.9.3 mismatch on net8/9/10 (CLAUDE.md violation, behaviour change) - PublicApi/modern/PublicAPI.Shipped.txt missing Result.Value.get -> T? entry (needs RS0016 sweep) - benchmarks csproj net8.0 → net10.0 (perf picture changes) - README database example uses sync IO inside Try.Run (opinion) - tests csproj/dir naming mismatch (Wolfgang.TryPattern.Tests.Unit vs Wolfgang.TryPattern.Tests) Closes #128 --- docs/DOCFX-VERSION-PICKER.md | 4 +- examples/FSharp.DotNet8.Example/Program.fs | 2 +- src/Wolfgang.TryPattern/Result.cs | 51 ++++++++++++------- src/Wolfgang.TryPattern/Try.cs | 10 ++-- .../Wolfgang.TryPattern.csproj | 49 +++++++++--------- .../Wolfgang.TryPattern.Tests/ResultTests.cs | 4 +- .../Wolfgang.TryPattern.Tests/RunFuncTests.cs | 16 +++--- .../Wolfgang.TryPattern.Tests.Unit.csproj | 18 ------- 8 files changed, 76 insertions(+), 78 deletions(-) diff --git a/docs/DOCFX-VERSION-PICKER.md b/docs/DOCFX-VERSION-PICKER.md index 8713cbe..4e39e86 100644 --- a/docs/DOCFX-VERSION-PICKER.md +++ b/docs/DOCFX-VERSION-PICKER.md @@ -87,8 +87,8 @@ Committed as `[]` (empty array). The `docfx.yaml` workflow regenerates the real `versions.json` at deploy time from the set of actual `v*` tags that have versioned docs deployed (D6 derivation) and writes it to the gh-pages site root. The empty stub is the fanout-safe default — -no DateTime-Extensions paths leak into other repos when this folder is -synced fleet-wide. +no repo-specific version paths leak into other repos when this folder +is synced fleet-wide. **Local picker testing** requires populating `versions.json` manually with mock entries (see "Testing locally" below). The picker diff --git a/examples/FSharp.DotNet8.Example/Program.fs b/examples/FSharp.DotNet8.Example/Program.fs index 18b22fd..cb79bef 100644 --- a/examples/FSharp.DotNet8.Example/Program.fs +++ b/examples/FSharp.DotNet8.Example/Program.fs @@ -1,4 +1,4 @@ -module FSharp.DotNet462.Example +module FSharp.DotNet8.Example open System open System.IO diff --git a/src/Wolfgang.TryPattern/Result.cs b/src/Wolfgang.TryPattern/Result.cs index f791e12..1883ca4 100644 --- a/src/Wolfgang.TryPattern/Result.cs +++ b/src/Wolfgang.TryPattern/Result.cs @@ -7,10 +7,14 @@ namespace Wolfgang.TryPattern; /// -/// The result of executing an . Contains properties indicating whether the operation -/// succeeded or failed. If the operation failed the property will contain -/// a message as to why. +/// Represents the outcome of an operation. Contains properties indicating whether the operation +/// succeeded or failed. If the operation failed the property will +/// contain a message as to why. /// +/// +/// Commonly produced by , but also useful directly as a return type +/// from validation helpers, repository methods, and other service-layer code. +/// public class Result { /// @@ -55,13 +59,14 @@ protected Result /// - /// Creates a failed Result with the specified error Message. + /// Creates a failed with the specified error message. /// /// The error message indicating the reason for failure. - /// errorMessage is null, empty, or whitespace + /// A failed whose is set to . + /// is null, empty, or whitespace. public static Result Failure(string errorMessage) => string.IsNullOrWhiteSpace(errorMessage) - ? throw new ArgumentException("errorMessage cannot be empty", nameof(errorMessage)) + ? throw new ArgumentException("errorMessage cannot be null, empty, or whitespace.", nameof(errorMessage)) : new Result(succeeded: false, errorMessage); @@ -73,6 +78,7 @@ public static Result Failure(string errorMessage) => /// /// Creates a successful . /// + /// A successful . /// /// Returns a cached singleton instance. is immutable, so reusing /// the same instance is safe and avoids per-call allocations on hot paths. Callers must @@ -102,7 +108,7 @@ public static Result Failure(string errorMessage) => /// - /// The error message describing why the operation failed. Otherwise, an empty string if the operation succeeded. + /// Gets the error message describing why the operation failed, or an empty string if the operation succeeded. /// public string? ErrorMessage { get; } @@ -263,11 +269,17 @@ public static bool AllSucceeded([NotNull] params Result[]? results) /// -/// The result of executing an . Contains properties indicating whether the operation -/// or . If the operation failed the -/// property will contain a message as to why. If the operation succeeded the -/// property will contain the return value from the function. +/// Represents the outcome of an operation that produces a value of type . +/// Contains properties indicating whether the operation or +/// . If the operation failed the property +/// will contain a message as to why. If the operation succeeded the +/// property will contain the returned value. /// +/// The type of value returned on success. +/// +/// Commonly produced by , but also useful directly as a return type +/// from repository, service, or validation code that wants to surface a value-or-error outcome. +/// [System.Diagnostics.CodeAnalysis.SuppressMessage( "Design", "CA1000:Do not declare static members on generic types", @@ -306,27 +318,30 @@ public class Result : Result /// - /// Creates a failed Result with the specified error message. + /// Creates a failed with the specified error message. /// /// The error message indicating the reason for failure. - /// errorMessage is null, empty, or whitespace + /// A failed whose is set to . + /// is null, empty, or whitespace. #if NET5_0_OR_GREATER public static new Result Failure(string errorMessage) => string.IsNullOrWhiteSpace(errorMessage) - ? throw new ArgumentException("errorMessage cannot be empty", nameof(errorMessage)) + ? throw new ArgumentException("errorMessage cannot be null, empty, or whitespace.", nameof(errorMessage)) : new Result(succeeded: false, errorMessage, default!); #else public static new Result Failure(string errorMessage) => string.IsNullOrWhiteSpace(errorMessage) - ? throw new ArgumentException("errorMessage cannot be empty", nameof(errorMessage)) + ? throw new ArgumentException("errorMessage cannot be null, empty, or whitespace.", nameof(errorMessage)) : new Result(succeeded: false, errorMessage, default!); #endif /// - /// Creates a successful with specified value. + /// Creates a successful with the specified value. /// + /// The value produced by the operation. + /// A successful whose is . #if NET5_0_OR_GREATER public static Result Success(T? value) => new(succeeded: true, string.Empty, value); #else @@ -336,9 +351,9 @@ public class Result : Result /// - /// The value produced by the operation if it succeeded. + /// Gets the value produced by the operation if it succeeded; throws if the operation failed. /// - /// Retrieving this property if the operation failed + /// Thrown when this property is accessed after the operation has failed. #if NET5_0_OR_GREATER public T? Value => Failed ? throw new InvalidOperationException("Cannot access the Value of a failed Result.") diff --git a/src/Wolfgang.TryPattern/Try.cs b/src/Wolfgang.TryPattern/Try.cs index 07de954..fbe654c 100644 --- a/src/Wolfgang.TryPattern/Try.cs +++ b/src/Wolfgang.TryPattern/Try.cs @@ -41,13 +41,13 @@ public static Result Run([NotNull] Action? action) /// - /// Executes the specified function, catching any exception that may occur. + /// Executes the specified function and returns its result, catching any exception that may occur. /// /// The return type of the function. /// The function to execute. /// - /// A indicating if the function was successful or not and the result of - /// the function if it was. + /// A successful wrapping the function's return value, or a failed + /// whose is the caught exception's message. /// /// is null. #if NET5_0_OR_GREATER @@ -135,10 +135,10 @@ public static async Task RunAsync([NotNull] Action? action, Cancellation /// - /// Executes the specified function, catching any exception that may occur. + /// Executes the specified asynchronous function, catching any exception that may occur. /// /// The return type of the function. - /// The function to execute. + /// The asynchronous function to execute. /// /// A that is checked before is /// invoked. If cancellation is already requested, an diff --git a/src/Wolfgang.TryPattern/Wolfgang.TryPattern.csproj b/src/Wolfgang.TryPattern/Wolfgang.TryPattern.csproj index cd4be5d..3b930fd 100644 --- a/src/Wolfgang.TryPattern/Wolfgang.TryPattern.csproj +++ b/src/Wolfgang.TryPattern/Wolfgang.TryPattern.csproj @@ -1,32 +1,33 @@ - + - net462;netstandard2.0;net8.0;net10.0 - 14 - 0.3.2 - - 1.0.0.0 - $([System.Text.RegularExpressions.Regex]::Replace("$(Version)", "[-+].*$", "")).0 - $(AssemblyName) - A .NET library demonstrating the Try pattern for structured error handling and result types. - https://github.com/Chris-Wolfgang/Try-Pattern - https://github.com/Chris-Wolfgang/Try-Pattern.git - README.md - MIT - True - True - False - icon.png + net462;netstandard2.0;net8.0;net10.0 + 14 + 0.3.2 + + 1.0.0.0 + $([System.Text.RegularExpressions.Regex]::Replace("$(Version)", "[-+].*$", "")).0 + $(AssemblyName) + A .NET library demonstrating the Try pattern for structured error handling and result types. + try;result;error-handling;exception-handling;functional;railway-oriented;dotnet + https://github.com/Chris-Wolfgang/Try-Pattern + https://github.com/Chris-Wolfgang/Try-Pattern.git + README.md + MIT + True + True + False + icon.png + '$(TargetFramework)' == 'net8.0' OR + '$(TargetFramework)' == 'net10.0' + "> enable diff --git a/tests/Wolfgang.TryPattern.Tests/ResultTests.cs b/tests/Wolfgang.TryPattern.Tests/ResultTests.cs index daa1dfe..9482205 100644 --- a/tests/Wolfgang.TryPattern.Tests/ResultTests.cs +++ b/tests/Wolfgang.TryPattern.Tests/ResultTests.cs @@ -18,7 +18,7 @@ public void Ctor_when_passed_true_and_empty_string_does_not_throw_Exception() [InlineData(null)] [InlineData(" ")] [InlineData("Test error")] - public void Ctor_when_passed_true_and_non_empty_string_throw_InvalidOperationException(string? message) + public void Ctor_when_passed_true_and_non_empty_string_throws_ArgumentException(string? message) { var ex = Assert.Throws(() => new TestResult(succeeded: true, message)); Assert.Equal("errorMessage", ex.ParamName); @@ -38,7 +38,7 @@ public void Ctor_when_passed_false_and_message_does_not_throw_Exception() [InlineData(null)] [InlineData(" ")] [InlineData("")] - public void Ctor_when_passed_false_and_no_message_throw_InvalidOperationException(string? message) + public void Ctor_when_passed_false_and_no_message_throws_ArgumentException(string? message) { var ex = Assert.Throws(() => new TestResult(succeeded: false, message)); Assert.Equal("errorMessage", ex.ParamName); diff --git a/tests/Wolfgang.TryPattern.Tests/RunFuncTests.cs b/tests/Wolfgang.TryPattern.Tests/RunFuncTests.cs index db8584b..0ef76b7 100644 --- a/tests/Wolfgang.TryPattern.Tests/RunFuncTests.cs +++ b/tests/Wolfgang.TryPattern.Tests/RunFuncTests.cs @@ -6,7 +6,7 @@ namespace Wolfgang.TryPattern.Tests; public class RunFuncTests { [Fact] - public void Run_Func_WithNullFunction_ThrowsArgumentNullException() + public void Run_Func_when_function_is_null_throws_ArgumentNullException() { // Arrange Func? nullFunction = null; @@ -18,7 +18,7 @@ public void Run_Func_WithNullFunction_ThrowsArgumentNullException() [Fact] - public void Run_Func_WithSuccessfulFunctionOfInt_ReturnsResult() + public void Run_Func_when_int_function_succeeds_returns_successful_Result() { // Arrange const int expectedValue = 42; @@ -37,7 +37,7 @@ public void Run_Func_WithSuccessfulFunctionOfInt_ReturnsResult() [Fact] - public void Run_Func_WithSuccessfulFunctionOfNullableInt_ReturnsResult() + public void Run_Func_when_nullable_int_function_succeeds_returns_successful_Result() { // Arrange var expectedValue = 42; @@ -56,7 +56,7 @@ public void Run_Func_WithSuccessfulFunctionOfNullableInt_ReturnsResult() [Fact] - public void Run_Func_WithStringFunction_ReturnsResult() + public void Run_Func_when_string_function_succeeds_returns_successful_Result() { // Arrange const string expectedValue = "Hello, World!"; @@ -75,7 +75,7 @@ public void Run_Func_WithStringFunction_ReturnsResult() [Fact] - public void Run_Func_WithNullableStringFunction_ReturnsResult() + public void Run_Func_when_nullable_string_function_succeeds_returns_successful_Result() { // Arrange const string expectedValue = "Hello, World!"; @@ -94,7 +94,7 @@ public void Run_Func_WithNullableStringFunction_ReturnsResult() [Fact] - public void Run_Func_WithObjectFunction_ReturnsResult() + public void Run_Func_when_object_function_succeeds_returns_successful_Result() { // Arrange var expectedValue = new object(); @@ -113,7 +113,7 @@ public void Run_Func_WithObjectFunction_ReturnsResult() [Fact] - public void FunctionNullableInt_WithExceptionThrowingFunction_ReturnsDefault() + public void Run_Func_when_nullable_int_function_throws_returns_failed_Result_whose_Value_access_throws() { // Arrange static int? Function() => throw new InvalidOperationException("Test exception"); @@ -149,7 +149,7 @@ public void Run_Func_reference_type_returns_Result_with_correct_properties() [Fact] - public void Run_Func_WithMultipleCalls_HandlesEachIndependently() + public void Run_Func_when_called_multiple_times_handles_each_independently() { // Arrange var callCount = 0; diff --git a/tests/Wolfgang.TryPattern.Tests/Wolfgang.TryPattern.Tests.Unit.csproj b/tests/Wolfgang.TryPattern.Tests/Wolfgang.TryPattern.Tests.Unit.csproj index ba1906d..1cfd526 100644 --- a/tests/Wolfgang.TryPattern.Tests/Wolfgang.TryPattern.Tests.Unit.csproj +++ b/tests/Wolfgang.TryPattern.Tests/Wolfgang.TryPattern.Tests.Unit.csproj @@ -2,7 +2,6 @@ net462;net472;net48;net481;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0 - 0.3.0 latest enable false @@ -61,23 +60,6 @@ - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - -