From bb9371f255c808659066f6eae70dbcbb36e3f45e Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Thu, 9 Feb 2023 22:41:19 +0000 Subject: [PATCH] [analyzer] Tidy up much benchmark and integration test code: * Add a type argument to raw `Future` types (typically `Future`) * Add type arguments to raw `Map` types (typically Map`) * Add a type argument to raw `Completer` constructor calls. * Use collection-elements in more places. * Replace an implementation of `String.padLeft` and `String.padRight` with StringBuffer extension methods that use `String.padLeft` and `String.padRight`. * Rename many `sb` variables to `buffer`, which is more idiomatic. * Move some StringBuffer helper methods to be extensions on StringBuffer. * Use constructor tear-offs instead of closures which call a constructor. * Use single quotes where we can. * Do not prefix constant names with the letter 'k' [1]. * In IntegrationTestMixin: * Rename to `IntegrationTest`, as it is never used as a mixin. * Public Stream fields are converted to be getters. * Private StreamController fields are initialized at their declaration [2], instead of an initialization method. * Remove empty zero-parameter constructors. [1] https://dart.dev/guides/language/effective-dart/style#dont-use-prefix-letters [2] https://dart.dev/guides/language/effective-dart/usage#do-initialize-fields-at-their-declaration-when-possible Change-Id: I7a923a80d32f74fbecf42a0fa35ae25285994097 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/281874 Reviewed-by: Brian Wilkerson Reviewed-by: Konstantin Shcheglov Commit-Queue: Samuel Rawlins --- pkg/analysis_server/benchmark/benchmarks.dart | 35 ++- .../benchmark/integration/driver.dart | 141 +++++----- .../benchmark/integration/operation.dart | 4 +- .../benchmark/perf/benchmarks_impl.dart | 8 +- .../benchmark/perf/dart_analyze.dart | 26 +- .../perf/flutter_completion_benchmark.dart | 14 +- .../benchmark/perf/memory_tests.dart | 12 +- .../execution/delete_context_test.dart | 2 +- .../support/integration_test_methods.dart | 256 ++++++++---------- .../support/integration_tests.dart | 9 +- .../test/timing/timing_framework.dart | 16 +- .../tool/spec/codegen_inttest_methods.dart | 34 +-- 12 files changed, 241 insertions(+), 316 deletions(-) diff --git a/pkg/analysis_server/benchmark/benchmarks.dart b/pkg/analysis_server/benchmark/benchmarks.dart index eecb3c6182e..9d4aed2fbcb 100644 --- a/pkg/analysis_server/benchmark/benchmarks.dart +++ b/pkg/analysis_server/benchmark/benchmarks.dart @@ -77,9 +77,9 @@ abstract class Benchmark { bool get needsSetup => false; - Future oneTimeCleanup() => Future.value(); + Future oneTimeCleanup() => Future.value(); - Future oneTimeSetup() => Future.value(); + Future oneTimeSetup() => Future.value(); Future run({ required String dartSdkPath, @@ -87,7 +87,7 @@ abstract class Benchmark { bool verbose = false, }); - Map toJson() => + Map toJson() => {'id': id, 'description': description, 'enabled': enabled, 'kind': kind}; @override @@ -106,7 +106,7 @@ class BenchMarkResult { return BenchMarkResult(kindName, math.min(value, other.value)); } - Map toJson() => {kindName: value}; + Map toJson() => {kindName: value}; @override String toString() => '$kindName: $value'; @@ -124,35 +124,32 @@ class CompoundBenchMarkResult extends BenchMarkResult { } @override - BenchMarkResult combine(BenchMarkResult other) { + BenchMarkResult combine(covariant CompoundBenchMarkResult other) { BenchMarkResult combine(BenchMarkResult? a, BenchMarkResult? b) { if (a == null) return b!; if (b == null) return a; return a.combine(b); } - var o = other as CompoundBenchMarkResult; - var combined = CompoundBenchMarkResult(name); - var keys = ({} - ..addAll(results.keys) - ..addAll(o.results.keys)) - .toList(); + var keys = { + ...results.keys, + ...other.results.keys, + }.toList(); for (var key in keys) { - combined.add(key, combine(results[key], o.results[key])); + combined.add(key, combine(results[key], other.results[key])); } return combined; } @override - Map toJson() { - var m = {}; - for (var entry in results.entries) { - m['$name-${entry.key}'] = entry.value.toJson(); - } - return m; + Map toJson() { + return { + for (var entry in results.entries) + '$name-${entry.key}': entry.value.toJson(), + }; } @override @@ -186,7 +183,7 @@ class ListCommand extends Command { @override void run() { if (argResults!['machine'] as bool) { - var map = { + var map = { 'benchmarks': benchmarks.map((b) => b.toJson()).toList() }; print(JsonEncoder.withIndent(' ').convert(map)); diff --git a/pkg/analysis_server/benchmark/integration/driver.dart b/pkg/analysis_server/benchmark/integration/driver.dart index 5c16d36a6c3..b8b79c5e15c 100644 --- a/pkg/analysis_server/benchmark/integration/driver.dart +++ b/pkg/analysis_server/benchmark/integration/driver.dart @@ -13,28 +13,10 @@ import '../../test/integration/support/integration_test_methods.dart'; import '../../test/integration/support/integration_tests.dart'; import 'operation.dart'; -final SPACE = ' '.codeUnitAt(0); - -void _printColumn(StringBuffer sb, String text, int keyLen, - {bool rightJustified = false}) { - if (!rightJustified) { - sb.write(text); - sb.write(','); - } - for (var i = text.length; i < keyLen; ++i) { - sb.writeCharCode(SPACE); - } - if (rightJustified) { - sb.write(text); - sb.write(','); - } - sb.writeCharCode(SPACE); -} - /// [Driver] launches and manages an instance of analysis server, /// reads a stream of operations, sends requests to analysis server /// based upon those operations, and evaluates the results. -class Driver extends IntegrationTestMixin { +class Driver extends IntegrationTest { /// The amount of time to give the server to respond to a shutdown request /// before forcibly terminating it. static const Duration SHUTDOWN_TIMEOUT = Duration(seconds: 5); @@ -63,30 +45,33 @@ class Driver extends IntegrationTestMixin { Future get runComplete => _runCompleter.future; /// Perform the given operation. + /// /// Return a [Future] that completes when the next operation can be performed, /// or `null` if the next operation can be performed immediately Future? perform(Operation op) { return op.perform(this); } - /// Send a command to the server. An 'id' will be automatically assigned. - /// The returned [Future] will be completed when the server acknowledges the - /// command with a response. If the server acknowledges the command with a - /// normal (non-error) response, the future will be completed with the - /// 'result' field from the response. If the server acknowledges the command - /// with an error response, the future will be completed with an error. + /// Send a command to the server. + /// + /// An 'id' will be automatically assigned. The returned [Future] will be + /// completed when the server acknowledges the command with a response. If + /// the server acknowledges the command with a normal (non-error) response, + /// the future will be completed with the 'result' field from the response. + /// If the server acknowledges the command with an error response, the future + /// will be completed with an error. Future?> send( String method, Map params) { return server.send(method, params); } /// Launch the analysis server. + /// /// Return a [Future] that completes when analysis server has started. - Future startServer() async { + Future startServer() async { logger.log(Level.FINE, 'starting server'); - initializeInttestMixin(); server = Server(); - var serverConnected = Completer(); + var serverConnected = Completer(); onServerConnected.listen((_) { logger.log(Level.FINE, 'connected to server'); serverConnected.complete(); @@ -107,7 +92,7 @@ class Driver extends IntegrationTestMixin { } /// Shutdown the analysis server if it is running. - Future stopServer([Duration timeout = SHUTDOWN_TIMEOUT]) async { + Future stopServer([Duration timeout = SHUTDOWN_TIMEOUT]) async { if (running) { logger.log(Level.FINE, 'requesting server shutdown'); // Give the server a short time to comply with the shutdown request; if it @@ -165,19 +150,19 @@ class Measurement { var variance = differenceFromMeanSquared / count; var standardDeviation = sqrt(variance).round(); - var sb = StringBuffer(); - _printColumn(sb, tag, keyLen); - _printColumn(sb, count.toString(), 6, rightJustified: true); - _printColumn(sb, errorCount.toString(), 6, rightJustified: true); - _printColumn(sb, unexpectedResultCount.toString(), 6, rightJustified: true); - _printDuration(sb, Duration(microseconds: meanTime)); - _printDuration(sb, time90th); - _printDuration(sb, time99th); - _printDuration(sb, Duration(microseconds: standardDeviation)); - _printDuration(sb, minTime); - _printDuration(sb, maxTime); - _printDuration(sb, Duration(microseconds: totalTimeMicros)); - print(sb.toString()); + var buffer = StringBuffer(); + buffer.writePadRight(tag, keyLen); + buffer.writePadLeft(count.toString(), 6); + buffer.writePadLeft(errorCount.toString(), 6); + buffer.writePadLeft(unexpectedResultCount.toString(), 6); + buffer.writeDuration(Duration(microseconds: meanTime)); + buffer.writeDuration(time90th); + buffer.writeDuration(time99th); + buffer.writeDuration(Duration(microseconds: standardDeviation)); + buffer.writeDuration(minTime); + buffer.writeDuration(maxTime); + buffer.writeDuration(Duration(microseconds: totalTimeMicros)); + print(buffer.toString()); } void record(bool success, Duration elapsed) { @@ -190,15 +175,10 @@ class Measurement { void recordUnexpectedResults() { ++unexpectedResultCount; } - - void _printDuration(StringBuffer sb, Duration duration) { - _printColumn(sb, duration.inMilliseconds.toString(), 15, - rightJustified: true); - } } -/// [Results] contains information gathered by [Driver] -/// while running the analysis server +/// [Results] contains information gathered by [Driver] while running the +/// analysis server. class Results { Map measurements = {}; @@ -236,7 +216,7 @@ class Results { } } - /// TODO(danrubel) *** print warnings if driver caches are not empty **** + // TODO(danrubel): print warnings if driver caches are not empty. print(''' (1) uxr = UneXpected Results or responses received from the server @@ -259,31 +239,46 @@ class Results { measurements[tag]!.recordUnexpectedResults(); } - void _printGroupHeader(String groupName, int keyLen) { - var sb = StringBuffer(); - _printColumn(sb, groupName, keyLen); - _printColumn(sb, 'count', 6, rightJustified: true); - _printColumn(sb, 'error', 6, rightJustified: true); - _printColumn(sb, 'uxr(1)', 6, rightJustified: true); - sb.write(' '); - _printColumn(sb, 'mean(2)', 15); - _printColumn(sb, '90th', 15); - _printColumn(sb, '99th', 15); - _printColumn(sb, 'std-dev', 15); - _printColumn(sb, 'minimum', 15); - _printColumn(sb, 'maximum', 15); - _printColumn(sb, 'total', 15); - print(sb.toString()); + static void _printGroupHeader(String groupName, int keyLength) { + var buffer = StringBuffer(); + buffer.writePadRight(groupName, keyLength); + buffer.writePadLeft('count', 6); + buffer.writePadLeft('error', 6); + buffer.writePadLeft('uxr(1)', 6); + buffer.write(' '); + buffer.writePadRight('mean(2)', 15); + buffer.writePadRight('90th', 15); + buffer.writePadRight('99th', 15); + buffer.writePadRight('std-dev', 15); + buffer.writePadRight('minimum', 15); + buffer.writePadRight('maximum', 15); + buffer.writePadRight('total', 15); + print(buffer.toString()); } - void _printTotals(int keyLen, int totalCount, int totalErrorCount, + static void _printTotals(int keyLength, int totalCount, int totalErrorCount, int totalUnexpectedResultCount) { - var sb = StringBuffer(); - _printColumn(sb, 'Totals', keyLen); - _printColumn(sb, totalCount.toString(), 6, rightJustified: true); - _printColumn(sb, totalErrorCount.toString(), 6, rightJustified: true); - _printColumn(sb, totalUnexpectedResultCount.toString(), 6, - rightJustified: true); - print(sb.toString()); + var buffer = StringBuffer(); + buffer.writePadRight('Totals', keyLength); + buffer.writePadLeft(totalCount.toString(), 6); + buffer.writePadLeft(totalErrorCount.toString(), 6); + buffer.writePadLeft(totalUnexpectedResultCount.toString(), 6); + print(buffer.toString()); + } +} + +extension on StringBuffer { + void writeDuration(Duration duration) { + writePadLeft(duration.inMilliseconds.toString(), 15); + } + + void writePadLeft(String text, int keyLength) { + write(text.padLeft(keyLength, ' ')); + write(' '); + } + + void writePadRight(String text, int keyLength) { + write(text.padRight(keyLength, ' ')); + write(' '); } } diff --git a/pkg/analysis_server/benchmark/integration/operation.dart b/pkg/analysis_server/benchmark/integration/operation.dart index 882c15fb638..569092b4f95 100644 --- a/pkg/analysis_server/benchmark/integration/operation.dart +++ b/pkg/analysis_server/benchmark/integration/operation.dart @@ -170,14 +170,14 @@ class ResponseOperation extends Operation { class StartServerOperation extends Operation { @override - Future perform(Driver driver) { + Future perform(Driver driver) { return driver.startServer(); } } class WaitForAnalysisCompleteOperation extends Operation { @override - Future perform(Driver driver) { + Future perform(Driver driver) { var start = DateTime.now(); driver.logger.log(Level.FINE, 'waiting for analysis to complete'); late StreamSubscription subscription; diff --git a/pkg/analysis_server/benchmark/perf/benchmarks_impl.dart b/pkg/analysis_server/benchmark/perf/benchmarks_impl.dart index 48584d262d3..67b27442b39 100644 --- a/pkg/analysis_server/benchmark/perf/benchmarks_impl.dart +++ b/pkg/analysis_server/benchmark/perf/benchmarks_impl.dart @@ -76,7 +76,7 @@ class AnalysisBenchmark extends Benchmark { var completionCount = 0; var stopwatch = Stopwatch()..start(); - Future complete(int offset) async { + Future complete(int offset) async { await test.complete(filePath, offset, isWarmUp: false); completionCount++; } @@ -191,10 +191,10 @@ class ColdAnalysisBenchmark extends Benchmark { } class ServerBenchmark { - static final das = ServerBenchmark('analysis-server', 'Analysis Server', - () => AnalysisServerBenchmarkTest()); + static final das = ServerBenchmark( + 'analysis-server', 'Analysis Server', AnalysisServerBenchmarkTest.new); static final lsp = ServerBenchmark('lsp-analysis-server', - 'LSP Analysis Server', () => LspAnalysisServerBenchmarkTest()); + 'LSP Analysis Server', LspAnalysisServerBenchmarkTest.new); final String id; final String name; diff --git a/pkg/analysis_server/benchmark/perf/dart_analyze.dart b/pkg/analysis_server/benchmark/perf/dart_analyze.dart index 234e7081168..205a5815b80 100644 --- a/pkg/analysis_server/benchmark/perf/dart_analyze.dart +++ b/pkg/analysis_server/benchmark/perf/dart_analyze.dart @@ -120,15 +120,15 @@ class CmdLineSeveralProjectsBenchmark extends AbstractCmdLineBenchmark { @override List analyzeWhat(bool quick) => quick - ? ["meta"] + ? ['meta'] : [ - "analysis_server", - "analysis_server_client", - "analyzer", - "analyzer_cli", - "analyzer_plugin", - "analyzer_utilities", - "_fe_analyzer_shared", + 'analysis_server', + 'analysis_server_client', + 'analyzer', + 'analyzer_cli', + 'analyzer_plugin', + 'analyzer_utilities', + '_fe_analyzer_shared', ]; } @@ -144,7 +144,7 @@ class CmdLineSmallFileBenchmark extends AbstractCmdLineBenchmark { String get workingDir => _tempDir!.path; @override - List analyzeWhat(bool quick) => ["t.dart"]; + List analyzeWhat(bool quick) => ['t.dart']; @override void cleanup() { @@ -154,12 +154,12 @@ class CmdLineSmallFileBenchmark extends AbstractCmdLineBenchmark { @override void setup() { - var dir = Directory.systemTemp.createTempSync("analyzer-benchmark"); - var file = File.fromUri(dir.uri.resolve("t.dart")); - file.writeAsStringSync(""" + var dir = Directory.systemTemp.createTempSync('analyzer-benchmark'); + var file = File.fromUri(dir.uri.resolve('t.dart')); + file.writeAsStringSync(''' void main() { print("Hello, world!"); -}"""); +}'''); _tempDir = dir; } } diff --git a/pkg/analysis_server/benchmark/perf/flutter_completion_benchmark.dart b/pkg/analysis_server/benchmark/perf/flutter_completion_benchmark.dart index 12adde90930..7a6ea9afcf4 100644 --- a/pkg/analysis_server/benchmark/perf/flutter_completion_benchmark.dart +++ b/pkg/analysis_server/benchmark/perf/flutter_completion_benchmark.dart @@ -13,12 +13,12 @@ import 'memory_tests.dart'; class FlutterCompletionBenchmark extends Benchmark implements FlutterBenchmark { static final das = FlutterCompletionBenchmark( 'das', - () => AnalysisServerBenchmarkTest(), + AnalysisServerBenchmarkTest.new, ); static final lsp = FlutterCompletionBenchmark( 'lsp', - () => LspAnalysisServerBenchmarkTest(), + LspAnalysisServerBenchmarkTest.new, ); final AbstractBenchmarkTest Function() testConstructor; @@ -240,20 +240,20 @@ class FlutterCompletionBenchmark extends Benchmark implements FlutterBenchmark { // Perform warm-up. // The cold start does not matter. // The sustained performance is much more important. - const kWarmUpCount = 5; - for (var i = 0; i < kWarmUpCount; i++) { + const warmUpCount = 5; + for (var i = 0; i < warmUpCount; i++) { await perform(isWarmUp: true); } - const kRepeatCount = 5; + const repeatCount = 5; final timer = Stopwatch()..start(); - for (var i = 0; i < kRepeatCount; i++) { + for (var i = 0; i < repeatCount; i++) { await perform(isWarmUp: false); } await test.closeFile(filePath); - return timer.elapsedMicroseconds ~/ kRepeatCount; + return timer.elapsedMicroseconds ~/ repeatCount; } } diff --git a/pkg/analysis_server/benchmark/perf/memory_tests.dart b/pkg/analysis_server/benchmark/perf/memory_tests.dart index 2c79645e821..087746159b3 100644 --- a/pkg/analysis_server/benchmark/perf/memory_tests.dart +++ b/pkg/analysis_server/benchmark/perf/memory_tests.dart @@ -274,21 +274,21 @@ class ServiceProtocol { var id = '${++_id}'; var completer = Completer(); _completers[id] = completer; - var m = { + var messageMap = { 'jsonrpc': '2.0', 'id': id, 'method': method, - 'args': args + 'args': args, + 'params': args, }; - m['params'] = args; - var message = jsonEncode(m); + var message = jsonEncode(messageMap); socket.add(message); return completer.future; } - Future dispose() => socket.close(); + Future dispose() => socket.close(); - void _handleMessage(dynamic message) { + void _handleMessage(Object? message) { if (message is! String) { return; } diff --git a/pkg/analysis_server/test/integration/execution/delete_context_test.dart b/pkg/analysis_server/test/integration/execution/delete_context_test.dart index 138cdaf459e..54f621f30e5 100644 --- a/pkg/analysis_server/test/integration/execution/delete_context_test.dart +++ b/pkg/analysis_server/test/integration/execution/delete_context_test.dart @@ -27,7 +27,7 @@ class DeleteContextTest extends AbstractAnalysisServerIntegrationTest { await sendExecutionMapUri(contextId, uri: 'package:test/main.dart'); expect(result.file, pathname); - expect(await sendExecutionDeleteContext(contextId), isNull); + await sendExecutionDeleteContext(contextId); // After the delete, expect this to fail. try { diff --git a/pkg/analysis_server/test/integration/support/integration_test_methods.dart b/pkg/analysis_server/test/integration/support/integration_test_methods.dart index 9b0e23e35b4..b9ce0fcd0b7 100644 --- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart +++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart @@ -11,14 +11,14 @@ import 'dart:async'; import 'package:analysis_server/protocol/protocol_generated.dart'; import 'package:analysis_server/src/protocol/protocol_internal.dart'; +import 'package:analyzer_plugin/protocol/protocol_common.dart'; import 'package:test/test.dart'; import 'integration_tests.dart'; import 'protocol_matchers.dart'; -import 'package:analyzer_plugin/protocol/protocol_common.dart'; -/// Convenience methods for running integration tests. -abstract class IntegrationTestMixin { +/// Base implementation for running integration tests. +abstract class IntegrationTest { Server get server; /// Return the version number of the analysis server. @@ -39,10 +39,9 @@ abstract class IntegrationTestMixin { /// this request, but for which a response has not yet been sent, will not be /// responded to. No further responses or notifications will be sent after /// the response to this request has been sent. - Future sendServerShutdown() async { + Future sendServerShutdown() async { var result = await server.send('server.shutdown', null); outOfTestExpect(result, isNull); - return null; } /// Subscribe for services. All previous subscriptions are replaced by the @@ -57,11 +56,11 @@ abstract class IntegrationTestMixin { /// subscriptions: List /// /// A list of the services being subscribed to. - Future sendServerSetSubscriptions(List subscriptions) async { + Future sendServerSetSubscriptions( + List subscriptions) async { var params = ServerSetSubscriptionsParams(subscriptions).toJson(); var result = await server.send('server.setSubscriptions', params); outOfTestExpect(result, isNull); - return null; } /// Requests cancellation of a request sent by the client by id. This is @@ -77,11 +76,10 @@ abstract class IntegrationTestMixin { /// id: String /// /// The id of the request that should be cancelled. - Future sendServerCancelRequest(String id) async { + Future sendServerCancelRequest(String id) async { var params = ServerCancelRequestParams(id).toJson(); var result = await server.send('server.cancelRequest', params); outOfTestExpect(result, isNull); - return null; } /// Reports that the server is running. This notification is issued once @@ -99,10 +97,12 @@ abstract class IntegrationTestMixin { /// pid: int /// /// The process id of the analysis server process. - late Stream onServerConnected; + late final Stream onServerConnected = + _onServerConnected.stream.asBroadcastStream(); /// Stream controller for [onServerConnected]. - late StreamController _onServerConnected; + final _onServerConnected = + StreamController(sync: true); /// Reports that an unexpected error has occurred while executing the server. /// This notification is not used for problems with specific requests (which @@ -127,20 +127,22 @@ abstract class IntegrationTestMixin { /// /// The stack trace associated with the generation of the error, used for /// debugging the server. - late Stream onServerError; + late final Stream onServerError = + _onServerError.stream.asBroadcastStream(); /// Stream controller for [onServerError]. - late StreamController _onServerError; + final _onServerError = StreamController(sync: true); /// The stream of entries describing events happened in the server. /// /// Parameters /// /// entry: ServerLogEntry - late Stream onServerLog; + late final Stream onServerLog = + _onServerLog.stream.asBroadcastStream(); /// Stream controller for [onServerLog]. - late StreamController _onServerLog; + final _onServerLog = StreamController(sync: true); /// Reports the current status of the server. Parameters are omitted if there /// has been no change in the status represented by that parameter. @@ -163,10 +165,11 @@ abstract class IntegrationTestMixin { /// /// Note: this status type is deprecated, and is no longer sent by the /// server. - late Stream onServerStatus; + late final Stream onServerStatus = + _onServerStatus.stream.asBroadcastStream(); /// Stream controller for [onServerStatus]. - late StreamController _onServerStatus; + final _onServerStatus = StreamController(sync: true); /// Return the errors associated with the given file. If the errors for the /// given file have not yet been computed, or the most recently computed @@ -452,10 +455,9 @@ abstract class IntegrationTestMixin { /// Force re-reading of all potentially changed files, re-resolving of all /// referenced URIs, and corresponding re-analysis of everything affected in /// the current analysis roots. - Future sendAnalysisReanalyze() async { + Future sendAnalysisReanalyze() async { var result = await server.send('analysis.reanalyze', null); outOfTestExpect(result, isNull); - return null; } /// Sets the root paths used to determine which files to analyze. The set of @@ -509,7 +511,7 @@ abstract class IntegrationTestMixin { /// their package: URI's resolved using the normal pubspec.yaml mechanism. /// If this field is absent, or the empty map is specified, that indicates /// that the normal pubspec.yaml mechanism should always be used. - Future sendAnalysisSetAnalysisRoots( + Future sendAnalysisSetAnalysisRoots( List included, List excluded, {Map? packageRoots}) async { var params = AnalysisSetAnalysisRootsParams(included, excluded, @@ -517,7 +519,6 @@ abstract class IntegrationTestMixin { .toJson(); var result = await server.send('analysis.setAnalysisRoots', params); outOfTestExpect(result, isNull); - return null; } /// Subscribe for general services (that is, services that are not specific @@ -533,12 +534,11 @@ abstract class IntegrationTestMixin { /// subscriptions: List /// /// A list of the services being subscribed to. - Future sendAnalysisSetGeneralSubscriptions( + Future sendAnalysisSetGeneralSubscriptions( List subscriptions) async { var params = AnalysisSetGeneralSubscriptionsParams(subscriptions).toJson(); var result = await server.send('analysis.setGeneralSubscriptions', params); outOfTestExpect(result, isNull); - return null; } /// Set the priority files to the files in the given list. A priority file is @@ -564,11 +564,10 @@ abstract class IntegrationTestMixin { /// files: List /// /// The files that are to be a priority for analysis. - Future sendAnalysisSetPriorityFiles(List files) async { + Future sendAnalysisSetPriorityFiles(List files) async { var params = AnalysisSetPriorityFilesParams(files).toJson(); var result = await server.send('analysis.setPriorityFiles', params); outOfTestExpect(result, isNull); - return null; } /// Subscribe for services that are specific to individual files. All @@ -601,12 +600,11 @@ abstract class IntegrationTestMixin { /// /// A table mapping services to a list of the files being subscribed to the /// service. - Future sendAnalysisSetSubscriptions( + Future sendAnalysisSetSubscriptions( Map> subscriptions) async { var params = AnalysisSetSubscriptionsParams(subscriptions).toJson(); var result = await server.send('analysis.setSubscriptions', params); outOfTestExpect(result, isNull); - return null; } /// Update the content of one or more files. Files that were previously @@ -647,11 +645,10 @@ abstract class IntegrationTestMixin { /// /// The options that are to be used to control analysis. @deprecated - Future sendAnalysisUpdateOptions(AnalysisOptions options) async { + Future sendAnalysisUpdateOptions(AnalysisOptions options) async { var params = AnalysisUpdateOptionsParams(options).toJson(); var result = await server.send('analysis.updateOptions', params); outOfTestExpect(result, isNull); - return null; } /// Reports the paths of the files that are being analyzed. @@ -665,10 +662,12 @@ abstract class IntegrationTestMixin { /// directories: List /// /// A list of the paths of the files that are being analyzed. - late Stream onAnalysisAnalyzedFiles; + late final Stream onAnalysisAnalyzedFiles = + _onAnalysisAnalyzedFiles.stream.asBroadcastStream(); /// Stream controller for [onAnalysisAnalyzedFiles]. - late StreamController _onAnalysisAnalyzedFiles; + final _onAnalysisAnalyzedFiles = + StreamController(sync: true); /// Reports closing labels relevant to a given file. /// @@ -691,10 +690,12 @@ abstract class IntegrationTestMixin { /// constructor/method calls and List arguments that span multiple lines. /// Note that the ranges that are returned can overlap each other because /// they may be associated with constructs that can be nested. - late Stream onAnalysisClosingLabels; + late final Stream onAnalysisClosingLabels = + _onAnalysisClosingLabels.stream.asBroadcastStream(); /// Stream controller for [onAnalysisClosingLabels]. - late StreamController _onAnalysisClosingLabels; + final _onAnalysisClosingLabels = + StreamController(sync: true); /// Reports the errors associated with a given file. The set of errors /// included in the notification is always a complete list that supersedes @@ -709,10 +710,11 @@ abstract class IntegrationTestMixin { /// errors: List /// /// The errors contained in the file. - late Stream onAnalysisErrors; + late final Stream onAnalysisErrors = + _onAnalysisErrors.stream.asBroadcastStream(); /// Stream controller for [onAnalysisErrors]. - late StreamController _onAnalysisErrors; + final _onAnalysisErrors = StreamController(sync: true); /// Reports that any analysis results that were previously associated with /// the given files should be considered to be invalid because those files @@ -732,10 +734,12 @@ abstract class IntegrationTestMixin { /// files: List /// /// The files that are no longer being analyzed. - late Stream onAnalysisFlushResults; + late final Stream onAnalysisFlushResults = + _onAnalysisFlushResults.stream.asBroadcastStream(); /// Stream controller for [onAnalysisFlushResults]. - late StreamController _onAnalysisFlushResults; + final _onAnalysisFlushResults = + StreamController(sync: true); /// Reports the folding regions associated with a given file. Folding regions /// can be nested, but will not be overlapping. Nesting occurs when a @@ -755,10 +759,12 @@ abstract class IntegrationTestMixin { /// regions: List /// /// The folding regions contained in the file. - late Stream onAnalysisFolding; + late final Stream onAnalysisFolding = + _onAnalysisFolding.stream.asBroadcastStream(); /// Stream controller for [onAnalysisFolding]. - late StreamController _onAnalysisFolding; + final _onAnalysisFolding = + StreamController(sync: true); /// Reports the highlight regions associated with a given file. /// @@ -779,10 +785,12 @@ abstract class IntegrationTestMixin { /// some range. Note that the highlight regions that are returned can /// overlap other highlight regions if there is more than one meaning /// associated with a particular region. - late Stream onAnalysisHighlights; + late final Stream onAnalysisHighlights = + _onAnalysisHighlights.stream.asBroadcastStream(); /// Stream controller for [onAnalysisHighlights]. - late StreamController _onAnalysisHighlights; + final _onAnalysisHighlights = + StreamController(sync: true); /// Reports the classes that are implemented or extended and class members /// that are implemented or overridden in a file. @@ -804,10 +812,12 @@ abstract class IntegrationTestMixin { /// members: List /// /// The member defined in the file that are implemented or overridden. - late Stream onAnalysisImplemented; + late final Stream onAnalysisImplemented = + _onAnalysisImplemented.stream.asBroadcastStream(); /// Stream controller for [onAnalysisImplemented]. - late StreamController _onAnalysisImplemented; + final _onAnalysisImplemented = + StreamController(sync: true); /// Reports that the navigation information associated with a region of a /// single file has become invalid and should be re-requested. @@ -835,10 +845,12 @@ abstract class IntegrationTestMixin { /// The delta to be applied to the offsets in information that follows the /// invalidated region in order to update it so that it doesn't need to be /// re-requested. - late Stream onAnalysisInvalidate; + late final Stream onAnalysisInvalidate = + _onAnalysisInvalidate.stream.asBroadcastStream(); /// Stream controller for [onAnalysisInvalidate]. - late StreamController _onAnalysisInvalidate; + final _onAnalysisInvalidate = + StreamController(sync: true); /// Reports the navigation targets associated with a given file. /// @@ -871,10 +883,12 @@ abstract class IntegrationTestMixin { /// /// The files containing navigation targets referenced in the file. They /// are referenced by NavigationTargets by their index in this array. - late Stream onAnalysisNavigation; + late final Stream onAnalysisNavigation = + _onAnalysisNavigation.stream.asBroadcastStream(); /// Stream controller for [onAnalysisNavigation]. - late StreamController _onAnalysisNavigation; + final _onAnalysisNavigation = + StreamController(sync: true); /// Reports the occurrences of references to elements within a single file. /// @@ -891,10 +905,12 @@ abstract class IntegrationTestMixin { /// occurrences: List /// /// The occurrences of references to elements within the file. - late Stream onAnalysisOccurrences; + late final Stream onAnalysisOccurrences = + _onAnalysisOccurrences.stream.asBroadcastStream(); /// Stream controller for [onAnalysisOccurrences]. - late StreamController _onAnalysisOccurrences; + final _onAnalysisOccurrences = + StreamController(sync: true); /// Reports the outline associated with a single file. /// @@ -923,10 +939,12 @@ abstract class IntegrationTestMixin { /// outline: Outline /// /// The outline associated with the file. - late Stream onAnalysisOutline; + late final Stream onAnalysisOutline = + _onAnalysisOutline.stream.asBroadcastStream(); /// Stream controller for [onAnalysisOutline]. - late StreamController _onAnalysisOutline; + final _onAnalysisOutline = + StreamController(sync: true); /// Reports the overriding members in a file. /// @@ -943,10 +961,12 @@ abstract class IntegrationTestMixin { /// overrides: List /// /// The overrides associated with the file. - late Stream onAnalysisOverrides; + late final Stream onAnalysisOverrides = + _onAnalysisOverrides.stream.asBroadcastStream(); /// Stream controller for [onAnalysisOverrides]. - late StreamController _onAnalysisOverrides; + final _onAnalysisOverrides = + StreamController(sync: true); /// Request that completion suggestions for the given offset in the given /// file be returned. @@ -1062,12 +1082,11 @@ abstract class IntegrationTestMixin { /// subscriptions: List /// /// A list of the services being subscribed to. - Future sendCompletionSetSubscriptions( + Future sendCompletionSetSubscriptions( List subscriptions) async { var params = CompletionSetSubscriptionsParams(subscriptions).toJson(); var result = await server.send('completion.setSubscriptions', params); outOfTestExpect(result, isNull); - return null; } /// The client can make this request to express interest in certain libraries @@ -1087,11 +1106,11 @@ abstract class IntegrationTestMixin { /// suggestions. If one configured path is beneath another, the descendant /// will override the ancestors' configured libraries of interest. @deprecated - Future sendCompletionRegisterLibraryPaths(List paths) async { + Future sendCompletionRegisterLibraryPaths( + List paths) async { var params = CompletionRegisterLibraryPathsParams(paths).toJson(); var result = await server.send('completion.registerLibraryPaths', params); outOfTestExpect(result, isNull); - return null; } /// Clients must make this request when the user has selected a completion @@ -1267,10 +1286,12 @@ abstract class IntegrationTestMixin { /// /// If an AvailableSuggestion has relevance tags that match more than one /// IncludedSuggestionRelevanceTag, the maximum relevance boost is used. - late Stream onCompletionResults; + late final Stream onCompletionResults = + _onCompletionResults.stream.asBroadcastStream(); /// Stream controller for [onCompletionResults]. - late StreamController _onCompletionResults; + final _onCompletionResults = + StreamController(sync: true); /// Reports the pre-computed, candidate completions from symbols defined in a /// corresponding library. This notification may be sent multiple times. When @@ -1290,12 +1311,13 @@ abstract class IntegrationTestMixin { /// removedLibraries: List (optional) /// /// A list of library ids that no longer apply. - late Stream - onCompletionAvailableSuggestions; + late final Stream + onCompletionAvailableSuggestions = + _onCompletionAvailableSuggestions.stream.asBroadcastStream(); /// Stream controller for [onCompletionAvailableSuggestions]. - late StreamController - _onCompletionAvailableSuggestions; + final _onCompletionAvailableSuggestions = + StreamController(sync: true); /// Reports existing imports in a library. This notification may be sent /// multiple times for a library. When a notification is processed, clients @@ -1310,11 +1332,13 @@ abstract class IntegrationTestMixin { /// imports: ExistingImports /// /// The existing imports in the library. - late Stream onCompletionExistingImports; + late final Stream + onCompletionExistingImports = + _onCompletionExistingImports.stream.asBroadcastStream(); /// Stream controller for [onCompletionExistingImports]. - late StreamController - _onCompletionExistingImports; + final _onCompletionExistingImports = + StreamController(sync: true); /// Perform a search for references to the element defined or referenced at /// the given offset in the given file. @@ -1548,10 +1572,11 @@ abstract class IntegrationTestMixin { /// /// True if this is that last set of results that will be returned for the /// indicated search. - late Stream onSearchResults; + late final Stream onSearchResults = + _onSearchResults.stream.asBroadcastStream(); /// Stream controller for [onSearchResults]. - late StreamController _onSearchResults; + final _onSearchResults = StreamController(sync: true); /// Format the contents of a single file. The currently selected region of /// text is passed in so that the selection can be preserved across the @@ -2141,11 +2166,10 @@ abstract class IntegrationTestMixin { /// id: ExecutionContextId /// /// The identifier of the execution context that is to be deleted. - Future sendExecutionDeleteContext(String id) async { + Future sendExecutionDeleteContext(String id) async { var params = ExecutionDeleteContextParams(id).toJson(); var result = await server.send('execution.deleteContext', params); outOfTestExpect(result, isNull); - return null; } /// Request completion suggestions for the given runtime context. @@ -2306,12 +2330,11 @@ abstract class IntegrationTestMixin { /// /// A list of the services being subscribed to. @deprecated - Future sendExecutionSetSubscriptions( + Future sendExecutionSetSubscriptions( List subscriptions) async { var params = ExecutionSetSubscriptionsParams(subscriptions).toJson(); var result = await server.send('execution.setSubscriptions', params); outOfTestExpect(result, isNull); - return null; } /// Reports information needed to allow a single file to be launched. @@ -2336,10 +2359,12 @@ abstract class IntegrationTestMixin { /// /// A list of the Dart files that are referenced by the file. This field is /// omitted if the file is not an HTML file. - late Stream onExecutionLaunchData; + late final Stream onExecutionLaunchData = + _onExecutionLaunchData.stream.asBroadcastStream(); /// Stream controller for [onExecutionLaunchData]. - late StreamController _onExecutionLaunchData; + final _onExecutionLaunchData = + StreamController(sync: true); /// Return server diagnostics. /// @@ -2407,11 +2432,10 @@ abstract class IntegrationTestMixin { /// value: bool /// /// Enable or disable analytics. - Future sendAnalyticsEnable(bool value) async { + Future sendAnalyticsEnable(bool value) async { var params = AnalyticsEnableParams(value).toJson(); var result = await server.send('analytics.enable', params); outOfTestExpect(result, isNull); - return null; } /// Send information about client events. @@ -2432,11 +2456,10 @@ abstract class IntegrationTestMixin { /// action: String /// /// The value used to indicate which action was performed. - Future sendAnalyticsSendEvent(String action) async { + Future sendAnalyticsSendEvent(String action) async { var params = AnalyticsSendEventParams(action).toJson(); var result = await server.send('analytics.sendEvent', params); outOfTestExpect(result, isNull); - return null; } /// Send timing information for client events (e.g. code completions). @@ -2460,11 +2483,10 @@ abstract class IntegrationTestMixin { /// millis: int /// /// The duration of the event in milliseconds. - Future sendAnalyticsSendTiming(String event, int millis) async { + Future sendAnalyticsSendTiming(String event, int millis) async { var params = AnalyticsSendTimingParams(event, millis).toJson(); var result = await server.send('analytics.sendTiming', params); outOfTestExpect(result, isNull); - return null; } /// Return the description of the widget instance at the given location. @@ -2578,12 +2600,11 @@ abstract class IntegrationTestMixin { /// /// A table mapping services to a list of the files being subscribed to the /// service. - Future sendFlutterSetSubscriptions( + Future sendFlutterSetSubscriptions( Map> subscriptions) async { var params = FlutterSetSubscriptionsParams(subscriptions).toJson(); var result = await server.send('flutter.setSubscriptions', params); outOfTestExpect(result, isNull); - return null; } /// Reports the Flutter outline associated with a single file. @@ -2601,76 +2622,11 @@ abstract class IntegrationTestMixin { /// outline: FlutterOutline /// /// The outline associated with the file. - late Stream onFlutterOutline; + late final Stream onFlutterOutline = + _onFlutterOutline.stream.asBroadcastStream(); /// Stream controller for [onFlutterOutline]. - late StreamController _onFlutterOutline; - - /// Initialize the fields in InttestMixin, and ensure that notifications will - /// be handled. - void initializeInttestMixin() { - _onServerConnected = StreamController(sync: true); - onServerConnected = _onServerConnected.stream.asBroadcastStream(); - _onServerError = StreamController(sync: true); - onServerError = _onServerError.stream.asBroadcastStream(); - _onServerLog = StreamController(sync: true); - onServerLog = _onServerLog.stream.asBroadcastStream(); - _onServerStatus = StreamController(sync: true); - onServerStatus = _onServerStatus.stream.asBroadcastStream(); - _onAnalysisAnalyzedFiles = - StreamController(sync: true); - onAnalysisAnalyzedFiles = - _onAnalysisAnalyzedFiles.stream.asBroadcastStream(); - _onAnalysisClosingLabels = - StreamController(sync: true); - onAnalysisClosingLabels = - _onAnalysisClosingLabels.stream.asBroadcastStream(); - _onAnalysisErrors = StreamController(sync: true); - onAnalysisErrors = _onAnalysisErrors.stream.asBroadcastStream(); - _onAnalysisFlushResults = - StreamController(sync: true); - onAnalysisFlushResults = _onAnalysisFlushResults.stream.asBroadcastStream(); - _onAnalysisFolding = StreamController(sync: true); - onAnalysisFolding = _onAnalysisFolding.stream.asBroadcastStream(); - _onAnalysisHighlights = - StreamController(sync: true); - onAnalysisHighlights = _onAnalysisHighlights.stream.asBroadcastStream(); - _onAnalysisImplemented = - StreamController(sync: true); - onAnalysisImplemented = _onAnalysisImplemented.stream.asBroadcastStream(); - _onAnalysisInvalidate = - StreamController(sync: true); - onAnalysisInvalidate = _onAnalysisInvalidate.stream.asBroadcastStream(); - _onAnalysisNavigation = - StreamController(sync: true); - onAnalysisNavigation = _onAnalysisNavigation.stream.asBroadcastStream(); - _onAnalysisOccurrences = - StreamController(sync: true); - onAnalysisOccurrences = _onAnalysisOccurrences.stream.asBroadcastStream(); - _onAnalysisOutline = StreamController(sync: true); - onAnalysisOutline = _onAnalysisOutline.stream.asBroadcastStream(); - _onAnalysisOverrides = - StreamController(sync: true); - onAnalysisOverrides = _onAnalysisOverrides.stream.asBroadcastStream(); - _onCompletionResults = - StreamController(sync: true); - onCompletionResults = _onCompletionResults.stream.asBroadcastStream(); - _onCompletionAvailableSuggestions = - StreamController(sync: true); - onCompletionAvailableSuggestions = - _onCompletionAvailableSuggestions.stream.asBroadcastStream(); - _onCompletionExistingImports = - StreamController(sync: true); - onCompletionExistingImports = - _onCompletionExistingImports.stream.asBroadcastStream(); - _onSearchResults = StreamController(sync: true); - onSearchResults = _onSearchResults.stream.asBroadcastStream(); - _onExecutionLaunchData = - StreamController(sync: true); - onExecutionLaunchData = _onExecutionLaunchData.stream.asBroadcastStream(); - _onFlutterOutline = StreamController(sync: true); - onFlutterOutline = _onFlutterOutline.stream.asBroadcastStream(); - } + final _onFlutterOutline = StreamController(sync: true); /// Dispatch the notification named [event], and containing parameters /// [params], to the appropriate stream. diff --git a/pkg/analysis_server/test/integration/support/integration_tests.dart b/pkg/analysis_server/test/integration/support/integration_tests.dart index 607aeb3b22f..f45b3e110bf 100644 --- a/pkg/analysis_server/test/integration/support/integration_tests.dart +++ b/pkg/analysis_server/test/integration/support/integration_tests.dart @@ -79,8 +79,7 @@ typedef MismatchDescriber = Description Function( typedef NotificationProcessor = void Function(String event, Map params); /// Base class for analysis server integration tests. -abstract class AbstractAnalysisServerIntegrationTest - extends IntegrationTestMixin { +abstract class AbstractAnalysisServerIntegrationTest extends IntegrationTest { /// Amount of time to give the server to respond to a shutdown request before /// forcibly terminating it. static const Duration SHUTDOWN_TIMEOUT = Duration(seconds: 60); @@ -110,10 +109,6 @@ abstract class AbstractAnalysisServerIntegrationTest String dartSdkPath = path.dirname(path.dirname(Platform.resolvedExecutable)); - AbstractAnalysisServerIntegrationTest() { - initializeInttestMixin(); - } - /// Return a future which will complete when a 'server.status' notification is /// received from the server with 'analyzing' set to false. /// @@ -609,7 +604,7 @@ class Server { /// Start the server. If [profileServer] is `true`, the server will be started /// with "--observe" and "--pause-isolates-on-exit", allowing the observatory /// to be used. - Future start({ + Future start({ required String dartSdkPath, int? diagnosticPort, String? instrumentationLogFile, diff --git a/pkg/analysis_server/test/timing/timing_framework.dart b/pkg/analysis_server/test/timing/timing_framework.dart index 07f7aded21c..7b8a548c49f 100644 --- a/pkg/analysis_server/test/timing/timing_framework.dart +++ b/pkg/analysis_server/test/timing/timing_framework.dart @@ -96,7 +96,7 @@ class TimingResult { /// The abstract class [TimingTest] defines the behavior of objects that measure /// the time required to perform some sequence of server operations. -abstract class TimingTest extends IntegrationTestMixin { +abstract class TimingTest extends IntegrationTest { /// The number of times the test will be performed in order to warm up the VM. static final int DEFAULT_WARMUP_COUNT = 10; @@ -125,9 +125,6 @@ abstract class TimingTest extends IntegrationTestMixin { /// shutdown. bool skipShutdown = false; - /// Initialize a newly created test. - TimingTest(); - /// Return the number of iterations that should be performed in order to /// compute a time. int get timingCount => DEFAULT_TIMING_COUNT; @@ -138,11 +135,10 @@ abstract class TimingTest extends IntegrationTestMixin { /// Perform any operations that need to be performed once before any /// iterations. - Future oneTimeSetUp() { - initializeInttestMixin(); + Future oneTimeSetUp() { server = Server(); sourceDirectory = Directory.systemTemp.createTempSync('analysisServer'); - var serverConnected = Completer(); + var serverConnected = Completer(); onServerConnected.listen((_) { serverConnected.complete(); }); @@ -159,7 +155,7 @@ abstract class TimingTest extends IntegrationTestMixin { /// Perform any operations that need to be performed once after all /// iterations. - Future oneTimeTearDown() { + Future oneTimeTearDown() { return _shutdownIfNeeded().then((_) { sourceDirectory.deleteSync(recursive: true); }); @@ -213,7 +209,7 @@ abstract class TimingTest extends IntegrationTestMixin { /// Repeatedly execute this test [count] times, adding timing information to /// the given list of [times] if it is non-`null`. - Future _repeat(int count, List? times) { + Future _repeat(int count, List? times) { var stopwatch = Stopwatch(); return setUp().then((_) { stopwatch.start(); @@ -234,7 +230,7 @@ abstract class TimingTest extends IntegrationTestMixin { } /// Shut the server down unless [skipShutdown] is `true`. - Future _shutdownIfNeeded() { + Future _shutdownIfNeeded() { if (skipShutdown) { return Future.value(); } diff --git a/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart b/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart index 5864cb21be9..dfd35d995aa 100644 --- a/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart +++ b/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart @@ -90,32 +90,22 @@ class CodegenInttestMethodsVisitor extends DartCodegenVisitor writeln("import 'package:$packageName/protocol/protocol_generated.dart';"); writeln( "import 'package:$packageName/src/protocol/protocol_internal.dart';"); - writeln("import 'package:test/test.dart';"); - writeln(); - writeln("import 'integration_tests.dart';"); - writeln("import 'protocol_matchers.dart';"); for (var uri in api.types.importUris) { write("import '"); write(uri); writeln("';"); } + writeln("import 'package:test/test.dart';"); writeln(); - writeln('/// Convenience methods for running integration tests.'); - writeln('abstract class IntegrationTestMixin {'); + writeln("import 'integration_tests.dart';"); + writeln("import 'protocol_matchers.dart';"); + writeln(); + writeln('/// Base implementation for running integration tests.'); + writeln('abstract class IntegrationTest {'); indent(() { writeln('Server get server;'); super.visitApi(); writeln(); - docComment(toHtmlVisitor.collectHtml(() { - toHtmlVisitor.writeln('Initialize the fields in InttestMixin, and'); - toHtmlVisitor.writeln('ensure that notifications will be handled.'); - })); - writeln('void initializeInttestMixin() {'); - indent(() { - write(fieldInitializationCode.join()); - }); - writeln('}'); - writeln(); docComment(toHtmlVisitor.collectHtml(() { toHtmlVisitor.writeln('Dispatch the notification named [event], and'); toHtmlVisitor.writeln('containing parameters [params], to the'); @@ -151,16 +141,13 @@ class CodegenInttestMethodsVisitor extends DartCodegenVisitor toHtmlVisitor.translateHtml(notification.html); toHtmlVisitor.describePayload(notification.params, 'Parameters'); })); - writeln('late Stream<$className> $streamName;'); + writeln('late final Stream<$className> $streamName = ' + '_$streamName.stream.asBroadcastStream();'); writeln(); docComment(toHtmlVisitor.collectHtml(() { toHtmlVisitor.write('Stream controller for [$streamName].'); })); - writeln('late StreamController<$className> _$streamName;'); - fieldInitializationCode.add(collectCode(() { - writeln('_$streamName = StreamController<$className>(sync: true);'); - writeln('$streamName = _$streamName.stream.asBroadcastStream();'); - })); + writeln('final _$streamName = StreamController<$className>(sync: true);'); notificationSwitchContents.add(collectCode(() { writeln("case '${notification.longEvent}':"); indent(() { @@ -215,7 +202,7 @@ class CodegenInttestMethodsVisitor extends DartCodegenVisitor doCapitalize: true); futureClass = 'Future<$resultClass>'; } else { - futureClass = 'Future'; + futureClass = 'Future'; } writeln('$futureClass $methodName(${args.join(', ')}) async {'); @@ -249,7 +236,6 @@ class CodegenInttestMethodsVisitor extends DartCodegenVisitor writeln("return $resultClass.fromJson(decoder, 'result', result);"); } else { writeln('outOfTestExpect(result, isNull);'); - writeln('return null;'); } }); writeln('}');