// Copyright (c) 2017, 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 'package:analysis_server/protocol/protocol_generated.dart'; import 'package:analysis_server/src/edit/edit_domain.dart'; import 'package:analyzer_plugin/protocol/protocol_common.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; import '../analysis_abstract.dart'; import '../mocks.dart'; void main() { defineReflectiveSuite(() { defineReflectiveTests(StatementCompletionTest); }); } @reflectiveTest class StatementCompletionTest extends AbstractAnalysisTest { late SourceChange change; @override void setUp() { super.setUp(); createProject(); handler = EditDomainHandler(server); } Future test_invalidFilePathFormat_notAbsolute() async { var request = EditGetStatementCompletionParams('test.dart', 0).toRequest('0'); var response = await waitResponse(request); expect( response, isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT), ); } Future test_invalidFilePathFormat_notNormalized() async { var request = EditGetStatementCompletionParams( convertPath('/foo/../bar/test.dart'), 0) .toRequest('0'); var response = await waitResponse(request); expect( response, isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT), ); } Future test_plainEnterFromStart() async { addTestFile(''' main() { int v = 1; } '''); await waitForTasksFinished(); await _prepareCompletion('v = 1;', atStart: true); _assertHasChange('Insert a newline at the end of the current line', ''' main() { int v = 1; /*caret*/ } '''); } Future test_plainOleEnter() async { addTestFile(''' main() { int v = 1; } '''); await waitForTasksFinished(); await _prepareCompletion('v = 1;', atEnd: true); _assertHasChange('Insert a newline at the end of the current line', ''' main() { int v = 1; /*caret*/ } '''); } Future test_plainOleEnterWithError() async { addTestFile(''' main() { int v = } '''); await waitForTasksFinished(); var match = 'v ='; await _prepareCompletion(match, atEnd: true); _assertHasChange( 'Insert a newline at the end of the current line', ''' main() { int v = x } ''', (s) => s.indexOf(match) + match.length); // Ensure cursor after '='. } void _assertHasChange(String message, String expectedCode, [Function? cmp]) { if (change.message == message) { if (change.edits.isNotEmpty) { var resultCode = SourceEdit.applySequence(testCode, change.edits[0].edits); expect(resultCode, expectedCode.replaceAll('/*caret*/', '')); if (cmp != null) { int offset = cmp(resultCode); expect(change.selection!.offset, offset); } } else { if (cmp != null) { int offset = cmp(testCode); expect(change.selection!.offset, offset); } } return; } fail('Expected to find |$message| but got: ' + change.message); } Future _prepareCompletion(String search, {bool atStart = false, bool atEnd = false, int delta = 0}) async { var offset = findOffset(search); if (atStart) { delta = 0; } else if (atEnd) { delta = search.length; } await _prepareCompletionAt(offset + delta); } Future _prepareCompletionAt(int offset) async { var request = EditGetStatementCompletionParams(testFile, offset).toRequest('0'); var response = await waitResponse(request); var result = EditGetStatementCompletionResult.fromResponse(response); change = result.change; } }