Line data Source code
1 : // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 : // for details. All rights reserved. Use of this source code is governed by a 3 : // BSD-style license that can be found in the LICENSE file. 4 : 5 : import 'package:matcher/matcher.dart'; 6 : import 'package:test_api/hooks.dart'; 7 : 8 : import 'async_matcher.dart'; 9 : import 'util/pretty_print.dart'; 10 : 11 : /// This function is deprecated. 12 : /// 13 : /// Use [throwsA] instead. We strongly recommend that you add assertions about 14 : /// at least the type of the error, but you can write `throwsA(anything)` to 15 : /// mimic the behavior of this matcher. 16 : @Deprecated('Will be removed in 0.13.0') 17 : const Matcher throws = Throws(); 18 : 19 : /// This can be used to match three kinds of objects: 20 : /// 21 : /// * A [Function] that throws an exception when called. The function cannot 22 : /// take any arguments. If you want to test that a function expecting 23 : /// arguments throws, wrap it in another zero-argument function that calls 24 : /// the one you want to test. 25 : /// 26 : /// * A [Future] that completes with an exception. Note that this creates an 27 : /// asynchronous expectation. The call to `expect()` that includes this will 28 : /// return immediately and execution will continue. Later, when the future 29 : /// completes, the actual expectation will run. 30 : /// 31 : /// * A [Function] that returns a [Future] that completes with an exception. 32 : /// 33 : /// In all three cases, when an exception is thrown, this will test that the 34 : /// exception object matches [matcher]. If [matcher] is not an instance of 35 : /// [Matcher], it will implicitly be treated as `equals(matcher)`. 36 : /// 37 : /// Examples: 38 : /// ```dart 39 : /// void functionThatThrows() => throw SomeException(); 40 : /// 41 : /// void functionWithArgument(bool shouldThrow) { 42 : /// if (shouldThrow) { 43 : /// throw SomeException(); 44 : /// } 45 : /// } 46 : /// 47 : /// Future<void> asyncFunctionThatThrows() async => throw SomeException(); 48 : /// 49 : /// expect(functionThatThrows, throwsA(isA<SomeException>())); 50 : /// 51 : /// expect(() => functionWithArgument(true), throwsA(isA<SomeException>())); 52 : /// 53 : /// var future = asyncFunctionThatThrows(); 54 : /// await expectLater(future, throwsA(isA<SomeException>())); 55 : /// 56 : /// await expectLater( 57 : /// asyncFunctionThatThrows, throwsA(isA<SomeException>())); 58 : /// ``` 59 15 : Matcher throwsA(matcher) => Throws(wrapMatcher(matcher)); 60 : 61 : /// Use the [throwsA] function instead. 62 : @Deprecated('Will be removed in 0.13.0') 63 : class Throws extends AsyncMatcher { 64 : final Matcher? _matcher; 65 : 66 27 : const Throws([Matcher? matcher]) : _matcher = matcher; 67 : 68 : // Avoid async/await so we synchronously fail if we match a synchronous 69 : // function. 70 5 : @override 71 : dynamic /*FutureOr<String>*/ matchAsync(item) { 72 10 : if (item is! Function && item is! Future) { 73 : return 'was not a Function or Future'; 74 : } 75 : 76 5 : if (item is Future) { 77 5 : return _matchFuture(item, 'emitted '); 78 : } 79 : 80 : try { 81 0 : var value = item(); 82 0 : if (value is Future) { 83 0 : return _matchFuture(value, 'returned a Future that emitted '); 84 : } 85 : 86 0 : return indent(prettyPrint(value), first: 'returned '); 87 : } catch (error, trace) { 88 0 : return _check(error, trace); 89 : } 90 : } 91 : 92 : /// Matches [future], using try/catch since `onError` doesn't seem to work 93 : /// properly in nnbd. 94 5 : Future<String?> _matchFuture( 95 : Future<dynamic> future, String messagePrefix) async { 96 : try { 97 5 : var value = await future; 98 0 : return indent(prettyPrint(value), first: messagePrefix); 99 : } catch (error, trace) { 100 5 : return _check(error, trace); 101 : } 102 : } 103 : 104 0 : @override 105 : Description describe(Description description) { 106 0 : if (_matcher == null) { 107 0 : return description.add('throws'); 108 : } else { 109 0 : return description.add('throws ').addDescriptionOf(_matcher); 110 : } 111 : } 112 : 113 : /// Verifies that [error] matches [_matcher] and returns a [String] 114 : /// description of the failure if it doesn't. 115 5 : String? _check(error, StackTrace? trace) { 116 5 : if (_matcher == null) return null; 117 : 118 5 : var matchState = {}; 119 10 : if (_matcher!.matches(error, matchState)) return null; 120 : 121 0 : var result = _matcher! 122 0 : .describeMismatch(error, StringDescription(), matchState, false) 123 0 : .toString(); 124 : 125 0 : var buffer = StringBuffer(); 126 0 : buffer.writeln(indent(prettyPrint(error), first: 'threw ')); 127 : if (trace != null) { 128 0 : buffer.writeln(indent( 129 0 : TestHandle.current.formatStackTrace(trace).toString(), 130 : first: 'stack ')); 131 : } 132 0 : if (result.isNotEmpty) buffer.writeln(indent(result, first: 'which ')); 133 0 : return buffer.toString().trimRight(); 134 : } 135 : }