diff --git a/bench/record_result.dart b/bench/record_result.dart index 2acbd5f..8617357 100644 --- a/bench/record_result.dart +++ b/bench/record_result.dart @@ -1,3 +1,5 @@ +// ignore_for_file: null_check_on_nullable_type_parameter + import 'package:inline_result/inline_result.dart'; extension type RecordResult._((T? value, Exception? exception) _value) { diff --git a/example/inline_result_example.dart b/example/inline_result_example.dart index 0cd0e44..557747e 100644 --- a/example/inline_result_example.dart +++ b/example/inline_result_example.dart @@ -2,7 +2,7 @@ import 'package:inline_result/inline_result.dart'; -Result divide(int a, int b) { +Result divide(int a, int b) { return runCatching(() { if (b == 0) { throw Exception('Division by zero'); diff --git a/lib/src/failure.dart b/lib/src/failure.dart index 66fa96f..49601ed 100644 --- a/lib/src/failure.dart +++ b/lib/src/failure.dart @@ -2,9 +2,9 @@ part of 'result.dart'; /// Internal class representing a failed Result. @immutable -class _Failure { +class _Failure { /// The exception encapsulated in this failure. - final Exception exception; + final F exception; /// Optional stacktrace of this failure. final StackTrace? stacktrace; diff --git a/lib/src/fold.dart b/lib/src/fold.dart index 78183e2..a5e1594 100644 --- a/lib/src/fold.dart +++ b/lib/src/fold.dart @@ -1,7 +1,7 @@ part of 'result.dart'; /// Extension providing folding functionality for [Result]. -extension ResultFold on Result { +extension ResultFold on Result { /// Combines both cases of Result into a single value. /// /// [onSuccess] handles successful values. @@ -9,15 +9,15 @@ extension ResultFold on Result { @pragma('vm:prefer-inline') R fold({ required Transformer onSuccess, - required FailureTransformer onFailure, + required FailureTransformer onFailure, }) => - _value is _Failure + _value is _Failure ? onFailure(_value.exception, _value.stacktrace) : onSuccess(_value as T); } /// Extension providing folding functionality for [Result]. -extension FutureResultFold on Future> { +extension FutureResultFold on Future> { /// Combines both cases of Result into a single value. /// /// [onSuccess] handles successful values. @@ -25,9 +25,9 @@ extension FutureResultFold on Future> { @pragma('vm:prefer-inline') Future fold({ required AsyncTransformer onSuccess, - required AsyncFailureTransformer onFailure, + required AsyncFailureTransformer onFailure, }) => - then((result) => result._value is _Failure + then((result) => result._value is _Failure ? onFailure(result._value.exception, result._value.stacktrace) : onSuccess(result._value)); } diff --git a/lib/src/future.dart b/lib/src/future.dart index cd44da5..a68c633 100644 --- a/lib/src/future.dart +++ b/lib/src/future.dart @@ -24,15 +24,15 @@ extension FutureResult on Future { /// /// - If the [Future] completes successfully, wraps the value in [Result.success]. /// - If the [Future] completes with an [Exception], wraps the exception in [Result.failure]. - Future> get asResult => - then(Result.success).onError(Result.failure); + Future> asResult() => + then(Result.success).onError(Result.failure); } extension FutureOrResult on FutureOr { - FutureOr> get asResult async { + FutureOr> asResult() async { try { return Result.success(await this); - } on Exception catch (e, st) { + } on F catch (e, st) { return Result.failure(e, st); } } diff --git a/lib/src/getter.dart b/lib/src/getter.dart index f9131c5..cac68f3 100644 --- a/lib/src/getter.dart +++ b/lib/src/getter.dart @@ -1,39 +1,50 @@ part of 'result.dart'; /// Extension providing getters for Result's values -extension ResultGetter on Result { +extension ResultGetter on Result { /// Returns the encapsulated value if successful, otherwise `null`. @pragma('vm:prefer-inline') T? get getOrNull => isFailure ? null : _value as T; /// Returns the encapsulated exception if failed, otherwise `null`. @pragma('vm:prefer-inline') - Exception? get exceptionOrNull => - isFailure ? (_value as _Failure).exception : null; + F? get exceptionOrNull => _value is _Failure ? _value.exception : null; /// Returns the encapsulated stacktrace if failed and there is stacktrace, /// otherwise `null`. @pragma('vm:prefer-inline') StackTrace? get stacktraceOrNull => - _value is _Failure ? _value.stacktrace : null; + _value is _Failure ? _value.stacktrace : null; /// Returns the encapsulated value if successful, otherwise throws the exception. /// /// Throws the encapsulated [Exception] if this Result is a failure. @pragma('vm:prefer-inline') - T get getOrThrow => _value is _Failure ? throw _value.exception : _value as T; + T get getOrThrow => + //ignore:only_throw_errors + _value is _Failure ? throw _value.exception : _value as T; + + /// Returns the value if successful, otherwise applies [onFailure]. + @pragma('vm:prefer-inline') + T getOrElse(FailureTransformer onFailure) => _value is _Failure + ? onFailure(_value.exception, _value.stacktrace) + : _value as T; + + /// Returns the value if successful, otherwise [defaultValue]. + @pragma('vm:prefer-inline') + T getOrDefault(T defaultValue) => + _value is _Failure ? defaultValue : _value as T; } /// Extension providing getters for Result's values -extension FutureResultGetter on Future> { +extension FutureResultGetter on Future> { /// Returns the encapsulated value if successful, otherwise `null`. @pragma('vm:prefer-inline') Future get getOrNull => then((result) => result.getOrNull); /// Returns the encapsulated exception if failed, otherwise `null`. @pragma('vm:prefer-inline') - Future get exceptionOrNull => - then((result) => result.exceptionOrNull); + Future get exceptionOrNull => then((result) => result.exceptionOrNull); /// Returns the encapsulated stacktrace if failed and there is stacktrace, /// otherwise `null`. @@ -46,4 +57,19 @@ extension FutureResultGetter on Future> { /// Throws the encapsulated [Exception] if this Result is a failure. @pragma('vm:prefer-inline') Future get getOrThrow => then((result) => result.getOrThrow); + + /// Returns the value if successful, otherwise applies [onFailure]. + @pragma('vm:prefer-inline') + Future getOrElse(AsyncFailureTransformer onFailure) => + then((result) => result._value is _Failure + ? onFailure( + result._value.exception, + result._value.stacktrace, + ) + : result._value as T); + + /// Returns the value if successful, otherwise [defaultValue]. + @pragma('vm:prefer-inline') + Future getOrDefault(T defaultValue) => + then((result) => result.getOrDefault(defaultValue)); } diff --git a/lib/src/on_action.dart b/lib/src/on_action.dart index 7c67890..2f85c85 100644 --- a/lib/src/on_action.dart +++ b/lib/src/on_action.dart @@ -1,13 +1,15 @@ part of 'result.dart'; /// Extension providing side-effect methods for [Result]. -extension ResultOnActions on Result { +extension ResultOnActions on Result { /// Executes [action] if this Result is a failure and returns itself. /// /// Useful for logging or handling failures without modifying the Result. @pragma('vm:prefer-inline') - Result onFailure(FailureTransformer action) { - if (_value is _Failure && _value.exception is E) { + Result onFailure( + FailureTransformer action, + ) { + if (_value is _Failure && _value.exception is E) { action(_value.exception as E, _value.stacktrace); } return this; @@ -17,7 +19,7 @@ extension ResultOnActions on Result { /// /// Useful for processing successful values without modifying the Result. @pragma('vm:prefer-inline') - Result onSuccess(Transformer action) { + Result onSuccess(Transformer action) { if (_value is T) { action(_value); } @@ -25,19 +27,20 @@ extension ResultOnActions on Result { } } -extension FutureResultOnActions on Future> { +extension FutureResultOnActions on Future> { /// Executes [action] if this Result is a failure and returns itself. /// /// Useful for logging or handling failures without modifying the Result. @pragma('vm:prefer-inline') - Future> onFailure( - FailureTransformer action) => + Future> onFailure( + FailureTransformer action, + ) => then((result) => result.onFailure(action)); /// Executes [action] if this Result is successful and returns itself. /// /// Useful for processing successful values without modifying the Result. @pragma('vm:prefer-inline') - Future> onSuccess(void Function(T value) action) => + Future> onSuccess(void Function(T value) action) => then((result) => result.onSuccess(action)); } diff --git a/lib/src/or.dart b/lib/src/or.dart deleted file mode 100644 index ad053c1..0000000 --- a/lib/src/or.dart +++ /dev/null @@ -1,33 +0,0 @@ -part of 'result.dart'; - -/// Extension providing fallback value methods. -extension ResultOr on Result { - /// Returns the value if successful, otherwise applies [onFailure]. - @pragma('vm:prefer-inline') - T getOrElse(FailureTransformer onFailure) => _value is _Failure - ? onFailure(_value.exception, _value.stacktrace) - : _value as T; - - /// Returns the value if successful, otherwise [defaultValue]. - @pragma('vm:prefer-inline') - T getOrDefault(T defaultValue) => - _value is _Failure ? defaultValue : _value as T; -} - -/// Extension providing fallback value methods. -extension FutureResultOr on Future> { - /// Returns the value if successful, otherwise applies [onFailure]. - @pragma('vm:prefer-inline') - Future getOrElse(AsyncFailureTransformer onFailure) => - then((result) => result._value is _Failure - ? onFailure( - result._value.exception, - result._value.stacktrace, - ) - : result._value as T); - - /// Returns the value if successful, otherwise [defaultValue]. - @pragma('vm:prefer-inline') - Future getOrDefault(T defaultValue) => - then((result) => result.getOrDefault(defaultValue)); -} diff --git a/lib/src/recover.dart b/lib/src/recover.dart index 0f0a3ab..6ac2b30 100644 --- a/lib/src/recover.dart +++ b/lib/src/recover.dart @@ -1,15 +1,15 @@ part of 'result.dart'; /// Extension providing recovery methods for [Result]. -extension ResultRecover on Result { +extension ResultRecover on Result { /// Transforms a failure into a success using [transform]. /// /// If this [Result] is a failure, applies [transform] to the exception and returns /// a successful [Result] containing the transformed value. /// If successful, returns the original [Result]. @pragma('vm:prefer-inline') - Result recover(FailureTransformer transform) => - _value is _Failure && _value.exception is E + Result recover(FailureTransformer transform) => + _value is _Failure && _value.exception is E ? Result.success(transform(_value.exception as E, _value.stacktrace)) : this; @@ -17,10 +17,10 @@ extension ResultRecover on Result { /// /// Similar to [recover], but wraps any exceptions thrown by [transform] in a [Result]. @pragma('vm:prefer-inline') - Result recoverCatching( + Result recoverCatching( FailureTransformer transform, ) => - _value is _Failure && _value.exception is E + _value is _Failure && _value.exception is E ? runCatching(() => transform( _value.exception as E, _value.stacktrace, @@ -29,18 +29,18 @@ extension ResultRecover on Result { } /// Extension providing recovery methods for [Result]. -extension FutureResultRecover on Future> { +extension FutureResultRecover on Future> { /// Transforms a failure into a success using [transform]. /// /// If this [Result] is a failure, applies [transform] to the exception and returns /// a successful [Result] containing the transformed value. /// If successful, returns the original [Result]. @pragma('vm:prefer-inline') - Future> recover( + Future> recover( AsyncFailureTransformer transform, ) => then((result) async => - result._value is _Failure && result._value.exception is E + result._value is _Failure && result._value.exception is E ? Result.success(await transform( result._value.exception as E, result._value.stacktrace, @@ -51,13 +51,14 @@ extension FutureResultRecover on Future> { /// /// Similar to [recover], but wraps any exceptions thrown by [transform] in a [Result]. @pragma('vm:prefer-inline') - Future> recoverCatching( + Future> recoverCatching( AsyncFailureTransformer transform, ) => - then((result) => result._value is _Failure && result._value.exception is E - ? transform( - result._value.exception as E, - result._value.stacktrace, - ).asResult - : result); + then((result) => + result._value is _Failure && result._value.exception is E + ? transform( + result._value.exception as E, + result._value.stacktrace, + ).asResult() + : result); } diff --git a/lib/src/result.dart b/lib/src/result.dart index 9e8ed9d..71a150a 100644 --- a/lib/src/result.dart +++ b/lib/src/result.dart @@ -12,8 +12,6 @@ part 'getter.dart'; part 'on_action.dart'; -part 'or.dart'; - part 'recover.dart'; part 'run_catching.dart'; @@ -26,12 +24,12 @@ typedef Transformer = R Function(T value); typedef AsyncTransformer = FutureOr Function(T value); /// Transform failure result from [exception] and optional [stacktrace] into new value of [R]. -typedef FailureTransformer = R Function( +typedef FailureTransformer = R Function( E exception, StackTrace? stacktrace, ); -typedef AsyncFailureTransformer = FutureOr Function( +typedef AsyncFailureTransformer = FutureOr Function( E exception, StackTrace? stacktrace, ); @@ -45,28 +43,14 @@ typedef Block = T Function(); /// This is implemented as an extension type for zero-cost wrapping, providing static type safety /// while having no runtime overhead. Use [Result.success] to wrap successful values and /// [Result.failure] to wrap exceptions. -extension type const Result._(dynamic _value) { +extension type const Result._(dynamic _value) { /// Creates a successful Result containing [value]. const factory Result.success(T value) = Result._; /// Creates a failed Result containing [exception] and optional [stacktrace]. - factory Result.failure(Exception exception, [StackTrace? stacktrace]) => + factory Result.failure(F exception, [StackTrace? stacktrace]) => Result._(_Failure(exception, stacktrace)); - /// Executes [block] and wraps any thrown [Exception] in a [Result]. - /// - /// If [block] completes successfully, returns [Result.success] with the result. - /// If [block] throws, returns [Result.failure] with the exception. - @Deprecated('Will be removed. Use global function runCatching instead.') - @pragma('vm:prefer-inline') - static Result runCatching(Block block) { - try { - return Result.success(block()); - } on Exception catch (exception, stacktrace) { - return Result.failure(exception, stacktrace); - } - } - /// Returns `true` if this [Result] is successful. bool get isSuccess => _value is! _Failure; diff --git a/lib/src/run_catching.dart b/lib/src/run_catching.dart index 78d7204..3f66298 100644 --- a/lib/src/run_catching.dart +++ b/lib/src/run_catching.dart @@ -5,10 +5,10 @@ part of 'result.dart'; /// If [block] completes successfully, returns [Result.success] with the result. /// If [block] throws, returns [Result.failure] with the exception. @pragma('vm:prefer-inline') -Result runCatching(Block block) { +Result runCatching(Block block) { try { return Result.success(block()); - } on Exception catch (exception, stacktrace) { + } on F catch (exception, stacktrace) { return Result.failure(exception, stacktrace); } } @@ -17,10 +17,12 @@ Result runCatching(Block block) { /// /// If [block] completes successfully, returns [Result.success] with the result. /// If [block] throws, returns [Result.failure] with the exception. -Future> asyncRunCatching(Future Function() block) async { +Future> asyncRunCatching( + Future Function() block, +) async { try { return Result.success(await block()); - } on Exception catch (exception, stacktrace) { + } on F catch (exception, stacktrace) { return Result.failure(exception, stacktrace); } } @@ -33,10 +35,10 @@ extension RunCatchingX on T { /// If [block] completes successfully, returns [Result.success] with the result. /// If [block] throws, returns [Result.failure] with the exception. @pragma('vm:prefer-inline') - Result runCatching(R Function(T value) block) { + Result runCatching(R Function(T value) block) { try { return Result.success(block(this)); - } on Exception catch (exception, stacktrace) { + } on F catch (exception, stacktrace) { return Result.failure(exception, stacktrace); } } @@ -48,12 +50,12 @@ extension FutureRunCatchingX on Future { /// /// If [block] completes successfully, returns [Result.success] with the result. /// If [block] throws, returns [Result.failure] with the exception. - Future> asyncRunCatching( + Future> asyncRunCatching( FutureOr Function(T value) block, ) async { try { return Result.success(await block(await this)); - } on Exception catch (exception, stacktrace) { + } on F catch (exception, stacktrace) { return Result.failure(exception, stacktrace); } } diff --git a/lib/src/transformation.dart b/lib/src/transformation.dart index 550bd3a..7d2bfed 100644 --- a/lib/src/transformation.dart +++ b/lib/src/transformation.dart @@ -1,67 +1,69 @@ part of 'result.dart'; /// Extension providing transformation methods for [Result]. -extension ResultTransformation on Result { +extension ResultTransformation on Result { /// Transforms a successful value using [transform]. /// /// If successful, returns a new Result with the transformed value. /// If failed, returns the original failure. @pragma('vm:prefer-inline') - Result map(Transformer transform) => - isSuccess ? Result.success(transform(_value as T)) : Result._(_value); + Result map(Transformer transform) => isSuccess + ? Result.success(transform(_value as T)) + : Result._(_value); /// Transforms a successful value, catching exceptions from [transform]. /// /// Similar to [map], but wraps any exceptions thrown by [transform] in a Result. @pragma('vm:prefer-inline') - Result mapCatching(Transformer transform) => isSuccess - ? runCatching(() => transform(_value as T)) - : Result._(_value); + Result mapCatching(Transformer transform) => isSuccess + ? runCatching(() => transform(_value as T)) + : Result._(_value); /// Transforms a successful value to another [Result] using [transform]. /// /// If successful, applies [transform] and returns its result. /// If failed, returns the original failure. @pragma('vm:prefer-inline') - Result flatMap(Result Function(T value) transform) => - _value is _Failure - ? Result.failure( + Result flatMap(Result Function(T value) transform) => + _value is _Failure + ? Result.failure( _value.exception, _value.stacktrace, ) : transform(_value as T); } -extension FutureResultTransformation on Future> { +extension FutureResultTransformation + on Future> { /// Transforms a successful value using [transform]. /// /// If successful, returns a new Result with the transformed value. /// If failed, returns the original failure. @pragma('vm:prefer-inline') - Future> map(AsyncTransformer transform) => - then((result) async => result._value is _Failure - ? Result._(result._value) + Future> map(AsyncTransformer transform) => + then((result) async => result._value is _Failure + ? Result._(result._value) : Result.success(await transform(result._value))); /// Transforms a successful value, catching exceptions from [transform]. /// /// Similar to [map], but wraps any exceptions thrown by [transform] in a Result. @pragma('vm:prefer-inline') - Future> mapCatching(AsyncTransformer transform) => + Future> mapCatching(AsyncTransformer transform) => then((result) => result.isSuccess ? asyncRunCatching(() async => transform(result._value as T)) - : Future.value(Result._(result._value))); + : Future.value(Result._(result._value))); /// Transforms a successful value to another [Result] using [transform]. /// /// If successful, applies [transform] and returns its result. /// If failed, returns the original failure. @pragma('vm:prefer-inline') - Future> flatMap( - FutureOr> Function(T value) transform, + Future> flatMap( + FutureOr> Function(T value) transform, ) => - then((result) => result._value is _Failure - ? Result.failure( + then((result) => result._value is _Failure + ? Result.failure( result._value.exception, result._value.stacktrace, ) diff --git a/test/inline_result_test.dart b/test/inline_result_test.dart index 742245c..93f5946 100644 --- a/test/inline_result_test.dart +++ b/test/inline_result_test.dart @@ -9,7 +9,7 @@ void main() { // group('Synchronous Result Tests', () { test('runCatching returns success when block succeeds', () { - final result = Result.runCatching(() => 'OK'); + final result = runCatching(() => 'OK'); expect(result.isSuccess, isTrue); expect(result.isFailure, isFalse); expect(result.getOrNull, equals('OK')); @@ -27,8 +27,8 @@ void main() { }); test('runCatching returns failure when block throws', () { - final result = - runCatching(() => throw const CustomException('F')); + final result = runCatching( + () => throw const CustomException('F')); expect(result.isSuccess, isFalse); expect(result.isFailure, isTrue); expect(result.getOrNull, isNull); @@ -55,7 +55,8 @@ void main() { }); test('constructed failure result throws on getOrThrow', () { - final result = Result.failure(const CustomException('F')); + final result = + Result.failure(const CustomException('F')); expect(result.isFailure, isTrue); expect(() => result.getOrThrow, throwsA(isA())); }); @@ -78,8 +79,8 @@ void main() { }); test('map on failure propagates the original failure', () { - final failure = - Result.failure(const CustomException('F'), StackTrace.empty); + final failure = Result.failure( + const CustomException('F'), StackTrace.empty); final mapped = failure.map((v) => v * 2); expect(mapped.isFailure, isTrue); expect(mapped.stacktraceOrNull, isNotNull); @@ -104,8 +105,8 @@ void main() { expect(() => flatFailure.getOrThrow, throwsA(isA())); // flatMap on failure should not execute the transformation. - final originalFailure = - Result.failure(const CustomException('original failure')); + final originalFailure = Result.failure( + const CustomException('original failure')); var transformCalled = false; final propagated = originalFailure.flatMap((v) { transformCalled = true; @@ -118,7 +119,8 @@ void main() { test('recover and recoverCatching work as expected', () { // recover transforms failure to success. - final failure = Result.failure(const CustomException('F')); + final failure = + Result.failure(const CustomException('F')); final recovered = failure.recover((e, _) => 42); expect(recovered.isSuccess, isTrue); expect(recovered.getOrThrow, equals(42)); @@ -126,7 +128,7 @@ void main() { // recover with specific exception type. bool isFormatCalled = false; bool isCustomCalled = false; - final res = runCatching(() { + final res = runCatching(() { throw const FormatException(); }).recover((_, __) { isFormatCalled = true; @@ -140,19 +142,21 @@ void main() { expect(isCustomCalled, isFalse); // recover on a success should return the original value. - const success = Result.success(10); + const success = Result.success(10); final recovSuccess = success.recover((e, _) => 42); expect(recovSuccess.isSuccess, isTrue); expect(recovSuccess.getOrThrow, equals(10)); // recoverCatching transforms failure to success. - final failure2 = Result.failure(const CustomException('F')); + final failure2 = + Result.failure(const CustomException('F')); final recoveredCatching = failure2.recoverCatching((e, _) => 42); expect(recoveredCatching.isSuccess, isTrue); expect(recoveredCatching.getOrThrow, equals(42)); // recoverCatching catches exception thrown in the recovery transform. - final failure3 = Result.failure(const CustomException('F')); + final failure3 = + Result.failure(const CustomException('F')); final recoveredCatchingFail = failure3.recoverCatching( (e, _) => throw const CustomException('recoverFail')); expect(recoveredCatchingFail.isFailure, isTrue); @@ -160,7 +164,7 @@ void main() { throwsA(isA())); // recoverCatching on a success returns the original value. - final success2 = Result.success(10); + const success2 = Result.success(10); final recoveredCatchingSuccess = success2.recoverCatching((e, _) => 42); expect(recoveredCatchingSuccess.isSuccess, isTrue); expect(recoveredCatchingSuccess.getOrThrow, equals(10)); @@ -174,7 +178,8 @@ void main() { expect(identical(successResult, afterSuccess), isTrue); Object? failureCapture; - final failureResult = Result.failure(const CustomException('F')); + final failureResult = + Result.failure(const CustomException('F')); final afterFailure = failureResult.onFailure((e, _) => failureCapture = e); expect(failureCapture, isNotNull); @@ -187,7 +192,7 @@ void main() { expect(successResult.stacktraceOrNull, isNull); // For a failure, the stacktrace should be non-null. - final failureResult = Result.runCatching(() { + final failureResult = runCatching(() { throw CustomException(DateTime.now().toIso8601String()); }); expect(failureResult.isFailure, isTrue); @@ -225,7 +230,7 @@ void main() { test( 'asyncRunCatching extension returns failure for async block throwing error', () async { - final result = await Future.value(10).asyncRunCatching( + final result = await Future.value(10).asyncRunCatching( (v) => throw const CustomException('run async fail')); expect(result.isFailure, isTrue); expect(() => result.getOrThrow, throwsA(isA())); @@ -238,14 +243,14 @@ void main() { group('Future Result Tests', () { test('asResult converts successful future to success', () async { final future = Future.value(42); - final result = await future.asResult; + final result = await future.asResult(); expect(result.isSuccess, isTrue); expect(result.getOrThrow, equals(42)); }); test('asResult converts failing future (Exception) to failure', () async { final future = Future.error(Exception('Failure occurred')); - final result = await future.asResult; + final result = await future.asResult(); expect(result.isFailure, isTrue); expect(result.exceptionOrNull, isA()); expect(result.exceptionOrNull.toString(), contains('Failure occurred')); @@ -254,7 +259,7 @@ void main() { test('asResult converts failing future (CustomException) to failure', () async { final future = Future.error(const CustomException('Custom failure')); - final result = await future.asResult; + final result = await future.asResult(); expect(result.isFailure, isTrue); expect(result.exceptionOrNull, isA()); expect(result.exceptionOrNull.toString(), contains('Custom failure')); @@ -263,12 +268,12 @@ void main() { test('asResult on failing future with non-Exception error throws', () async { final future = Future.error('Non-exception error'); - expect(future.asResult, throwsA(isA())); + expect(future.asResult(), throwsA(isA())); }); test('asResult converts delayed success to success', () async { final future = Future.delayed(const Duration(milliseconds: 50), () => 99); - final result = await future.asResult; + final result = await future.asResult(); expect(result.isSuccess, isTrue); expect(result.getOrThrow, equals(99)); }); @@ -278,7 +283,7 @@ void main() { const Duration(milliseconds: 50), () => throw Exception('Delayed failure'), ); - final result = await future.asResult; + final result = await future.asResult(); expect(result.isFailure, isTrue); expect(result.exceptionOrNull, isA()); expect(result.exceptionOrNull.toString(), contains('Delayed failure')); @@ -294,8 +299,8 @@ void main() { }); test('Future fold on failure computes fallback value', () async { - final futureResult = - Future.value(Result.failure(const CustomException('fail'))); + final futureResult = Future.value( + Result.failure(const CustomException('fail'))); final folded = await futureResult.fold( onSuccess: (v) async => v * 2, onFailure: (e, st) async => -1, @@ -310,11 +315,11 @@ void main() { expect(successResult, equals('OK')); final failureResult = await Future.value( - Result.failure(const CustomException('err'))) + Result.failure(const CustomException('err'))) .exceptionOrNull; expect(failureResult.toString(), contains('CustomException: err')); - final stacktrace = await Future.value(Result.failure( + final stacktrace = await Future.value(Result.failure( const CustomException('err'), StackTrace.current)) .stacktraceOrNull; expect(stacktrace, isNotNull); @@ -322,8 +327,8 @@ void main() { final value = await Future.value(const Result.success(42)).getOrThrow; expect(value, equals(42)); - final futureFail = - Future.value(Result.failure(const CustomException('fail'))); + final futureFail = Future.value( + Result.failure(const CustomException('fail'))); expect( () async => futureFail.getOrThrow, throwsA(isA())); }); @@ -336,9 +341,9 @@ void main() { expect(successFuture.getOrThrow, equals(5)); Object? capturedFailure; - final failureFuture = - await Future.value(Result.failure(const CustomException('fail'))) - .onFailure((e, st) => capturedFailure = e); + final failureFuture = await Future.value( + Result.failure(const CustomException('fail'))) + .onFailure((e, st) => capturedFailure = e); expect(capturedFailure, isNotNull); expect(capturedFailure.toString(), contains('CustomException: fail')); expect(() => failureFuture.getOrThrow, throwsA(isA())); @@ -349,8 +354,8 @@ void main() { final valueSuccess = await futureSuccess.getOrElse((e, st) async => 0); expect(valueSuccess, equals(10)); - final futureFailure = - Future.value(Result.failure(const CustomException('fail'))); + final futureFailure = Future.value( + Result.failure(const CustomException('fail'))); final valueFailure = await futureFailure.getOrElse((e, st) async => 99); expect(valueFailure, equals(99)); @@ -358,16 +363,16 @@ void main() { await Future.value(const Result.success(10)).getOrDefault(100); expect(defaultSuccess, equals(10)); - final defaultFailure = - await Future.value(Result.failure(const CustomException('fail'))) - .getOrDefault(100); + final defaultFailure = await Future.value( + Result.failure(const CustomException('fail'))) + .getOrDefault(100); expect(defaultFailure, equals(100)); }); test('Future recover and recoverCatching work as expected', () async { // recover transforms failure into a success value. - final futureFailure = - Future.value(Result.failure(const CustomException('fail'))); + final futureFailure = Future.value( + Result.failure(const CustomException('fail'))); final recovered = await futureFailure.recover((e, st) async => 55); expect(recovered.isSuccess, isTrue); expect(recovered.getOrThrow, equals(55)); @@ -379,16 +384,16 @@ void main() { expect(recoveredSuccess.getOrThrow, equals(77)); // recoverCatching transforms failure to success. - final futureFailure2 = - Future.value(Result.failure(const CustomException('fail'))); + final futureFailure2 = Future.value( + Result.failure(const CustomException('fail'))); final recoveredCatching = await futureFailure2.recoverCatching((e, st) async => 88); expect(recoveredCatching.isSuccess, isTrue); expect(recoveredCatching.getOrThrow, equals(88)); // recoverCatching catches exception in the recovery transform. - final futureFailure3 = - Future.value(Result.failure(const CustomException('fail'))); + final futureFailure3 = Future.value( + Result.failure(const CustomException('fail'))); final recoveredCatchingFail = await futureFailure3.recoverCatching( (e, st) async => throw const CustomException('recovery fail')); expect(recoveredCatchingFail.isFailure, isTrue); @@ -415,13 +420,13 @@ void main() { }); test('asResult on FutureOr values works correctly', () async { - final syncResult = await (42 as FutureOr).asResult; + final syncResult = await (42 as FutureOr).asResult(); expect(syncResult.isSuccess, isTrue); expect(syncResult.getOrThrow, equals(42)); final syncFailure = await Future.sync(() => throw const CustomException('sync error')) - .asResult; + .asResult(); expect(syncFailure.isFailure, isTrue); expect(() => syncFailure.getOrThrow, throwsA(isA())); }); @@ -435,8 +440,8 @@ void main() { expect(mapped.getOrThrow, equals(20)); // map propagates failure without transformation. - final futureFailureMap = - Future.value(Result.failure(const CustomException('fail'))); + final futureFailureMap = Future.value( + Result.failure(const CustomException('fail'))); final mappedFailure = await futureFailureMap.map((v) async => v * 4); expect(mappedFailure.isFailure, isTrue);