blob: 652aec3c64092ebc710a896a5e3bfe32e1e52dcc [file]
// Copyright (c) 2019, 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/lsp_protocol/protocol.dart';
import 'package:analysis_server/src/lsp/constants.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../shared/shared_code_actions_refactor_tests.dart';
import 'code_actions_mixin.dart';
import 'server_abstract.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(ExtractMethodRefactorCodeActionsTest);
defineReflectiveTests(ExtractWidgetRefactorCodeActionsTest);
defineReflectiveTests(ExtractVariableRefactorCodeActionsTest);
defineReflectiveTests(InlineLocalVariableRefactorCodeActionsTest);
defineReflectiveTests(InlineMethodRefactorCodeActionsTest);
defineReflectiveTests(ConvertGetterToMethodCodeActionsTest);
defineReflectiveTests(ConvertMethodToGetterCodeActionsTest);
});
}
@reflectiveTest
class ConvertGetterToMethodCodeActionsTest extends RefactorCodeActionsTest
with
// Tests are defined in a shared mixin.
SharedConvertGetterToMethodRefactorCodeActionsTests {}
@reflectiveTest
class ConvertMethodToGetterCodeActionsTest extends RefactorCodeActionsTest
with
// Tests are defined in a shared mixin.
SharedConvertMethodToGetterRefactorCodeActionsTests {}
@reflectiveTest
class ExtractMethodRefactorCodeActionsTest extends RefactorCodeActionsTest
with
// Most tests are defined in a shared mixin.
SharedExtractMethodRefactorCodeActionsTests {
Future<void> test_progress_clientProvided() async {
const content = '''
void f() {
print('Test!');
[!print('Test!');!]
}
''';
const expectedContent = '''
void f() {
print('Test!');
newMethod();
}
void newMethod() {
print('Test!');
}
''';
// Expect begin/end progress updates without a create, since the
// token was supplied by us (the client).
expect(progressUpdates, emitsInOrder(['BEGIN', 'END']));
await verifyCodeActionLiteralEdits(
content,
expectedContent,
command: Commands.performRefactor,
title: extractMethodTitle,
commandWorkDoneToken: clientProvidedTestWorkDoneToken,
);
}
Future<void> test_progress_notSupported() async {
const content = '''
void f() {
print('Test!');
[!print('Test!');!]
}
''';
const expectedContent = '''
void f() {
print('Test!');
newMethod();
}
void newMethod() {
print('Test!');
}
''';
var didGetProgressNotifications = false;
progressUpdates.listen((_) => didGetProgressNotifications = true);
await verifyCodeActionLiteralEdits(
content,
expectedContent,
command: Commands.performRefactor,
title: extractMethodTitle,
);
expect(didGetProgressNotifications, isFalse);
}
Future<void> test_progress_serverGenerated() async {
const content = '''
void f() {
print('Test!');
[!print('Test!');!]
}
''';
const expectedContent = '''
void f() {
print('Test!');
newMethod();
}
void newMethod() {
print('Test!');
}
''';
// Expect create/begin/end progress updates, because in this case the server
// generates the token.
expect(progressUpdates, emitsInOrder(['CREATE', 'BEGIN', 'END']));
setWorkDoneProgressSupport();
await verifyCodeActionLiteralEdits(
content,
expectedContent,
command: Commands.performRefactor,
title: extractMethodTitle,
);
}
/// Test if the client does not call refactor.validate it still gets a
/// sensible `showMessage` call and not a failed request.
Future<void> test_validLocation_failsInitialValidation_noValidation() async {
const content = '''
f() {
var a = 0;
doFoo([!() => print(a)!]);
print(a);
}
void doFoo(void Function() a) => a();
''';
var codeAction = await expectCodeActionLiteral(
content,
command: Commands.performRefactor,
title: extractMethodTitle,
);
var command = codeAction.command!;
// Call the refactor without any validation and expected an error message
// without a request failure.
var errorNotification = await expectErrorNotification(() async {
var response = await executeCommand(
Command(
title: command.title,
command: command.command,
arguments: command.arguments,
),
);
expect(response, isNull);
});
expect(
errorNotification.message,
contains('Cannot extract the closure as a method'),
);
}
}
@reflectiveTest
class ExtractVariableRefactorCodeActionsTest extends RefactorCodeActionsTest
with
// Tests are defined in a shared mixin.
SharedExtractVariableRefactorCodeActionsTests {}
@reflectiveTest
class ExtractWidgetRefactorCodeActionsTest extends RefactorCodeActionsTest
with
// Tests are defined in a shared mixin.
SharedExtractWidgetRefactorCodeActionsTests {}
@reflectiveTest
class InlineLocalVariableRefactorCodeActionsTest extends RefactorCodeActionsTest
with
// Tests are defined in a shared mixin.
SharedInlineLocalVariableRefactorCodeActionsTests {}
@reflectiveTest
class InlineMethodRefactorCodeActionsTest extends RefactorCodeActionsTest
with
// Tests are defined in a shared mixin.
SharedInlineMethodRefactorCodeActionsTests {}
abstract class RefactorCodeActionsTest extends AbstractLspAnalysisServerTest
with
LspSharedTestMixin,
CodeActionsTestMixin,
SharedRefactorCodeActionsTests {
@override
Future<T> handleRefactorAnywayPrompt<T>(
Future<T> Function() f, {
required String expectedMessage,
required List<String> expectedActions,
String? selectAction,
}) async {
return await handleExpectedRequest(
Method.window_showMessageRequest,
ShowMessageRequestParams.fromJson,
f,
handler: (ShowMessageRequestParams params) async {
// Ensure the warning prompt is as expected.
expect(params.type, equals(MessageType.Warning));
expect(params.message, equals(expectedMessage));
expect(params.actions, hasLength(2));
expect(
params.actions![0],
equals(MessageActionItem(title: UserPromptActions.refactorAnyway)),
);
expect(
params.actions![1],
equals(MessageActionItem(title: UserPromptActions.cancel)),
);
// Respond to the request with the required action.
return selectAction != null
? MessageActionItem(title: selectAction)
: null;
},
);
}
@override
void setUp() {
super.setUp();
setApplyEditSupport();
setDocumentChangesSupport();
setSupportedCodeActionKinds([CodeActionKind.Refactor]);
}
}