Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkgs/async/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
with variable intervals.
- Mark `Result` as `sealed`, and `ValueResult`, and `ErrorResult` as `final`
classes.
- Add `value` getter to `Result`.

## 2.13.1

Expand Down
5 changes: 5 additions & 0 deletions pkgs/async/lib/src/result/error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ final class ErrorResult implements Result<Never> {
@override
Future<Never> get asFuture => Future<Never>.error(error, stackTrace);

@override
Never get value {
Error.throwWithStackTrace(error, stackTrace);
}

/// Calls an error handler with the error and stacktrace.
///
/// An async error handler function is either a function expecting two
Expand Down
10 changes: 10 additions & 0 deletions pkgs/async/lib/src/result/result.dart
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,16 @@ sealed class Result<T> {
/// Calls the sink's `add` or `addError` method as appropriate.
void addTo(EventSink<T> sink);

/// The value of this result, or throws the error if this is an error result.
///
/// If this is a [ValueResult], returns its value.
/// If this is an [ErrorResult], throws its error with its stack trace
/// using [Error.throwWithStackTrace].
///
/// To read the value without the risk of an exception first check [isValue]
/// or use [asValue] to get `null` instead.
T get value;

/// A future that has been completed with this result as a value or an error.
Future<T> get asFuture;
}
1 change: 1 addition & 0 deletions pkgs/async/lib/src/result/value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ part of 'result.dart';
/// A result representing a returned value.
final class ValueResult<T> implements Result<T> {
/// The result of a successful computation.
@override
final T value;

@override
Expand Down
24 changes: 24 additions & 0 deletions pkgs/async/test/result/result_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,30 @@ void main() {
);
});

group('value', () {
test('returns value for ValueResult', () {
var result = Result<int>.value(42);
expect(result.value, equals(42));
});

test('throws error for ErrorResult', () {
var result = Result<int>.error('BAD', stack);
expect(() => result.value, throwsA('BAD'));
});

test('throws error with stack trace for ErrorResult', () {
var result = Result<int>.error('BAD', stack);
// Use try/catch over throwsA to check expectations about the stack trace
try {
result.value;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't it use expect(…, throwsA(…))?

If not, maybe document why.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a good pattern for testing expectations on stack traaces.

I filed dart-lang/test#2706 to potentially add a better way in package:checks. If we end up using a getter based model instead of Condition arguments I think using a Subject<({Object error, StackTrace stackTrace})> might be a good choice

fail('Expected error to be thrown');
} catch (e, s) {
expect(e, equals('BAD'));
expect(Trace.from(s).toString(), equals(stack.toString()));
}
});
});

test('capture future value', () {
var value = Future<int>.value(42);
Result.capture(value).then(
Expand Down
Loading