namespace Raliway.Tests.Results; public class Bugs { #region BUG-1: Result.Equals asymmetry [Fact] public void Result_Success_ShouldNotEqual_Default() { // default(Result) has State=Bottom — it's uninitialized. // Equals should throw because one operand is Bottom. var success = Result.Success(); Result bottom = default; // Should throw ResultNotInitializedException, NOT return true Should.Throw(() => success.Equals(bottom)); } [Fact] public void Result_Default_ShouldNotEqual_Success() { Result bottom = default; var success = Result.Success(); Should.Throw(() => bottom.Equals(success)); } [Fact] public void Result_Success_EqualsOperator_WithDefault() { var success = Result.Success(); Result bottom = default; Should.Throw(() => success == bottom); } [Fact] public void Result_Error_Equals_WithBottom_ShouldThrow() { var error = Result.Failure("test"); Result bottom = default; Should.Throw(() => error.Equals(bottom)); } [Fact] public void Result_Bottom_Equals_WithSuccess_ShouldThrow() { Result bottom = default; var success = Result.Success(); Should.Throw(() => bottom.Equals(success)); } #endregion #region BUG-2: Result.Equals asymmetry [Fact] public void ResultOfT_Success_ShouldNotEqual_Default() { var success = Result.Success(42); Result bottom = default; Should.Throw(() => success.Equals(bottom)); } [Fact] public void ResultOfT_Error_ShouldNotEqual_Default() { var error = Result.Failure("test"); Result bottom = default; Should.Throw(() => error.Equals(bottom)); } [Fact] public void ResultOfT_Default_ShouldNotEqual_Success() { Result bottom = default; var success = Result.Success(42); Should.Throw(() => bottom.Equals(success)); } #endregion #region BUG-3: Task.WhenAny Merge — faulted task [Fact] public async Task Merge_Tasks_WhenOneFaults_ShouldReturnError_NotThrow() { var tasks = new Task[] { Task.FromResult(Result.Success()), Task.Run(() => { throw new InvalidOperationException("boom"); #pragma warning disable CS0162 // Unreachable code return Result.Success(); #pragma warning restore CS0162 }), }; // Should not throw AggregateException escaping the Result error channel var result = await tasks.Merge(); result.IsFailure.ShouldBeTrue(); } [Fact] public async Task Merge_Tasks_WhenOneIsCanceled_ShouldReturnError_NotThrow() { var cts = new CancellationTokenSource(); cts.Cancel(); var canceledTask = Task.FromCanceled(cts.Token); var tasks = new Task[] { Task.FromResult(Result.Success()), canceledTask, }; // Should not throw — canceled tasks have null Exception var result = await tasks.Merge(); result.IsFailure.ShouldBeTrue(); } #endregion #region BUG-4: Task.WhenAny Merge — canceled task + O(n²) [Fact] public async Task MergeOfT_Tasks_WhenOneIsCanceled_ShouldReturnError_NotThrow() { var cts = new CancellationTokenSource(); cts.Cancel(); var canceledTask = Task.FromCanceled>(cts.Token); var tasks = new Task>[] { Task.FromResult(Result.Success(1)), canceledTask, }; // Should not crash on canceled task (task.Exception is null → null ref in implicit operator) var result = await tasks.Merge(); result.IsFailure.ShouldBeTrue(); } [Fact] public async Task MergeOfT_Tasks_WhenOneFaults_ShouldReturnError_NotThrow() { var tasks = new Task>[] { Task.FromResult(Result.Success(1)), Task.Run(() => { throw new InvalidOperationException("boom"); #pragma warning disable CS0162 // Unreachable code return Result.Success(2); #pragma warning restore CS0162 }), }; var result = await tasks.Merge(); result.IsFailure.ShouldBeTrue(); } #endregion #region BUG-5: Error.New null type [Fact] public void Error_New_WithNullType_ShouldThrowArgumentNullException() { // Null type should throw immediately at construction, not crash later in CompareTo/IsSimilarTo Should.Throw(() => Error.New(null!, "some message")); } #endregion }