@@ -6,14 +6,21 @@ import 'dart:async';
66import 'dart:convert' ;
77import 'dart:io' ;
88
9+ import 'package:analyzer/dart/element/element.dart' ;
10+ import 'package:analyzer/file_system/file_system.dart' show ResourceProvider;
911import 'package:analyzer/file_system/memory_file_system.dart' ;
1012import 'package:analyzer/file_system/physical_file_system.dart' ;
13+ import 'package:analyzer/source/line_info.dart' ;
1114import 'package:analyzer/src/test_utilities/mock_sdk.dart' as mock_sdk;
1215import 'package:args/args.dart' ;
1316import 'package:cli_util/cli_logging.dart' ;
1417import 'package:http/http.dart' as http;
1518import 'package:meta/meta.dart' ;
19+ import 'package:nnbd_migration/instrumentation.dart' ;
1620import 'package:nnbd_migration/migration_cli.dart' ;
21+ import 'package:nnbd_migration/src/front_end/dartfix_listener.dart' ;
22+ import 'package:nnbd_migration/src/front_end/instrumentation_listener.dart' ;
23+ import 'package:nnbd_migration/src/front_end/migration_summary.dart' ;
1724import 'package:nnbd_migration/src/front_end/non_nullable_fix.dart' ;
1825import 'package:nnbd_migration/src/front_end/web/edit_details.dart' ;
1926import 'package:nnbd_migration/src/front_end/web/file_details.dart' ;
@@ -29,10 +36,54 @@ main() {
2936 });
3037}
3138
39+ /// Specialization of [InstrumentationListener] that generates artificial
40+ /// exceptions, so that we can test they are properly propagated to top level.
41+ class _ExceptionGeneratingInstrumentationListener
42+ extends InstrumentationListener {
43+ _ExceptionGeneratingInstrumentationListener (
44+ {MigrationSummary migrationSummary})
45+ : super (migrationSummary: migrationSummary);
46+
47+ @override
48+ void externalDecoratedType (Element element, DecoratedTypeInfo decoratedType) {
49+ if (element.name == 'print' ) {
50+ throw StateError ('Artificial exception triggered' );
51+ }
52+ super .externalDecoratedType (element, decoratedType);
53+ }
54+ }
55+
56+ /// Specialization of [NonNullableFix] that generates artificial exceptions, so
57+ /// that we can test they are properly propagated to top level.
58+ class _ExceptionGeneratingNonNullableFix extends NonNullableFix {
59+ _ExceptionGeneratingNonNullableFix (DartFixListener listener,
60+ ResourceProvider resourceProvider, LineInfo Function (String ) getLineInfo,
61+ {List <String > included = const < String > [],
62+ int preferredPort,
63+ bool enablePreview = true ,
64+ String summaryPath})
65+ : super (listener, resourceProvider, getLineInfo,
66+ included: included,
67+ preferredPort: preferredPort,
68+ enablePreview: enablePreview,
69+ summaryPath: summaryPath);
70+
71+ @override
72+ InstrumentationListener createInstrumentationListener (
73+ {MigrationSummary migrationSummary}) =>
74+ _ExceptionGeneratingInstrumentationListener (
75+ migrationSummary: migrationSummary);
76+ }
77+
3278class _MigrationCli extends MigrationCli {
79+ /// If `true` , then an artifical exception should be generated when migration
80+ /// encounters a reference to the `print` function.
81+ final bool injectArtificialException;
82+
3383 Future <void > Function () _runWhilePreviewServerActive;
3484
35- _MigrationCli (_MigrationCliTestBase test)
85+ _MigrationCli (_MigrationCliTestBase test,
86+ {this .injectArtificialException = false })
3687 : super (
3788 binaryName: 'nnbd_migration' ,
3889 loggerFactory: (isVerbose) => test.logger = _TestLogger (isVerbose),
@@ -50,6 +101,29 @@ class _MigrationCli extends MigrationCli {
50101 _runWhilePreviewServerActive = null ;
51102 }
52103
104+ @override
105+ NonNullableFix createNonNullableFix (DartFixListener listener,
106+ ResourceProvider resourceProvider, LineInfo getLineInfo (String path),
107+ {List <String > included = const < String > [],
108+ int preferredPort,
109+ bool enablePreview = true ,
110+ String summaryPath}) {
111+ if (injectArtificialException) {
112+ return _ExceptionGeneratingNonNullableFix (
113+ listener, resourceProvider, getLineInfo,
114+ included: included,
115+ preferredPort: preferredPort,
116+ enablePreview: enablePreview,
117+ summaryPath: summaryPath);
118+ } else {
119+ return super .createNonNullableFix (listener, resourceProvider, getLineInfo,
120+ included: included,
121+ preferredPort: preferredPort,
122+ enablePreview: enablePreview,
123+ summaryPath: summaryPath);
124+ }
125+ }
126+
53127 Future <void > runWithPreviewServer (
54128 ArgResults argResults, Future <void > callback ()) async {
55129 _runWhilePreviewServerActive = callback;
@@ -362,6 +436,16 @@ int${migrated ? '?' : ''} f() => null;
362436 assertProjectContents (projectDir, simpleProject (migrated: true ));
363437 }
364438
439+ test_lifecycle_exception_handling () async {
440+ var projectContents = simpleProject (sourceText: 'main() { print(0); }' );
441+ var projectDir = await createProjectDir (projectContents);
442+ var cli = _createCli (injectArtificialException: true );
443+ expect (
444+ () async => runWithPreviewServer (cli, [projectDir], (url) async {}),
445+ throwsA (TypeMatcher <Error >().having ((e) => e.toString (), 'toString' ,
446+ contains ('Artificial exception triggered' ))));
447+ }
448+
365449 test_lifecycle_ignore_errors_disable () async {
366450 var projectContents = simpleProject (sourceText: '''
367451int f() => null
@@ -1334,9 +1418,10 @@ name: test
13341418 headers: {'Content-Type' : 'application/json; charset=UTF-8' });
13351419 }
13361420
1337- _MigrationCli _createCli () {
1421+ _MigrationCli _createCli ({ bool injectArtificialException = false } ) {
13381422 mock_sdk.MockSdk (resourceProvider: resourceProvider);
1339- return _MigrationCli (this );
1423+ return _MigrationCli (this ,
1424+ injectArtificialException: injectArtificialException);
13401425 }
13411426
13421427 Future <String > _getHelpText ({@required bool verbose}) async {
0 commit comments