| // Copyright (c) 2015, 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. |
| |
| library services.analyzer_server_test; |
| |
| import 'package:dart_services/src/analysis_server.dart'; |
| import 'package:dart_services/src/common.dart'; |
| import 'package:dart_services/src/flutter_web.dart'; |
| import 'package:dart_services/src/protos/dart_services.pb.dart' as proto; |
| import 'package:dart_services/src/sdk_manager.dart'; |
| import 'package:test/test.dart'; |
| |
| const completionCode = r''' |
| void main() { |
| int i = 0; |
| i. |
| } |
| '''; |
| |
| const completionFilterCode = r''' |
| void main() { |
| pr |
| } |
| '''; |
| |
| const completionLargeNamespaces = r''' |
| class A {} |
| class AB {} |
| class ABC {} |
| void main() { |
| var c = A |
| } |
| class ZZ {} |
| class a {} |
| '''; |
| |
| const quickFixesCode = r''' |
| void main() { |
| int i = 0 |
| } |
| '''; |
| |
| const badFormatCode = r''' |
| void main() |
| { |
| int i = 0; |
| } |
| '''; |
| |
| const formattedCode = r''' |
| void main() { |
| int i = 0; |
| } |
| '''; |
| |
| const formatWithIssues = ''' |
| void main() { foo() } |
| '''; |
| |
| void main() => defineTests(); |
| |
| void defineTests() { |
| AnalysisServerWrapper analysisServer; |
| |
| group('Platform SDK analysis_server', () { |
| setUp(() async { |
| analysisServer = DartAnalysisServerWrapper(); |
| await analysisServer.init(); |
| }); |
| |
| tearDown(() => analysisServer.shutdown()); |
| |
| test('simple_completion', () async { |
| // Just after i. |
| final results = await analysisServer.complete(completionCode, 32); |
| expect(results.replacementLength, 0); |
| expect(results.replacementOffset, 32); |
| expectCompletionsContains(results, 'abs'); |
| expect(completionsContains(results, 'codeUnitAt'), false); |
| }); |
| |
| test('repro #126 - completions polluted on second request', () async { |
| // https://github.com/dart-lang/dart-services/issues/126 |
| return analysisServer.complete(completionFilterCode, 17).then((results) { |
| return analysisServer |
| .complete(completionFilterCode, 17) |
| .then((results) { |
| expect(results.replacementLength, 2); |
| expect(results.replacementOffset, 16); |
| expect(completionsContains(results, 'print'), true); |
| expect(completionsContains(results, 'pow'), false); |
| }); |
| }); |
| }); |
| |
| test('import_test', () async { |
| // We're testing here that we don't have any path imports - we don't want |
| // to enable browsing the file system. |
| final testCode = "import '/'; main() { int a = 0; a. }"; |
| final results = await analysisServer.complete(testCode, 9); |
| final completions = results.completions; |
| |
| if (completions.isNotEmpty) { |
| expect(completions.every((completion) { |
| return completion.completion['completion'].startsWith('dart:'); |
| }), true); |
| } |
| }); |
| |
| test('import_dart_core_test', () async { |
| // Ensure we can import dart: imports. |
| final testCode = "import 'dart:c'; main() { int a = 0; a. }"; |
| |
| final results = await analysisServer.complete(testCode, 14); |
| final completions = results.completions; |
| |
| expect( |
| completions.every((completion) => |
| completion.completion['completion'].startsWith('dart:')), |
| true, |
| ); |
| expect( |
| completions.any((completion) => |
| completion.completion['completion'].startsWith('dart:')), |
| true, |
| ); |
| }); |
| |
| test('import_and_other_test', () async { |
| final testCode = "import '/'; main() { int a = 0; a. }"; |
| final results = await analysisServer.complete(testCode, 34); |
| |
| expect(completionsContains(results, 'abs'), true); |
| }); |
| |
| test('simple_quickFix', () async { |
| final results = await analysisServer.getFixes(quickFixesCode, 25); |
| |
| expect(results.fixes.length, 2); |
| |
| // Fixes are not guaranteed to arrive in a particular order. |
| results.fixes.sort((a, b) => a.offset.compareTo(b.offset)); |
| |
| expect(results.fixes[0].offset, 20); |
| expect(results.fixes[0].length, 1); // We need an insertion. |
| |
| expect(results.fixes[1].offset, 24); |
| expect(results.fixes[1].length, 1); // We need an insertion. |
| |
| expect(results.fixes[1].fixes.length, 1); |
| |
| final candidateFix = results.fixes[1].fixes[0]; |
| |
| expect(candidateFix.message.contains(';'), true); |
| expect(candidateFix.edits[0].length, 0); |
| expect(candidateFix.edits[0].offset, 25); |
| expect(candidateFix.edits[0].replacement, ';'); |
| }); |
| |
| test('simple_format', () async { |
| final results = await analysisServer.format(badFormatCode, 0); |
| expect(results.newString, formattedCode); |
| }); |
| |
| test('format good code', () async { |
| final results = |
| await analysisServer.format(formattedCode.replaceAll('\n', ' '), 0); |
| expect(results.newString, formattedCode); |
| }); |
| |
| test('format with issues', () async { |
| final results = await analysisServer.format(formatWithIssues, 0); |
| expect(results.newString, formatWithIssues); |
| }); |
| |
| test('analyze', () async { |
| final results = await analysisServer.analyze(sampleCode); |
| expect(results.issues, isEmpty); |
| }); |
| |
| test('analyze with errors', () async { |
| final results = await analysisServer.analyze(sampleCodeError); |
| expect(results.issues, hasLength(1)); |
| }); |
| |
| test('analyze strong', () async { |
| final results = await analysisServer.analyze(sampleStrongError); |
| expect(results.issues, hasLength(1)); |
| final issue = results.issues.first; |
| expect(issue.kind, 'error'); |
| }); |
| |
| test('filter completions', () async { |
| // just after A |
| final idx = 61; |
| expect(completionLargeNamespaces.substring(idx - 1, idx), 'A'); |
| final results = |
| await analysisServer.complete(completionLargeNamespaces, 61); |
| expect(completionsContains(results, 'A'), true); |
| expect(completionsContains(results, 'AB'), true); |
| expect(completionsContains(results, 'ABC'), true); |
| expect(completionsContains(results, 'a'), true); |
| expect(completionsContains(results, 'ZZ'), false); |
| }); |
| }); |
| |
| group('Flutter cached SDK analysis_server', () { |
| FlutterWebManager flutterWebManager; |
| |
| setUp(() async { |
| flutterWebManager = FlutterWebManager(SdkManager.flutterSdk); |
| analysisServer = FlutterAnalysisServerWrapper(flutterWebManager); |
| await analysisServer.init(); |
| }); |
| |
| tearDown(() => analysisServer.shutdown()); |
| |
| test('analyze working Dart code', () async { |
| final results = await analysisServer.analyze(sampleCode); |
| expect(results.issues, isEmpty); |
| }); |
| |
| test('analyze working Flutter code', () async { |
| final results = await analysisServer.analyze(sampleCode); |
| expect(results.issues, isEmpty); |
| }); |
| }); |
| } |
| |
| bool completionsContains(proto.CompleteResponse response, String expected) => |
| response.completions |
| .any((completion) => completion.completion['completion'] == expected); |
| |
| void expectCompletionsContains( |
| proto.CompleteResponse response, String expected) { |
| final completions = |
| response.completions.map((c) => c.completion['completion']).toList(); |
| expect(completions, contains(expected)); |
| } |