| // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | import 'dart:async'; | 
 |  | 
 | import 'package:analysis_server/protocol/protocol.dart'; | 
 | import 'package:analysis_server/protocol/protocol_constants.dart'; | 
 | import 'package:analysis_server/protocol/protocol_generated.dart'; | 
 | import 'package:analysis_server/src/analysis_server.dart'; | 
 | import 'package:analyzer/file_system/file_system.dart'; | 
 | import 'package:analyzer/src/test_utilities/package_config_file_builder.dart'; | 
 | import 'package:analyzer/src/util/file_paths.dart' as file_paths; | 
 | import 'package:analyzer/src/utilities/extensions/file_system.dart'; | 
 | import 'package:analyzer_plugin/protocol/protocol_common.dart'; | 
 | import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin; | 
 | import 'package:collection/collection.dart'; | 
 | import 'package:test/test.dart'; | 
 | import 'package:test_reflective_loader/test_reflective_loader.dart'; | 
 |  | 
 | import 'analysis_server_base.dart'; | 
 | import 'mocks.dart'; | 
 | import 'utils/tree_string_sink.dart'; | 
 |  | 
 | void main() { | 
 |   defineReflectiveSuite(() { | 
 |     defineReflectiveTests(AnalysisDomainBlazeTest); | 
 |     defineReflectiveTests(AnalysisDomainPubTest); | 
 |     defineReflectiveTests(SetSubscriptionsTest); | 
 |   }); | 
 | } | 
 |  | 
 | @reflectiveTest | 
 | class AnalysisDomainBlazeTest extends _AnalysisDomainTest { | 
 |   String get myPackageLibPath => '$myPackageRootPath/lib'; | 
 |  | 
 |   String get myPackageRootPath => '$workspaceRootPath/dart/my'; | 
 |  | 
 |   String get myPackageTestFilePath => '$myPackageLibPath/test.dart'; | 
 |  | 
 |   @override | 
 |   void setUp() { | 
 |     super.setUp(); | 
 |     newFile('$workspaceRootPath/${file_paths.blazeWorkspaceMarker}', ''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_changeFile_buildFile_legacy() async { | 
 |     // Make it a Blaze package. | 
 |     newBlazeBuildFile(myPackageRootPath, r''' | 
 | # foo | 
 | '''); | 
 |  | 
 |     newFile(myPackageTestFilePath, ''' | 
 | void f(int? a) {} | 
 | '''); | 
 |  | 
 |     await setRoots(included: [myPackageRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // No errors after initial analysis. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/dart/my/lib/test.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     // Change BUILD file, nothing interesting. | 
 |     newBlazeBuildFile(myPackageRootPath, r''' | 
 | # bar | 
 | '''); | 
 |  | 
 |     await pumpEventQueue(times: 5000); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // BUILD file change caused rebuilding analysis contexts. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/dart/my/lib/test.dart | 
 | AnalysisErrors | 
 |   file: /home/dart/my/lib/test.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 | } | 
 |  | 
 | @reflectiveTest | 
 | class AnalysisDomainPubTest extends _AnalysisDomainTest { | 
 |   Future<void> test_fileSystem_addFile_analysisOptions() async { | 
 |     deleteTestPackageAnalysisOptionsFile(); | 
 |  | 
 |     _createFilesWithErrors([ | 
 |       '$testPackageLibPath/a.dart', | 
 |       '$testPackageLibPath/b.dart', | 
 |     ]); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // Both a.dart and b.dart are analyzed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Write the options file that excludes b.dart | 
 |     newAnalysisOptionsYamlFile(testPackageRootPath, r''' | 
 | analyzer: | 
 |   exclude: | 
 |     - lib/b.dart | 
 | '''); | 
 |  | 
 |     await pumpEventQueue(times: 5000); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // Errors for all files were flushed, b.dart is not reported. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/lib/a.dart | 
 |   /home/test/lib/b.dart | 
 |   /home/test/pubspec.yaml | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_addFile_analysisOptions_analysis() async { | 
 |     deleteTestPackageAnalysisOptionsFile(); | 
 |     _createFilesWithErrors([ | 
 |       '$testPackageLibPath/a.dart', | 
 |     ]); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // a.dart was analyzed | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Add 'analysis_options.yaml' that has an error. | 
 |     newAnalysisOptionsYamlFile(testPackageRootPath, ''' | 
 | analyzer: | 
 |   error: | 
 | '''); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // Both files were analyzed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/lib/a.dart | 
 |   /home/test/pubspec.yaml | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_addFile_androidManifestXml() async { | 
 |     newAnalysisOptionsYamlFile(testPackageRootPath, ''' | 
 | analyzer: | 
 |   optional-checks: | 
 |     chrome-os-manifest-checks: true | 
 | '''); | 
 |  | 
 |     newFile('$testPackageLibPath/a.dart', ''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     newFile('$testPackageRootPath/AndroidManifest.xml', '<manifest/>'); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // No touch-screen. | 
 |     // TODO(scheglov): Why duplicate analysis? | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/AndroidManifest.xml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/AndroidManifest.xml | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_addFile_dart() async { | 
 |     // We have to create the folder, otherwise there is nothing to watch. | 
 |     newFolder(testPackageLibPath); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We don't have a.dart yet. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     _createFilesWithErrors([ | 
 |       '$testPackageLibPath/a.dart', | 
 |     ]); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We created a.dart, so it should be analyzed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_addFile_dart_dotFolder() async { | 
 |     var a_path = '$testPackageLibPath/.foo/a.dart'; | 
 |     var b_path = '$testPackageLibPath/b.dart'; | 
 |  | 
 |     newFile(b_path, r''' | 
 | import '.foo/a.dart'; | 
 | void f(A a) {} | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We don't have a.dart, so the import cannot be resolved. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     newFile(a_path, r''' | 
 | class A {} | 
 | '''); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // 'a.dart' is in a dot-folder, so excluded from analysis. | 
 |     // We added a.dart with `A`, so no errors. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_addFile_dart_excluded() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var b_path = '$testPackageLibPath/b.dart'; | 
 |  | 
 |     newAnalysisOptionsYamlFile(testPackageRootPath, r''' | 
 | analyzer: | 
 |   exclude: | 
 |     - "**/a.dart" | 
 | '''); | 
 |  | 
 |     newFile(b_path, r''' | 
 | import 'a.dart'; | 
 | void f(A a) {} | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We don't have a.dart, so the import cannot be resolved. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     newFile(a_path, r''' | 
 | class A {} | 
 | '''); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We excluded 'a.dart' from analysis, no errors notification for it. | 
 |     // We added a.dart with `A`, so no errors. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_addFile_fixDataFolderYaml() async { | 
 |     var path = '$testPackageLibPath/fix_data/foo.yaml'; | 
 |  | 
 |     newFile('$testPackageLibPath/a.dart', ''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // No `fix_data.yaml` to analyze yet. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     // Create it, will be analyzed. | 
 |     newFile(path, '0: 1'); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // And it has errors. | 
 |     // We don't recreate analysis contexts. | 
 |     // TODO(scheglov): Why duplicate analysis? | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data/foo.yaml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data/foo.yaml | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_addFile_fixDataYaml() async { | 
 |     var path = '$testPackageLibPath/fix_data.yaml'; | 
 |  | 
 |     newFile('$testPackageLibPath/a.dart', ''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // No `fix_data.yaml` to analyze yet. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     // Create it, will be analyzed. | 
 |     newFile(path, '0: 1'); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // And it has errors. | 
 |     // We don't recreate analysis contexts. | 
 |     // TODO(scheglov): Why duplicate analysis? | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data.yaml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data.yaml | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_addFile_packageConfigJsonFile() async { | 
 |     var aaaRootPath = '/packages/aaa'; | 
 |     var a_path = '$aaaRootPath/lib/a.dart'; | 
 |  | 
 |     newFile(a_path, ''' | 
 | class A {} | 
 | '''); | 
 |  | 
 |     newFile(testFilePath, ''' | 
 | import 'package:aaa/a.dart'; | 
 | void f(A a) {} | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We cannot resolve `package:aaa/a.dart` | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Write `package_config.json`, recreate analysis contexts. | 
 |     writeTestPackageConfig( | 
 |       config: PackageConfigFileBuilder() | 
 |         ..add(name: 'aaa', rootPath: aaaRootPath), | 
 |     ); | 
 |  | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We rebuilt analysis contexts. | 
 |     // We have `A` in 'package:aaa/a.dart', so no errors. | 
 |     // Errors are not reported for packages. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/analysis_options.yaml | 
 |   /home/test/lib/test.dart | 
 |   /home/test/pubspec.yaml | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_addFile_pubspec_analysis() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var pubspec_path = '$testPackageRootPath/pubspec.yaml'; | 
 |  | 
 |     newFile(a_path, 'error'); | 
 |  | 
 |     // Write an empty file to force a new analysis context. | 
 |     // We look for `pubspec.yaml` files only in analysis context roots. | 
 |     newAnalysisOptionsYamlFile(testPackageRootPath, ''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // a.dart was analyzed | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Add a non-Dart file that we know how to analyze. | 
 |     newFile(pubspec_path, ''' | 
 | name: sample | 
 | dependencies: true | 
 | '''); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We rebuilt analysis contexts. | 
 |     // All files were analyzed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/analysis_options.yaml | 
 |   /home/test/lib/a.dart | 
 |   /home/test/pubspec.yaml | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_addFile_unrelated() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var unrelated_path = '$testPackageRootPath/unrelated.txt'; | 
 |  | 
 |     newFile(a_path, 'error'); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // a.dart was analyzed | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Add an unrelated file, no analysis. | 
 |     newFile(unrelated_path, 'anything'); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // No analysis. | 
 |     assertNotificationsText(r''' | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_changeFile_analysisOptions() async { | 
 |     var options_path = '$testPackageRootPath/analysis_options.yaml'; | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var b_path = '$testPackageLibPath/b.dart'; | 
 |     var c_path = '$testPackageLibPath/c.dart'; | 
 |  | 
 |     _createFilesWithErrors([a_path, b_path, c_path]); | 
 |  | 
 |     // Exclude b.dart from analysis. | 
 |     newFile(options_path, r''' | 
 | analyzer: | 
 |   exclude: | 
 |     - lib/b.dart | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // Only a.dart and c.dart are analyzed, because b.dart is excluded. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/c.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Exclude c.dart from analysis. | 
 |     newFile(options_path, r''' | 
 | analyzer: | 
 |   exclude: | 
 |     - lib/c.dart | 
 | '''); | 
 |  | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // Analysis contexts were rebuilt. | 
 |     // Only a.dart and b.dart analyzed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/analysis_options.yaml | 
 |   /home/test/lib/a.dart | 
 |   /home/test/lib/c.dart | 
 |   /home/test/pubspec.yaml | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_changeFile_androidManifestXml() async { | 
 |     var path = '$testPackageRootPath/AndroidManifest.xml'; | 
 |  | 
 |     newFile('$testPackageLibPath/a.dart', ''); | 
 |  | 
 |     // Has an error - no touch screen. | 
 |     newFile(path, '<manifest/>'); | 
 |  | 
 |     newAnalysisOptionsYamlFile(testPackageRootPath, ''' | 
 | analyzer: | 
 |   optional-checks: | 
 |     chrome-os-manifest-checks: true | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/AndroidManifest.xml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     // Update the file, so analyze it. | 
 |     newFile(path, '<manifest/>'); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // An error was reported. | 
 |     // TODO(scheglov): Why duplicate analysis? | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/AndroidManifest.xml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/AndroidManifest.xml | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_changeFile_dart() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var b_path = '$testPackageLibPath/b.dart'; | 
 |  | 
 |     newFile(a_path, r''' | 
 | class A2 {} | 
 | '''); | 
 |  | 
 |     newFile(b_path, r''' | 
 | import 'a.dart'; | 
 | void f(A a) {} | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Update a.dart so that b.dart has no error. | 
 |     newFile(a_path, 'class A {}'); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // The update of a.dart fixed the error in b.dart | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_changeFile_dart_dotFolder() async { | 
 |     var a_path = '$testPackageLibPath/.foo/a.dart'; | 
 |     var b_path = '$testPackageLibPath/b.dart'; | 
 |  | 
 |     newFile(a_path, r''' | 
 | class B {} | 
 | '''); | 
 |  | 
 |     newFile(b_path, r''' | 
 | import '.foo/a.dart'; | 
 | void f(A a) {} | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // 'a.dart' is in a dot-folder, so excluded from analysis. | 
 |     // We have `B`, not `A`, in a.dart, so has errors. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     newFile(a_path, r''' | 
 | class A {} | 
 | '''); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // 'a.dart' is in a dot-folder, so excluded from analysis. | 
 |     // We changed a.dart, to have `A`, so no errors. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_changeFile_dart_excluded() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var b_path = '$testPackageLibPath/b.dart'; | 
 |  | 
 |     newAnalysisOptionsYamlFile(testPackageRootPath, r''' | 
 | analyzer: | 
 |   exclude: | 
 |     - "**/a.dart" | 
 | '''); | 
 |  | 
 |     newFile(a_path, r''' | 
 | class B {} | 
 | '''); | 
 |  | 
 |     newFile(b_path, r''' | 
 | import 'a.dart'; | 
 | void f(A a) {} | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We excluded 'a.dart' from analysis, no errors notification for it. | 
 |     // We have `B`, not `A`, in a.dart, so has errors. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     newFile(a_path, r''' | 
 | class A {} | 
 | '''); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We changed a.dart, to have `A`, so no errors. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_changeFile_fixDataFolderYaml() async { | 
 |     var path = '$testPackageLibPath/fix_data/foo.yaml'; | 
 |  | 
 |     newFile('$testPackageLibPath/a.dart', ''); | 
 |  | 
 |     // This file has an error. | 
 |     newFile(path, '0: 1'); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // The file was analyzed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data/foo.yaml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     // Replace with the content that does not have errors. | 
 |     newFile(path, r''' | 
 | version: 1 | 
 | transforms: [] | 
 | '''); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // No errors in `foo.yaml` anymore. | 
 |     // We don't recreate analysis contexts. | 
 |     // TODO(scheglov): Why duplicate analysis? | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data/foo.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data/foo.yaml | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_changeFile_fixDataYaml() async { | 
 |     var path = '$testPackageLibPath/fix_data.yaml'; | 
 |  | 
 |     newFile('$testPackageLibPath/a.dart', ''); | 
 |  | 
 |     // This file has an error. | 
 |     newFile(path, '0: 1'); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // The file was analyzed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data.yaml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     // Replace with the content that does not have errors. | 
 |     newFile(path, r''' | 
 | version: 1 | 
 | transforms: [] | 
 | '''); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // No errors in `fix_data.yaml` anymore. | 
 |     // We don't recreate analysis contexts. | 
 |     // TODO(scheglov): Why duplicate analysis? | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data.yaml | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_changeFile_hasOverlay_removeOverlay() async { | 
 |     newFile(testFilePath, ''); | 
 |  | 
 |     // Add an overlay without errors. | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         testFile.path: AddContentOverlay(''), | 
 |       }).toRequest('0'), | 
 |     ); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |  | 
 |     // The test file (overlay) is analyzed, no errors. | 
 |     await _waitAnalysisComplete(); | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     // Change the file, has errors. | 
 |     newFile(testFilePath, 'error'); | 
 |  | 
 |     // But the overlay is still present, so the file is not analyzed. | 
 |     await _waitAnalysisComplete(); | 
 |     assertNotificationsText(r''' | 
 | '''); | 
 |  | 
 |     // Remove the overlay, now the file will be read. | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         testFile.path: RemoveContentOverlay(), | 
 |       }).toRequest('0'), | 
 |     ); | 
 |  | 
 |     // The file has errors. | 
 |     await _waitAnalysisComplete(); | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_changeFile_packageConfigJsonFile() async { | 
 |     var aaaRootPath = '/packages/aaa'; | 
 |     var a_path = '$aaaRootPath/lib/a.dart'; | 
 |  | 
 |     newFile(a_path, ''' | 
 | class A {} | 
 | '''); | 
 |  | 
 |     newFile(testFilePath, ''' | 
 | import 'package:aaa/a.dart'; | 
 | void f(A a) {} | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // The default `package_config.json` is without `package:aaa`. | 
 |     // We cannot resolve `package:aaa/a.dart` | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Write `package_config.json`, recreate analysis contexts. | 
 |     writeTestPackageConfig( | 
 |       config: PackageConfigFileBuilder() | 
 |         ..add(name: 'aaa', rootPath: aaaRootPath), | 
 |     ); | 
 |  | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We have `A` in 'package:aaa/a.dart', so no errors. | 
 |     // Errors are not reported for packages. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/analysis_options.yaml | 
 |   /home/test/lib/test.dart | 
 |   /home/test/pubspec.yaml | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_deleteFile_analysisOptions() async { | 
 |     var options_path = '$testPackageRootPath/analysis_options.yaml'; | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var b_path = '$testPackageLibPath/b.dart'; | 
 |  | 
 |     _createFilesWithErrors([a_path, b_path]); | 
 |  | 
 |     // Exclude b.dart from analysis. | 
 |     newFile(options_path, r''' | 
 | analyzer: | 
 |   exclude: | 
 |     - lib/b.dart | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // Only a.dart is analyzed, because b.dart is excluded. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Delete the options file. | 
 |     deleteFile(options_path); | 
 |  | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // Errors for a.dart were flushed, a.dart and b.dart analyzed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/analysis_options.yaml | 
 |   /home/test/lib/a.dart | 
 |   /home/test/pubspec.yaml | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_deleteFile_androidManifestXml() async { | 
 |     var path = '$testPackageRootPath/AndroidManifest.xml'; | 
 |  | 
 |     newFile('$testPackageLibPath/a.dart', ''); | 
 |  | 
 |     // Has an error - no touch screen. | 
 |     newFile(path, '<manifest/>'); | 
 |  | 
 |     newAnalysisOptionsYamlFile(testPackageRootPath, ''' | 
 | analyzer: | 
 |   optional-checks: | 
 |     chrome-os-manifest-checks: true | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // An error was reported. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/AndroidManifest.xml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     // Delete the file. | 
 |     deleteFile(path); | 
 |     await pumpEventQueue(); | 
 |  | 
 |     // We received a flush notification. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/AndroidManifest.xml | 
 | '''); | 
 |   } | 
 |  | 
 |   /// Tests that deleting and re-creating a file while an overlay is active | 
 |   /// keeps the diagnotics when the overlay is then removed, then removes them | 
 |   /// when the file is deleted. | 
 |   /// | 
 |   /// https://github.com/dart-lang/sdk/issues/53475 | 
 |   Future<void> test_fileSystem_deleteFile_createFile_withOverlay_dart() async { | 
 |     var a_path = convertPath('$testPackageLibPath/a.dart'); | 
 |  | 
 |     _createFilesWithErrors([a_path]); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // Initial file has errors. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Set the overlay, with a different content. | 
 |     // We get another notification with errors. | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         a_path: AddContentOverlay('error2'), | 
 |       }).toRequest('0'), | 
 |     ); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Delete the file, we have the overlay, so no notifications. | 
 |     deleteFile(a_path); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | '''); | 
 |  | 
 |     // Re-creating the file, we have the overlay, so no notifications. | 
 |     _createFilesWithErrors([a_path]); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | '''); | 
 |  | 
 |     // Remove the overlay, the file has different content, so notification. | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         a_path: RemoveContentOverlay(), | 
 |       }).toRequest('1'), | 
 |     ); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Delete the file, errors are now gone. | 
 |     deleteFile(a_path); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/lib/a.dart | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_deleteFile_dart() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |  | 
 |     _createFilesWithErrors([a_path]); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // a.dart was analyzed | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     deleteFile(a_path); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We deleted a.dart, its errors should be flushed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/lib/a.dart | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_deleteFile_dart_excluded() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var b_path = '$testPackageLibPath/b.dart'; | 
 |  | 
 |     newAnalysisOptionsYamlFile(testPackageRootPath, r''' | 
 | analyzer: | 
 |   exclude: | 
 |     - "**/a.dart" | 
 | '''); | 
 |  | 
 |     newFile(a_path, r''' | 
 | class A {} | 
 | '''); | 
 |  | 
 |     newFile(b_path, r''' | 
 | import 'a.dart'; | 
 | void f(A a) {} | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We excluded 'a.dart' from analysis, no errors notification for it. | 
 |     // We have `A` in a.dart, so no errors. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     deleteFile(a_path); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We deleted a.dart, so `A` cannot be resolved. | 
 |     // TODO(scheglov): Should we get flush for a.dart also? | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_deleteFile_fixDataYaml() async { | 
 |     var path = '$testPackageLibPath/fix_data.yaml'; | 
 |  | 
 |     newFile('$testPackageLibPath/a.dart', ''); | 
 |  | 
 |     // This file has an error. | 
 |     newFile(path, '0: 1'); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // The file was analyzed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data.yaml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     // Delete the file. | 
 |     deleteFile(path); | 
 |     await pumpEventQueue(); | 
 |  | 
 |     // We received a flush notification. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/lib/fix_data.yaml | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_fileSystem_deleteFile_packageConfigJsonFile() async { | 
 |     var aaaRootPath = '/packages/aaa'; | 
 |     var a_path = '$aaaRootPath/lib/a.dart'; | 
 |  | 
 |     newFile(a_path, ''' | 
 | class A {} | 
 | '''); | 
 |  | 
 |     // Write the empty file, without `package:aaa`. | 
 |     writeTestPackageConfig( | 
 |       config: PackageConfigFileBuilder() | 
 |         ..add(name: 'aaa', rootPath: aaaRootPath), | 
 |     ); | 
 |  | 
 |     newFile(testFilePath, ''' | 
 | import 'package:aaa/a.dart'; | 
 | void f(A a) {} | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We have `A` in 'package:aaa/a.dart', so no errors. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: empty | 
 | '''); | 
 |  | 
 |     // Delete `package_config.json`, recreate analysis contexts. | 
 |     deleteFile( | 
 |       '$testPackageRootPath/.dart_tool/package_config.json', | 
 |     ); | 
 |  | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We cannot resolve 'package:aaa/a.dart', so errors. | 
 |     // Errors are not reported for packages. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/analysis_options.yaml | 
 |   /home/test/lib/test.dart | 
 |   /home/test/pubspec.yaml | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   /// Tests that deleting a file does not clear diagnostics if there's still | 
 |   /// an active overlay for the file. | 
 |   /// | 
 |   /// https://github.com/dart-lang/sdk/issues/53475 | 
 |   Future<void> test_fileSystem_deleteFile_withOverlay_dart() async { | 
 |     var a_path = convertPath('$testPackageLibPath/a.dart'); | 
 |  | 
 |     _createFilesWithErrors([a_path]); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // Initial file has errors. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Set overlay with different content, with errors. | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         a_path: AddContentOverlay('error2'), | 
 |       }).toRequest('0'), | 
 |     ); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Delete file, has the overlay, no notifications. | 
 |     deleteFile(a_path); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | '''); | 
 |  | 
 |     // After removing the overlay, errors are gone. | 
 |     // TODO(scheglov): why not flush? | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         a_path: RemoveContentOverlay(), | 
 |       }).toRequest('1'), | 
 |     ); | 
 |     await pumpEventQueue(); | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setPriorityFiles() async { | 
 |     var a = getFile('$workspaceRootPath/foo/lib/a.dart'); | 
 |     var b = getFile('$workspaceRootPath/foo/lib/b.dart'); | 
 |     var c = getFile('$workspaceRootPath/bar/lib/c.dart'); | 
 |     var d = getFile('$workspaceRootPath/bar/lib/d.dart'); | 
 |  | 
 |     a.writeAsStringSync(''); | 
 |     b.writeAsStringSync(''); | 
 |     c.writeAsStringSync(''); | 
 |     d.writeAsStringSync(''); | 
 |  | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisSetPriorityFilesParams( | 
 |         [a.path, c.path], | 
 |       ).toRequest('0'), | 
 |     ); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // a.dart and c.dart are priority files. | 
 |     // So, they are analyzed before b.dart and d.dart | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/foo/lib/a.dart | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/bar/lib/c.dart | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/foo/lib/b.dart | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/bar/lib/d.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setPriorityFiles_notAbsolute() async { | 
 |     var response = await handleRequest( | 
 |       AnalysisSetPriorityFilesParams( | 
 |         ['a.dart'], | 
 |       ).toRequest('0'), | 
 |     ); | 
 |  | 
 |     expect( | 
 |       response, | 
 |       isResponseFailure( | 
 |         '0', | 
 |         RequestErrorCode.INVALID_FILE_PATH_FORMAT, | 
 |       ), | 
 |     ); | 
 |   } | 
 |  | 
 |   Future<void> test_setPriorityFiles_withoutRoots() async { | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisSetPriorityFilesParams( | 
 |         [convertPath('$testPackageLibPath/a.dart')], | 
 |       ).toRequest('0'), | 
 |     ); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_excluded_notAbsolute() async { | 
 |     var response = await handleRequest( | 
 |       AnalysisSetAnalysisRootsParams( | 
 |         [workspaceRootPath], | 
 |         ['foo'], | 
 |         packageRoots: {}, | 
 |       ).toRequest('0'), | 
 |     ); | 
 |  | 
 |     expect( | 
 |       response, | 
 |       isResponseFailure( | 
 |         '0', | 
 |         RequestErrorCode.INVALID_FILE_PATH_FORMAT, | 
 |       ), | 
 |     ); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_excluded_notNormalized() async { | 
 |     var response = await handleRequest( | 
 |       AnalysisSetAnalysisRootsParams( | 
 |         [workspaceRootPath], | 
 |         [convertPath('/foo/../bar')], | 
 |         packageRoots: {}, | 
 |       ).toRequest('0'), | 
 |     ); | 
 |  | 
 |     expect( | 
 |       response, | 
 |       isResponseFailure( | 
 |         '0', | 
 |         RequestErrorCode.INVALID_FILE_PATH_FORMAT, | 
 |       ), | 
 |     ); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_included_notAbsolute() async { | 
 |     var response = await handleRequest( | 
 |       AnalysisSetAnalysisRootsParams( | 
 |         ['foo'], | 
 |         [], | 
 |         packageRoots: {}, | 
 |       ).toRequest('0'), | 
 |     ); | 
 |  | 
 |     expect( | 
 |       response, | 
 |       isResponseFailure( | 
 |         '0', | 
 |         RequestErrorCode.INVALID_FILE_PATH_FORMAT, | 
 |       ), | 
 |     ); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_included_notNormalized() async { | 
 |     var response = await handleRequest( | 
 |       AnalysisSetAnalysisRootsParams( | 
 |         [convertPath('/foo/../bar')], | 
 |         [], | 
 |         packageRoots: {}, | 
 |       ).toRequest('0'), | 
 |     ); | 
 |  | 
 |     expect( | 
 |       response, | 
 |       isResponseFailure( | 
 |         '0', | 
 |         RequestErrorCode.INVALID_FILE_PATH_FORMAT, | 
 |       ), | 
 |     ); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_includedFile() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var b_path = '$testPackageLibPath/b.dart'; | 
 |  | 
 |     _createFilesWithErrors([a_path, b_path]); | 
 |  | 
 |     await setRoots(included: [a_path], excluded: []); | 
 |  | 
 |     // Only a.dart is included, so b.dart is not analyzed. | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_includedFile_setRoots() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var b_path = '$testPackageLibPath/b.dart'; | 
 |  | 
 |     _createFilesWithErrors([a_path, b_path]); | 
 |  | 
 |     // Include only single file. | 
 |     await setRoots(included: [a_path], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // So, only a.dart is analyzed, and b.dart is not. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Include the folder that contains both a.dart and b.dart | 
 |     await setRoots(included: [testPackageRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // So, both a.dart and b.dart are analyzed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisFlush | 
 |   /home/test/lib/a.dart | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/b.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_includedFileFolder() async { | 
 |     var includedFile = '$testPackageLibPath/a.dart'; | 
 |     var includedFolder = '$testPackageLibPath/foo'; | 
 |     var includedFolderFile1 = '$includedFolder/1.dart'; | 
 |     var includedFolderFile2 = '$includedFolder/2.dart'; | 
 |     var notIncludedFile = '$testPackageLibPath/b.dart'; | 
 |  | 
 |     _createFilesWithErrors([ | 
 |       includedFile, | 
 |       includedFolderFile1, | 
 |       includedFolderFile2, | 
 |       notIncludedFile, | 
 |     ]); | 
 |  | 
 |     await setRoots(included: [includedFile, includedFolder], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We can combine a file, and a folder as included paths. | 
 |     // And the file that is not in there is not analyzed. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/foo/1.dart | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/foo/2.dart | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_includedFolder_analysisOptions_exclude() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var b_path = '$testPackageLibPath/b.dart'; | 
 |  | 
 |     newAnalysisOptionsYamlFile(testPackageRootPath, ''' | 
 | analyzer: | 
 |   exclude: | 
 |     - "**/b.dart" | 
 | '''); | 
 |  | 
 |     _createFilesWithErrors([a_path, b_path]); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |  | 
 |     // b.dart is excluded using the options file. | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   @FailingTest(reason: 'Not implemented in ContextLocator') | 
 |   Future<void> test_setRoots_includedFolder_excludedFile() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var excluded_path = '$testPackageRootPath/excluded/b.dart'; | 
 |  | 
 |     _createFilesWithErrors([a_path, excluded_path]); | 
 |  | 
 |     await setRoots( | 
 |       included: [workspaceRootPath], | 
 |       excluded: [excluded_path], | 
 |     ); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     fail('Not implemented'); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_includedFolder_excludedFolder() async { | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var excluded_path = '$testPackageRootPath/excluded/b.dart'; | 
 |  | 
 |     _createFilesWithErrors([a_path, excluded_path]); | 
 |  | 
 |     await setRoots( | 
 |       included: [workspaceRootPath], | 
 |       excluded: ['$testPackageRootPath/excluded'], | 
 |     ); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // a.dart is analyzed, but b.dart is in the excluded folder. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_includedFolder_notExisting() async { | 
 |     var existingFolder_path = '$testPackageLibPath/exiting'; | 
 |     var notExistingFolder_path = '$testPackageLibPath/notExisting'; | 
 |     var existingFile_path = '$existingFolder_path/1.dart'; | 
 |  | 
 |     _createFilesWithErrors([ | 
 |       existingFile_path, | 
 |     ]); | 
 |  | 
 |     await setRoots(included: [ | 
 |       existingFolder_path, | 
 |       notExistingFolder_path, | 
 |     ], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // The not existing root does not prevent analysis of the existing one. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/exiting/1.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_notDartFile_analysisOptions_excluded() async { | 
 |     deleteTestPackageAnalysisOptionsFile(); | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var options_path = '$testPackageRootPath/analysis_options.yaml'; | 
 |  | 
 |     newFile(a_path, 'error'); | 
 |  | 
 |     // 'analysis_options.yaml' that has an error and excludes itself. | 
 |     newFile(options_path, ''' | 
 | analyzer: | 
 |   exclude: | 
 |     - analysis_options.yaml | 
 |   error: | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_notDartFile_androidManifestXml() async { | 
 |     var path = '$testPackageRootPath/AndroidManifest.xml'; | 
 |  | 
 |     newFile('$testPackageLibPath/a.dart', ''); | 
 |  | 
 |     newAnalysisOptionsYamlFile(testPackageRootPath, ''' | 
 | analyzer: | 
 |   optional-checks: | 
 |     chrome-os-manifest-checks: true | 
 | '''); | 
 |  | 
 |     newFile(path, '<manifest/>'); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |  | 
 |     // No touch-screen. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/AndroidManifest.xml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_notDartFile_fixDataYaml() async { | 
 |     var path = '$testPackageLibPath/fix_data.yaml'; | 
 |  | 
 |     // `lib/fix_data.yaml` will be analyzed. | 
 |     newFile(path, '0: 1'); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |  | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data.yaml | 
 |   errors: notEmpty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_notDartFile_fixDataYaml_empty() async { | 
 |     var path = '$testPackageLibPath/fix_data.yaml'; | 
 |     newFile(path, ''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |  | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_notDartFile_fixDataYaml_onlyComments() async { | 
 |     var path = '$testPackageLibPath/fix_data.yaml'; | 
 |     newFile(path, '# one\n#two'); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |  | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/fix_data.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_notDartFile_pubspec_excluded() async { | 
 |     deleteTestPackageAnalysisOptionsFile(); | 
 |     var a_path = '$testPackageLibPath/a.dart'; | 
 |     var options_path = '$testPackageRootPath/analysis_options.yaml'; | 
 |  | 
 |     newFile(a_path, 'error'); | 
 |  | 
 |     writeTestPackagePubspecYamlFile(''' | 
 | name: | 
 |   - error | 
 | '''); | 
 |  | 
 |     // 'analysis_options.yaml' that excludes pubspec.yaml. | 
 |     newFile(options_path, ''' | 
 | analyzer: | 
 |   exclude: | 
 |     - pubspec.yaml | 
 | '''); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // No pubspec.yaml | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/a.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_setRoots_packageConfigJsonFile() async { | 
 |     var aaaRootPath = '/packages/aaa'; | 
 |     var a_path = '$aaaRootPath/lib/a.dart'; | 
 |  | 
 |     newFile(a_path, ''' | 
 | class A {} | 
 | '''); | 
 |  | 
 |     writeTestPackageConfig( | 
 |       config: PackageConfigFileBuilder() | 
 |         ..add(name: 'aaa', rootPath: aaaRootPath), | 
 |     ); | 
 |  | 
 |     newFile(testFilePath, ''' | 
 | import 'package:aaa/a.dart'; | 
 | void f(A a) {} | 
 | '''); | 
 |  | 
 |     // create project and wait for analysis | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     // We have `A` in 'package:aaa/a.dart', so no errors. | 
 |     // Errors are not reported for packages. | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_updateContent_addOverlay() async { | 
 |     newFile(testFilePath, 'error'); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |  | 
 |     // The file in the file system has errors. | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Add an overlay without errors. | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         testFile.path: AddContentOverlay(''), | 
 |       }).toRequest('0'), | 
 |     ); | 
 |  | 
 |     // A new errors notification was received, no errors. | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_updateContent_changeOverlay() async { | 
 |     newFile(testFilePath, ''); | 
 |  | 
 |     // Add the content with an error. | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         testFile.path: AddContentOverlay('var v = 0'), | 
 |       }).toRequest('0'), | 
 |     ); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |  | 
 |     // The overlay has an error. | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/analysis_options.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/pubspec.yaml | 
 |   errors: empty | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: notEmpty | 
 | '''); | 
 |  | 
 |     // Add the missing `;`. | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         testFile.path: ChangeContentOverlay([ | 
 |           SourceEdit(9, 0, ';'), | 
 |         ]), | 
 |       }).toRequest('0'), | 
 |     ); | 
 |  | 
 |     // A new errors notification was received, no errors. | 
 |     await server.onAnalysisComplete; | 
 |     assertNotificationsText(r''' | 
 | AnalysisErrors | 
 |   file: /home/test/lib/test.dart | 
 |   errors: empty | 
 | '''); | 
 |   } | 
 |  | 
 |   Future<void> test_updateContent_notAbsolute() async { | 
 |     var response = await handleRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         'a.dart': AddContentOverlay(''), | 
 |       }).toRequest('0'), | 
 |     ); | 
 |     expect(response, isResponseFailure('0')); | 
 |   } | 
 |  | 
 |   Future<void> test_updateContent_outOfRange_beyondEnd() { | 
 |     return _updateContent_outOfRange('012', SourceEdit(0, 5, 'foo')); | 
 |   } | 
 |  | 
 |   Future<void> test_updateContent_outOfRange_negativeLength() { | 
 |     return _updateContent_outOfRange('', SourceEdit(3, -1, 'foo')); | 
 |   } | 
 |  | 
 |   Future<void> test_updateContent_outOfRange_negativeOffset() { | 
 |     return _updateContent_outOfRange('', SourceEdit(-1, 3, 'foo')); | 
 |   } | 
 |  | 
 |   Future<void> _updateContent_outOfRange( | 
 |     String initialContent, | 
 |     SourceEdit edit, | 
 |   ) async { | 
 |     newFile(testFilePath, initialContent); | 
 |  | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |     await server.onAnalysisComplete; | 
 |  | 
 |     await handleSuccessfulRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         testFile.path: AddContentOverlay(initialContent), | 
 |       }).toRequest('0'), | 
 |     ); | 
 |  | 
 |     var response = await handleRequest( | 
 |       AnalysisUpdateContentParams({ | 
 |         testFile.path: ChangeContentOverlay([edit]), | 
 |       }).toRequest('0'), | 
 |     ); | 
 |  | 
 |     expect( | 
 |       response, | 
 |       isResponseFailure( | 
 |         '0', | 
 |         RequestErrorCode.INVALID_OVERLAY_CHANGE, | 
 |       ), | 
 |     ); | 
 |   } | 
 |  | 
 |   /// Pump the event queue, so that watch events are processed. | 
 |   /// Wait for analysis to complete. | 
 |   /// Repeat a few times, eventually there will be no work to do. | 
 |   Future<void> _waitAnalysisComplete() async { | 
 |     for (var i = 0; i < 128; i++) { | 
 |       await pumpEventQueue(); | 
 |       await server.onAnalysisComplete; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | @reflectiveTest | 
 | class SetSubscriptionsTest extends PubPackageAnalysisServerTest { | 
 |   Map<File, List<HighlightRegion>> filesHighlights = {}; | 
 |  | 
 |   final Completer<void> _resultsAvailable = Completer(); | 
 |  | 
 |   @override | 
 |   void processNotification(Notification notification) { | 
 |     super.processNotification(notification); | 
 |     if (notification.event == ANALYSIS_NOTIFICATION_HIGHLIGHTS) { | 
 |       var params = AnalysisHighlightsParams.fromNotification(notification); | 
 |       filesHighlights[getFile(params.file)] = params.regions; | 
 |       _resultsAvailable.complete(); | 
 |     } | 
 |   } | 
 |  | 
 |   @override | 
 |   Future<void> setUp() async { | 
 |     super.setUp(); | 
 |     await setRoots(included: [workspaceRootPath], excluded: []); | 
 |   } | 
 |  | 
 |   Future<void> test_afterAnalysis() async { | 
 |     addTestFile('int V = 42;'); | 
 |     // wait for analysis, no results initially | 
 |     await waitForTasksFinished(); | 
 |     expect(filesHighlights[testFile], isNull); | 
 |     // subscribe | 
 |     await addAnalysisSubscription(AnalysisService.HIGHLIGHTS, testFile); | 
 |     await _resultsAvailable.future; | 
 |     // there are results | 
 |     expect(filesHighlights[testFile], isNotEmpty); | 
 |   } | 
 |  | 
 |   Future<void> test_afterAnalysis_noSuchFile() async { | 
 |     var file = getFile('/no-such-file.dart'); | 
 |     addTestFile('// no matter'); | 
 |     // wait for analysis, no results initially | 
 |     await waitForTasksFinished(); | 
 |     expect(filesHighlights[testFile], isNull); | 
 |     // subscribe | 
 |     await addAnalysisSubscription(AnalysisService.HIGHLIGHTS, file); | 
 |     await _resultsAvailable.future; | 
 |     // there are results | 
 |     expect(filesHighlights[file], isEmpty); | 
 |   } | 
 |  | 
 |   Future<void> test_afterAnalysis_packageFile_external() async { | 
 |     var pkgFile = newFile('/packages/pkgA/lib/libA.dart', ''' | 
 | library lib_a; | 
 | class A {} | 
 | '''); | 
 |     writePackageConfig( | 
 |       convertPath('/project'), | 
 |       config: (PackageConfigFileBuilder() | 
 |         ..add(name: 'pkgA', rootPath: convertPath('/packages/pkgA'))), | 
 |     ); | 
 |     // | 
 |     addTestFile(''' | 
 | import 'package:pkgA/libA.dart'; | 
 | void f() { | 
 |   new A(); | 
 | } | 
 | '''); | 
 |     // wait for analysis, no results initially | 
 |     await waitForTasksFinished(); | 
 |     expect(filesHighlights[pkgFile], isNull); | 
 |     // subscribe | 
 |     await addAnalysisSubscription(AnalysisService.HIGHLIGHTS, pkgFile); | 
 |     await _resultsAvailable.future; | 
 |     // there are results | 
 |     expect(filesHighlights[pkgFile], isNotEmpty); | 
 |   } | 
 |  | 
 |   Future<void> test_afterAnalysis_packageFile_inRoot() async { | 
 |     var pkgA = convertPath('/pkgA'); | 
 |     var pkgB = convertPath('/pkgA'); | 
 |     var pkgFileA = newFile('$pkgA/lib/libA.dart', ''' | 
 | library lib_a; | 
 | class A {} | 
 | '''); | 
 |     newFile('$pkgA/lib/libB.dart', ''' | 
 | import 'package:pkgA/libA.dart'; | 
 | void f() { | 
 |   new A(); | 
 | } | 
 | '''); | 
 |     // add 'pkgA' and 'pkgB' as projects | 
 |     await setRoots(included: [pkgA, pkgB], excluded: []); | 
 |     // wait for analysis, no results initially | 
 |     await waitForTasksFinished(); | 
 |     expect(filesHighlights[pkgFileA], isNull); | 
 |     // subscribe | 
 |     await addAnalysisSubscription(AnalysisService.HIGHLIGHTS, pkgFileA); | 
 |     await _resultsAvailable.future; | 
 |     // there are results | 
 |     expect(filesHighlights[pkgFileA], isNotEmpty); | 
 |   } | 
 |  | 
 |   Future<void> test_afterAnalysis_packageFile_notUsed() async { | 
 |     var pkgFile = newFile('/packages/pkgA/lib/libA.dart', ''' | 
 | library lib_a; | 
 | class A {} | 
 | '''); | 
 |     writePackageConfig( | 
 |       convertPath('/project'), | 
 |       config: (PackageConfigFileBuilder() | 
 |         ..add(name: 'pkgA', rootPath: convertPath('/packages/pkgA'))), | 
 |     ); | 
 |     // | 
 |     addTestFile('// no "pkgA" reference'); | 
 |     // wait for analysis, no results initially | 
 |     await waitForTasksFinished(); | 
 |     expect(filesHighlights[pkgFile], isNull); | 
 |     // make it a priority file, so make analyzable | 
 |     server.setPriorityFiles('0', [pkgFile.path]); | 
 |     // subscribe | 
 |     await addAnalysisSubscription(AnalysisService.HIGHLIGHTS, pkgFile); | 
 |     await _resultsAvailable.future; | 
 |     // there are results | 
 |     expect(filesHighlights[pkgFile], isNotEmpty); | 
 |   } | 
 |  | 
 |   Future<void> test_afterAnalysis_sdkFile() async { | 
 |     var file = getFile('/sdk/lib/core/core.dart'); | 
 |     addTestFile('// no matter'); | 
 |     // wait for analysis, no results initially | 
 |     await waitForTasksFinished(); | 
 |     expect(filesHighlights[file], isNull); | 
 |     // subscribe | 
 |     await addAnalysisSubscription(AnalysisService.HIGHLIGHTS, file); | 
 |     await _resultsAvailable.future; | 
 |     // there are results | 
 |     expect(filesHighlights[file], isNotEmpty); | 
 |   } | 
 |  | 
 |   Future<void> test_beforeAnalysis() async { | 
 |     addTestFile('int V = 42;'); | 
 |     // subscribe | 
 |     await addAnalysisSubscription(AnalysisService.HIGHLIGHTS, testFile); | 
 |     // wait for analysis | 
 |     await waitForTasksFinished(); | 
 |     expect(filesHighlights[testFile], isNotEmpty); | 
 |   } | 
 |  | 
 |   Future<void> test_sentToPlugins() async { | 
 |     if (!AnalysisServer.supportsPlugins) return; | 
 |     addTestFile('int V = 42;'); | 
 |     // subscribe | 
 |     await addAnalysisSubscription(AnalysisService.HIGHLIGHTS, testFile); | 
 |     // wait for analysis | 
 |     await waitForTasksFinished(); | 
 |     var params = pluginManager.analysisSetSubscriptionsParams!; | 
 |     var subscriptions = params.subscriptions; | 
 |     expect(subscriptions, hasLength(1)); | 
 |     var files = subscriptions[plugin.AnalysisService.HIGHLIGHTS]; | 
 |     expect(files, [testFile.path]); | 
 |   } | 
 | } | 
 |  | 
 | class _AnalysisDomainTest extends PubPackageAnalysisServerTest { | 
 |   final configuration = _NotificationPrinterConfiguration(); | 
 |   final List<(String, Object)> notifications = []; | 
 |  | 
 |   void assertNotificationsText(String expected) { | 
 |     final buffer = StringBuffer(); | 
 |     final sink = TreeStringSink(sink: buffer, indent: ''); | 
 |     _NotificationPrinter( | 
 |       configuration: configuration, | 
 |       resourceProvider: resourceProvider, | 
 |       sink: sink, | 
 |     ).writeNotifications(notifications); | 
 |     notifications.clear(); | 
 |  | 
 |     final actual = buffer.toString(); | 
 |     if (actual != expected) { | 
 |       print('-------- Actual --------'); | 
 |       print('$actual------------------------'); | 
 |     } | 
 |     expect(actual, expected); | 
 |   } | 
 |  | 
 |   @override | 
 |   void processNotification(Notification notification) { | 
 |     if (notification.event == ANALYSIS_NOTIFICATION_FLUSH_RESULTS) { | 
 |       var decoded = AnalysisFlushResultsParams.fromNotification(notification); | 
 |       notifications.add((notification.event, decoded)); | 
 |     } | 
 |     if (notification.event == ANALYSIS_NOTIFICATION_ERRORS) { | 
 |       var decoded = AnalysisErrorsParams.fromNotification(notification); | 
 |       notifications.add((notification.event, decoded)); | 
 |     } | 
 |   } | 
 |  | 
 |   /// Create files with a content that has a compile time error. | 
 |   void _createFilesWithErrors(List<String> paths) { | 
 |     for (var path in paths) { | 
 |       newFile(path, 'error'); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | class _NotificationPrinter { | 
 |   final _NotificationPrinterConfiguration configuration; | 
 |   final ResourceProvider resourceProvider; | 
 |   final TreeStringSink sink; | 
 |  | 
 |   _NotificationPrinter({ | 
 |     required this.configuration, | 
 |     required this.resourceProvider, | 
 |     required this.sink, | 
 |   }); | 
 |  | 
 |   void writeNotifications(List<(String, Object)> notifications) { | 
 |     for (final entry in notifications) { | 
 |       _writeNotification(entry.$1, entry.$2); | 
 |     } | 
 |   } | 
 |  | 
 |   void _writelnFile(String path, {String? name}) { | 
 |     sink.writeIndentedLine(() { | 
 |       if (name != null) { | 
 |         sink.write('$name: '); | 
 |       } | 
 |       final file = resourceProvider.getFile(path); | 
 |       sink.write(file.posixPath); | 
 |     }); | 
 |   } | 
 |  | 
 |   void _writeNotification(String event, Object notification) { | 
 |     switch (notification) { | 
 |       case AnalysisFlushResultsParams(): | 
 |         final files = notification.files.sorted(); | 
 |         sink.writeElements('AnalysisFlush', files, _writelnFile); | 
 |       case AnalysisErrorsParams(): | 
 |         sink.writelnWithIndent('AnalysisErrors'); | 
 |         sink.withIndent(() { | 
 |           _writelnFile(name: 'file', notification.file); | 
 |           if (configuration.withAnalysisErrorDetails) { | 
 |             throw UnimplementedError(); | 
 |           } else if (notification.errors.isNotEmpty) { | 
 |             sink.writelnWithIndent('errors: notEmpty'); | 
 |           } else { | 
 |             sink.writelnWithIndent('errors: empty'); | 
 |           } | 
 |         }); | 
 |       default: | 
 |         throw UnimplementedError('${notification.runtimeType}'); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | class _NotificationPrinterConfiguration { | 
 |   bool withAnalysisErrorDetails = false; | 
 | } |