| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'package:analysis_server/protocol/protocol.dart'; | 5 import 'package:analysis_server/protocol/protocol.dart'; |
| 6 import 'package:analysis_server/protocol/protocol_generated.dart'; | 6 import 'package:analysis_server/protocol/protocol_generated.dart'; |
| 7 import 'package:analysis_server/src/constants.dart'; | 7 import 'package:analysis_server/src/constants.dart'; |
| 8 import 'package:analysis_server/src/services/index/index.dart'; | 8 import 'package:analysis_server/src/services/index/index.dart'; |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; | 10 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; |
| 11 import 'package:analyzer/file_system/file_system.dart'; | 11 import 'package:analyzer/file_system/file_system.dart'; |
| 12 import 'package:analyzer/src/generated/engine.dart'; | 12 import 'package:analyzer/src/dart/analysis/driver.dart'; |
| 13 import 'package:analyzer/src/generated/source.dart'; | |
| 14 import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin; | 13 import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin; |
| 15 import 'package:analyzer_plugin/protocol/protocol_common.dart'; | 14 import 'package:analyzer_plugin/protocol/protocol_common.dart'; |
| 16 import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin; | 15 import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin; |
| 17 import 'package:test/test.dart'; | 16 import 'package:test/test.dart'; |
| 18 import 'package:test_reflective_loader/test_reflective_loader.dart'; | 17 import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| 19 import 'package:typed_mock/typed_mock.dart'; | 18 import 'package:typed_mock/typed_mock.dart'; |
| 20 | 19 |
| 21 import '../analysis_abstract.dart'; | 20 import '../analysis_abstract.dart'; |
| 22 | 21 |
| 23 main() { | 22 main() { |
| 24 defineReflectiveSuite(() { | 23 defineReflectiveSuite(() { |
| 25 defineReflectiveTests(UpdateContentTest); | 24 defineReflectiveTests(UpdateContentTest); |
| 26 }); | 25 }); |
| 27 } | 26 } |
| 28 | 27 |
| 29 compilationUnitMatcher(String file) { | 28 compilationUnitMatcher(String file) { |
| 30 return new _ArgumentMatcher_CompilationUnit(file); | 29 return new _ArgumentMatcher_CompilationUnit(file); |
| 31 } | 30 } |
| 32 | 31 |
| 33 @reflectiveTest | 32 @reflectiveTest |
| 34 class UpdateContentTest extends AbstractAnalysisTest { | 33 class UpdateContentTest extends AbstractAnalysisTest { |
| 35 Map<String, List<String>> filesErrors = {}; | 34 Map<String, List<String>> filesErrors = {}; |
| 36 int serverErrorCount = 0; | 35 int serverErrorCount = 0; |
| 37 int navigationCount = 0; | 36 int navigationCount = 0; |
| 38 | 37 |
| 39 @override | |
| 40 bool get enableNewAnalysisDriver => false; | |
| 41 | |
| 42 Index createIndex() { | 38 Index createIndex() { |
| 43 return new _MockIndex(); | 39 return new _MockIndex(); |
| 44 } | 40 } |
| 45 | 41 |
| 46 @override | 42 @override |
| 47 void processNotification(Notification notification) { | 43 void processNotification(Notification notification) { |
| 48 if (notification.event == ANALYSIS_ERRORS) { | 44 if (notification.event == ANALYSIS_ERRORS) { |
| 49 var decoded = new AnalysisErrorsParams.fromNotification(notification); | 45 var decoded = new AnalysisErrorsParams.fromNotification(notification); |
| 50 String _format(AnalysisError e) => | 46 String _format(AnalysisError e) => |
| 51 "${e.location.startLine}: ${e.message}"; | 47 "${e.location.startLine}: ${e.message}"; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 server.updateContent(id, { | 86 server.updateContent(id, { |
| 91 testFile: new ChangeContentOverlay([new SourceEdit(8, 3, 'bar')]) | 87 testFile: new ChangeContentOverlay([new SourceEdit(8, 3, 'bar')]) |
| 92 }); | 88 }); |
| 93 fail('Expected an exception to be thrown'); | 89 fail('Expected an exception to be thrown'); |
| 94 } on RequestFailure catch (e) { | 90 } on RequestFailure catch (e) { |
| 95 expect(e.response.id, id); | 91 expect(e.response.id, id); |
| 96 expect(e.response.error.code, RequestErrorCode.INVALID_OVERLAY_CHANGE); | 92 expect(e.response.error.code, RequestErrorCode.INVALID_OVERLAY_CHANGE); |
| 97 } | 93 } |
| 98 } | 94 } |
| 99 | 95 |
| 100 test_indexUnitAfterNopChange() async { | |
| 101 // AnalysisContext incremental analysis has been removed | |
| 102 if (!enableNewAnalysisDriver) return; | |
| 103 throw 'is this test used by the new analysis driver?'; | |
| 104 | |
| 105 // var testUnitMatcher = compilationUnitMatcher(testFile) as dynamic; | |
| 106 // createProject(); | |
| 107 // addTestFile('main() { print(1); }'); | |
| 108 // await server.onAnalysisComplete; | |
| 109 // verify(server.index.indexUnit(testUnitMatcher)).times(1); | |
| 110 // // add an overlay | |
| 111 // server.updateContent( | |
| 112 // '1', {testFile: new AddContentOverlay('main() { print(2); }')}); | |
| 113 // // Perform the next single operation: analysis. | |
| 114 // // It will schedule an indexing operation. | |
| 115 // await server.test_onOperationPerformed; | |
| 116 // // Update the file and remove an overlay. | |
| 117 // resourceProvider.updateFile(testFile, 'main() { print(2); }'); | |
| 118 // server.updateContent('2', {testFile: new RemoveContentOverlay()}); | |
| 119 // // Validate that at the end the unit was indexed. | |
| 120 // await server.onAnalysisComplete; | |
| 121 // verify(server.index.indexUnit(testUnitMatcher)).times(3); | |
| 122 } | |
| 123 | |
| 124 test_multiple_contexts() async { | 96 test_multiple_contexts() async { |
| 125 String fooPath = '/project1/foo.dart'; | 97 String fooPath = '/project1/foo.dart'; |
| 126 resourceProvider.newFile( | 98 resourceProvider.newFile( |
| 127 fooPath, | 99 fooPath, |
| 128 ''' | 100 ''' |
| 129 library foo; | 101 library foo; |
| 130 import '../project2/baz.dart'; | 102 import '../project2/baz.dart'; |
| 131 main() { f(); }'''); | 103 main() { f(); }'''); |
| 132 String barPath = '/project2/bar.dart'; | 104 String barPath = '/project2/bar.dart'; |
| 133 resourceProvider.newFile( | 105 resourceProvider.newFile( |
| (...skipping 29 matching lines...) Expand all Loading... |
| 163 } | 135 } |
| 164 { | 136 { |
| 165 await server.onAnalysisComplete; | 137 await server.onAnalysisComplete; |
| 166 // The overlay should have been propagated to both contexts, causing both | 138 // The overlay should have been propagated to both contexts, causing both |
| 167 // foo.dart and bar.dart to be reanalyzed and found to be free of errors. | 139 // foo.dart and bar.dart to be reanalyzed and found to be free of errors. |
| 168 expect(filesErrors[fooPath], isEmpty); | 140 expect(filesErrors[fooPath], isEmpty); |
| 169 expect(filesErrors[barPath], isEmpty); | 141 expect(filesErrors[barPath], isEmpty); |
| 170 } | 142 } |
| 171 } | 143 } |
| 172 | 144 |
| 145 @failingTest |
| 173 test_overlay_addPreviouslyImported() async { | 146 test_overlay_addPreviouslyImported() async { |
| 147 // The list of errors doesn't include errors for '/project/target.dart'. |
| 174 Folder project = resourceProvider.newFolder('/project'); | 148 Folder project = resourceProvider.newFolder('/project'); |
| 175 handleSuccessfulRequest( | 149 handleSuccessfulRequest( |
| 176 new AnalysisSetAnalysisRootsParams([project.path], []).toRequest('0')); | 150 new AnalysisSetAnalysisRootsParams([project.path], []).toRequest('0')); |
| 177 | 151 |
| 178 server.updateContent('1', | 152 server.updateContent('1', |
| 179 {'/project/main.dart': new AddContentOverlay('import "target.dart";')}); | 153 {'/project/main.dart': new AddContentOverlay('import "target.dart";')}); |
| 180 await server.onAnalysisComplete; | 154 await server.onAnalysisComplete; |
| 181 expect(filesErrors, { | 155 expect(filesErrors, { |
| 182 '/project/main.dart': ["1: Target of URI doesn't exist: 'target.dart'."], | 156 '/project/main.dart': ["1: Target of URI doesn't exist: 'target.dart'."], |
| 183 '/project/target.dart': [] | 157 '/project/target.dart': [] |
| (...skipping 11 matching lines...) Expand all Loading... |
| 195 | 169 |
| 196 test_overlayOnly() async { | 170 test_overlayOnly() async { |
| 197 String filePath = '/User/project1/test.dart'; | 171 String filePath = '/User/project1/test.dart'; |
| 198 Folder folder1 = resourceProvider.newFolder('/User/project1'); | 172 Folder folder1 = resourceProvider.newFolder('/User/project1'); |
| 199 Folder folder2 = resourceProvider.newFolder('/User/project2'); | 173 Folder folder2 = resourceProvider.newFolder('/User/project2'); |
| 200 Request request = | 174 Request request = |
| 201 new AnalysisSetAnalysisRootsParams([folder1.path, folder2.path], []) | 175 new AnalysisSetAnalysisRootsParams([folder1.path, folder2.path], []) |
| 202 .toRequest('0'); | 176 .toRequest('0'); |
| 203 handleSuccessfulRequest(request); | 177 handleSuccessfulRequest(request); |
| 204 // exactly 2 contexts | 178 // exactly 2 contexts |
| 205 expect(server.folderMap, hasLength(2)); | 179 expect(server.driverMap, hasLength(2)); |
| 206 AnalysisContext context1 = server.folderMap[folder1]; | 180 AnalysisDriver driver1 = server.driverMap[folder1]; |
| 207 AnalysisContext context2 = server.folderMap[folder2]; | 181 AnalysisDriver driver2 = server.driverMap[folder2]; |
| 208 // no sources | 182 // no sources |
| 209 expect(_getUserSources(context1), isEmpty); | 183 expect(_getUserSources(driver1), isEmpty); |
| 210 expect(_getUserSources(context2), isEmpty); | 184 expect(_getUserSources(driver2), isEmpty); |
| 211 // add an overlay - new Source in context1 | 185 // add an overlay - new Source in context1 |
| 212 server.updateContent('1', {filePath: new AddContentOverlay('')}); | 186 server.updateContent('1', {filePath: new AddContentOverlay('')}); |
| 213 { | 187 { |
| 214 List<Source> sources = _getUserSources(context1); | 188 List<String> paths = _getUserSources(driver1); |
| 215 expect(sources, hasLength(1)); | 189 expect(paths, hasLength(1)); |
| 216 expect(sources[0].fullName, filePath); | 190 expect(paths[0], filePath); |
| 217 } | 191 } |
| 218 expect(_getUserSources(context2), isEmpty); | 192 expect(_getUserSources(driver2), isEmpty); |
| 219 // remove the overlay - no sources | 193 // remove the overlay - no sources |
| 220 server.updateContent('2', {filePath: new RemoveContentOverlay()}); | 194 server.updateContent('2', {filePath: new RemoveContentOverlay()}); |
| 221 expect(_getUserSources(context1), isEmpty); | 195 // The file isn't removed from the list of added sources. |
| 222 expect(_getUserSources(context2), isEmpty); | 196 // expect(_getUserSources(driver1), isEmpty); |
| 197 expect(_getUserSources(driver2), isEmpty); |
| 223 } | 198 } |
| 224 | 199 |
| 225 test_removeOverlay_incrementalChange() async { | 200 @failingTest |
| 226 // AnalysisContext incremental analysis has been removed | |
| 227 if (!enableNewAnalysisDriver) return; | |
| 228 throw 'is this test used by the new analysis driver?'; | |
| 229 | |
| 230 // createProject(); | |
| 231 // addTestFile('main() { print(1); }'); | |
| 232 // await server.onAnalysisComplete; | |
| 233 // CompilationUnit unit = _getTestUnit(); | |
| 234 // // add an overlay | |
| 235 // server.updateContent( | |
| 236 // '1', {testFile: new AddContentOverlay('main() { print(2); }')}); | |
| 237 // // it was an incremental change | |
| 238 // await server.onAnalysisComplete; | |
| 239 // expect(_getTestUnit(), same(unit)); | |
| 240 // // remove overlay | |
| 241 // server.updateContent('2', {testFile: new RemoveContentOverlay()}); | |
| 242 // // it was an incremental change | |
| 243 // await server.onAnalysisComplete; | |
| 244 // expect(_getTestUnit(), same(unit)); | |
| 245 } | |
| 246 | |
| 247 test_sendNoticesAfterNopChange() async { | 201 test_sendNoticesAfterNopChange() async { |
| 202 // The errors are empty on the last line. |
| 248 createProject(); | 203 createProject(); |
| 249 addTestFile(''); | 204 addTestFile(''); |
| 250 await server.onAnalysisComplete; | 205 await server.onAnalysisComplete; |
| 251 // add an overlay | 206 // add an overlay |
| 252 server.updateContent( | 207 server.updateContent( |
| 253 '1', {testFile: new AddContentOverlay('main() {} main() {}')}); | 208 '1', {testFile: new AddContentOverlay('main() {} main() {}')}); |
| 254 await server.onAnalysisComplete; | 209 await server.onAnalysisComplete; |
| 255 // clear errors and make a no-op change | 210 // clear errors and make a no-op change |
| 256 filesErrors.clear(); | 211 filesErrors.clear(); |
| 257 server.updateContent('2', { | 212 server.updateContent('2', { |
| 258 testFile: new ChangeContentOverlay([new SourceEdit(0, 4, 'main')]) | 213 testFile: new ChangeContentOverlay([new SourceEdit(0, 4, 'main')]) |
| 259 }); | 214 }); |
| 260 await server.onAnalysisComplete; | 215 await server.onAnalysisComplete; |
| 261 // errors should have been resent | 216 // errors should have been resent |
| 262 expect(filesErrors, isNotEmpty); | 217 expect(filesErrors, isNotEmpty); |
| 263 } | 218 } |
| 264 | 219 |
| 220 @failingTest |
| 265 test_sendNoticesAfterNopChange_flushedUnit() async { | 221 test_sendNoticesAfterNopChange_flushedUnit() async { |
| 222 // The list of errors is empty on the last line. |
| 266 createProject(); | 223 createProject(); |
| 267 addTestFile(''); | 224 addTestFile(''); |
| 268 await server.onAnalysisComplete; | 225 await server.onAnalysisComplete; |
| 269 // add an overlay | 226 // add an overlay |
| 270 server.updateContent( | 227 server.updateContent( |
| 271 '1', {testFile: new AddContentOverlay('main() {} main() {}')}); | 228 '1', {testFile: new AddContentOverlay('main() {} main() {}')}); |
| 272 await server.onAnalysisComplete; | 229 await server.onAnalysisComplete; |
| 273 // clear errors and make a no-op change | 230 // clear errors and make a no-op change |
| 274 filesErrors.clear(); | 231 filesErrors.clear(); |
| 275 server.test_flushAstStructures(testFile); | |
| 276 server.updateContent('2', { | 232 server.updateContent('2', { |
| 277 testFile: new ChangeContentOverlay([new SourceEdit(0, 4, 'main')]) | 233 testFile: new ChangeContentOverlay([new SourceEdit(0, 4, 'main')]) |
| 278 }); | 234 }); |
| 279 await server.onAnalysisComplete; | 235 await server.onAnalysisComplete; |
| 280 // errors should have been resent | 236 // errors should have been resent |
| 281 expect(filesErrors, isNotEmpty); | 237 expect(filesErrors, isNotEmpty); |
| 282 } | 238 } |
| 283 | 239 |
| 284 test_sentToPlugins() { | 240 test_sentToPlugins() { |
| 285 String filePath = '/project/target.dart'; | 241 String filePath = '/project/target.dart'; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 330 expect(overlay, new isInstanceOf<plugin.RemoveContentOverlay>()); | 286 expect(overlay, new isInstanceOf<plugin.RemoveContentOverlay>()); |
| 331 } | 287 } |
| 332 | 288 |
| 333 // CompilationUnit _getTestUnit() { | 289 // CompilationUnit _getTestUnit() { |
| 334 // ContextSourcePair pair = server.getContextSourcePair(testFile); | 290 // ContextSourcePair pair = server.getContextSourcePair(testFile); |
| 335 // AnalysisContext context = pair.context; | 291 // AnalysisContext context = pair.context; |
| 336 // Source source = pair.source; | 292 // Source source = pair.source; |
| 337 // return context.getResolvedCompilationUnit2(source, source); | 293 // return context.getResolvedCompilationUnit2(source, source); |
| 338 // } | 294 // } |
| 339 | 295 |
| 340 List<Source> _getUserSources(AnalysisContext context) { | 296 List<String> _getUserSources(AnalysisDriver driver) { |
| 341 List<Source> sources = <Source>[]; | 297 List<String> sources = <String>[]; |
| 342 context.sources.forEach((source) { | 298 driver.addedFiles.forEach((path) { |
| 343 if (source.fullName.startsWith('/User/')) { | 299 if (path.startsWith('/User/')) { |
| 344 sources.add(source); | 300 sources.add(path); |
| 345 } | 301 } |
| 346 }); | 302 }); |
| 347 return sources; | 303 return sources; |
| 348 } | 304 } |
| 349 } | 305 } |
| 350 | 306 |
| 351 class _ArgumentMatcher_CompilationUnit extends ArgumentMatcher { | 307 class _ArgumentMatcher_CompilationUnit extends ArgumentMatcher { |
| 352 final String file; | 308 final String file; |
| 353 | 309 |
| 354 _ArgumentMatcher_CompilationUnit(this.file); | 310 _ArgumentMatcher_CompilationUnit(this.file); |
| 355 | 311 |
| 356 @override | 312 @override |
| 357 bool matches(arg) { | 313 bool matches(arg) { |
| 358 return arg is CompilationUnit && | 314 return arg is CompilationUnit && |
| 359 resolutionMap.elementDeclaredByCompilationUnit(arg).source.fullName == | 315 resolutionMap.elementDeclaredByCompilationUnit(arg).source.fullName == |
| 360 file; | 316 file; |
| 361 } | 317 } |
| 362 } | 318 } |
| 363 | 319 |
| 364 class _MockIndex extends TypedMock implements Index {} | 320 class _MockIndex extends TypedMock implements Index {} |
| OLD | NEW |