[analysis_server] Modify code action/refactor tests to verify whole set of edits The goal here is to ensure tests can't accidentally check only a subset of edits made during the command execution. Not all tests have been migrated (only refactorings and a few that happened to use some of the same methods for verification). Change-Id: I5589e8e667e957aee3ea55f741b1b49a3859d6bd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/312304 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/test/integration/lsp_server/integration_tests.dart b/pkg/analysis_server/test/integration/lsp_server/integration_tests.dart index ba36560..1d9d91d 100644 --- a/pkg/analysis_server/test/integration/lsp_server/integration_tests.dart +++ b/pkg/analysis_server/test/integration/lsp_server/integration_tests.dart
@@ -23,11 +23,21 @@ final Map<num, Completer<ResponseMessage>> _completers = {}; String dartSdkPath = dirname(dirname(Platform.resolvedExecutable)); + /// Tracks the current overlay content so that when we apply edits they can + /// be applied in the same way a real client would apply them. + final _overlayContent = <Uri, String>{}; + LspByteStreamServerChannel get channel => client!.channel!; @override Stream<Message> get serverToClient => client!.serverToClient; + @override + Future<void> closeFile(Uri uri) { + _overlayContent.remove(uri); + return super.closeFile(uri); + } + /// Sends a request to the server and unwraps the result. Throws if the /// response was not successful or returned an error. @override @@ -46,12 +56,39 @@ } } + @override + String? getCurrentFileContent(Uri uri) { + // First try and overlay the test has set. + if (_overlayContent.containsKey(uri)) { + return _overlayContent[uri]; + } + + // Otherwise fall back to the disk. + try { + return File(uri.toFilePath()).readAsStringSync(); + } catch (_) { + return null; + } + } + void newFile(String path, String content) => File(path).writeAsStringSync(content); void newFolder(String path) => Directory(path).createSync(recursive: true); @override + Future<void> openFile(Uri uri, String content, {int version = 1}) { + _overlayContent[uri] = content; + return super.openFile(uri, content, version: version); + } + + @override + Future<void> replaceFile(int newVersion, Uri uri, String content) { + _overlayContent[uri] = content; + return super.replaceFile(newVersion, uri, content); + } + + @override void sendNotificationToServer(NotificationMessage notification) => channel.sendNotification(notification);
diff --git a/pkg/analysis_server/test/lsp/code_actions_abstract.dart b/pkg/analysis_server/test/lsp/code_actions_abstract.dart index e6a45af..115e6a7 100644 --- a/pkg/analysis_server/test/lsp/code_actions_abstract.dart +++ b/pkg/analysis_server/test/lsp/code_actions_abstract.dart
@@ -51,52 +51,6 @@ ); } - /// Executes [command] which is expected to call back to the client to apply - /// a [WorkspaceEdit]. - /// - /// Changes are applied to [contents] to be verified by the caller. - Future<void> executeCommandForEdits( - Command command, - // TODO(dantup): Change this map to use Uris for files. - Map<String, String> contents, { - bool expectDocumentChanges = false, - ProgressToken? workDoneToken, - }) async { - ApplyWorkspaceEditParams? editParams; - - final commandResponse = await handleExpectedRequest<Object?, - ApplyWorkspaceEditParams, ApplyWorkspaceEditResult>( - Method.workspace_applyEdit, - ApplyWorkspaceEditParams.fromJson, - () => executeCommand(command, workDoneToken: workDoneToken), - handler: (edit) { - // When the server sends the edit back, just keep a copy and say we - // applied successfully (it'll be verified by the caller). - editParams = edit; - return ApplyWorkspaceEditResult(applied: true); - }, - ); - // Successful edits return an empty success() response. - expect(commandResponse, isNull); - - // Ensure the edit came back, and using the expected change type. - expect(editParams, isNotNull); - final edit = editParams!.edit; - if (expectDocumentChanges) { - expect(edit.changes, isNull); - expect(edit.documentChanges, isNotNull); - } else { - expect(edit.changes, isNotNull); - expect(edit.documentChanges, isNull); - } - - if (expectDocumentChanges) { - applyDocumentChanges(contents, edit.documentChanges!); - } else { - applyChanges(contents, edit.changes!); - } - } - /// Expects that command [commandName] was logged to the analytics manager. void expectCommandLogged(String commandName) { expect( @@ -155,32 +109,8 @@ (codeAction) => codeAction.command!, ); - await verifyCommandEdits(command, content, expectedContent, + await verifyCommandEdits(command, expectedContent, expectDocumentChanges: expectDocumentChanges, workDoneToken: workDoneToken); } - - /// Verifies that executing the given command on the server results in an edit - /// being sent in the client that updates the main file to match the expected - /// content. - Future<void> verifyCommandEdits( - Command command, - String content, - String expectedContent, { - bool expectDocumentChanges = false, - ProgressToken? workDoneToken, - }) async { - final contents = { - mainFilePath: withoutMarkers(content), - }; - - await executeCommandForEdits( - command, - contents, - expectDocumentChanges: expectDocumentChanges, - workDoneToken: workDoneToken, - ); - - expect(contents[mainFilePath], equals(expectedContent)); - } }
diff --git a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart index c73685c..b61aa86 100644 --- a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart +++ b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
@@ -40,6 +40,7 @@ } '''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart int test() => 42; void f() { var a = test(); @@ -105,6 +106,7 @@ } '''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart int get test => 42; void f() { var a = test; @@ -168,8 +170,9 @@ print('Test!'); [[print('Test!');]] } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void f() { print('Test!'); newMethod(); @@ -178,7 +181,7 @@ void newMethod() { print('Test!'); } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -197,7 +200,7 @@ print('Test!'); [[print('Test!');]] } - '''; +'''; const expectedContent = ''' void f() { print('Test!'); @@ -207,7 +210,7 @@ void newMethod() { print('Test!'); } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -251,7 +254,7 @@ print('Test!'); [[print('Test!');]] } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -276,7 +279,7 @@ print('Test!'); [[print('Test!');]] } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize( textDocumentCapabilities: withCodeActionKinds( @@ -326,8 +329,9 @@ Object Container(Object text) => null; Object Text(Object text) => null; - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart Object F() { return Container(text()); } @@ -336,7 +340,7 @@ Object Container(Object text) => null; Object Text(Object text) => null; - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -354,7 +358,7 @@ import 'dart:convert'; ^ void f() {} - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -370,7 +374,7 @@ import 'dart:io' as io; i^o.File a; - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -408,8 +412,9 @@ print('Test!'); [[print('Test!');]] } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void f() { print('Test!'); newMethod(); @@ -418,7 +423,7 @@ void newMethod() { print('Test!'); } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize( windowCapabilities: @@ -444,8 +449,9 @@ print('Test!'); [[print('Test!');]] } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void f() { print('Test!'); newMethod(); @@ -454,7 +460,7 @@ void newMethod() { print('Test!'); } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -480,8 +486,9 @@ print('Test!'); [[print('Test!');]] } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void f() { print('Test!'); newMethod(); @@ -490,7 +497,7 @@ void newMethod() { print('Test!'); } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize( windowCapabilities: @@ -518,7 +525,7 @@ void doFoo(void Function() a) => a(); - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -559,7 +566,7 @@ void doFoo(void Function() a) => a(); - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize( // We expect an error notification so don't fail on it. @@ -601,7 +608,7 @@ void doFoo(void Function() a) => a(); - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -644,15 +651,16 @@ } void foo(int arg) {} - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void f() { var arg = 1 + 2; foo(arg); } void foo(int arg) {} - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -673,8 +681,9 @@ } void foo(int arg) {} - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void f() { var arg = "test"; var arg2 = 1 + 2; @@ -682,7 +691,7 @@ } void foo(int arg) {} - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -704,13 +713,14 @@ void f() { test(1, 2); } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void f() { print(1); print(2); } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -732,13 +742,14 @@ void f() { test(1, 2); } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void f() { print(1); print(2); } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -762,15 +773,16 @@ test(1, 2); } } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart class A { void f() { print(1); print(2); } } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -794,15 +806,16 @@ test(1, 2); } } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart class A { void f() { print(1); print(2); } } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -818,10 +831,11 @@ Future<void> test_methodToGetter_function_startOfParameterList() async { const content = ''' int test[[]]() => 42; - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart int get test => 42; - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -837,10 +851,11 @@ Future<void> test_methodToGetter_function_startOfTypeParameterList() async { const content = ''' int test[[]]<T>() => 42; - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart int get test<T> => 42; - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -858,12 +873,13 @@ class A { int test[[]]() => 42; } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart class A { int get test => 42; } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -881,12 +897,13 @@ class A { int test[[]]<T>() => 42; } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart class A { int get test<T> => 42; } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -939,8 +956,9 @@ ); } } - '''; +'''; final expectedContent = ''' +>>>>>>>>>> lib/main.dart import 'package:flutter/material.dart'; class MyWidget extends StatelessWidget { @@ -968,7 +986,7 @@ ); } } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -986,7 +1004,7 @@ import 'dart:convert'; ^ void f() {} - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -1025,14 +1043,15 @@ print(a); print(a); } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void f() { print(1); print(1); print(1); } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -1063,8 +1082,9 @@ void bar() { print('test'); } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void foo1() { print('test'); } @@ -1076,7 +1096,7 @@ void bar() { print('test'); } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -1102,8 +1122,9 @@ void ba^r() { print('test'); } - '''; +'''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void foo1() { print('test'); } @@ -1111,7 +1132,7 @@ void foo2() { print('test'); } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize();
diff --git a/pkg/analysis_server/test/lsp/code_actions_source_test.dart b/pkg/analysis_server/test/lsp/code_actions_source_test.dart index 1547d00..c34c8a5 100644 --- a/pkg/analysis_server/test/lsp/code_actions_source_test.dart +++ b/pkg/analysis_server/test/lsp/code_actions_source_test.dart
@@ -71,6 +71,7 @@ final b = new Set<String>(); '''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart final a = Object(); final b = <String>{}; '''; @@ -102,6 +103,7 @@ } '''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void f() { const a = 'test'; } @@ -134,6 +136,7 @@ } '''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart void f() { const a = 'test'; } @@ -263,6 +266,7 @@ int? a; '''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart int? a; '''; @@ -292,6 +296,7 @@ int minified(int x, int y) => min(x, y); '''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart import 'dart:async'; import 'dart:math'; @@ -320,6 +325,7 @@ int minified(int x, int y) => min(x, y); '''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart import 'dart:async'; import 'dart:math'; @@ -489,6 +495,7 @@ String a; '''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart String a; String b; '''; @@ -510,6 +517,7 @@ String a; '''; const expectedContent = ''' +>>>>>>>>>> lib/main.dart String a; String b; ''';
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart index 4451af0..8b86110 100644 --- a/pkg/analysis_server/test/lsp/completion_dart_test.dart +++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -97,7 +97,7 @@ void f() { MyClass^ } - '''; +'''; await initializeServer(); @@ -123,7 +123,7 @@ void f() { MyClass^ } - '''; +'''; await initializeServer(); @@ -149,7 +149,7 @@ void f() { MyClass^ } - '''; +'''; await initializeServer(); @@ -173,7 +173,7 @@ void f() { MyEnum^ } - '''; +'''; await initializeServer(); @@ -210,7 +210,7 @@ void f() { enumFunc(MyEnum^) } - '''; +'''; await initializeServer(); @@ -238,7 +238,7 @@ class A {} A^ - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await provideConfig( @@ -289,7 +289,7 @@ void f() { InOtherF^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await provideConfig( @@ -385,7 +385,7 @@ @^ int a = 1; } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -402,7 +402,7 @@ class B { @^ } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -418,7 +418,7 @@ final content = ''' // foo ^ void f() {} - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -431,7 +431,7 @@ // at the end of a file would return results. final content = ''' // foo ^ - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -650,7 +650,7 @@ return const Placeholder(); } } - '''; +'''; await provideConfig( () => initialize( @@ -700,7 +700,7 @@ void f() { [[myFu^]] } - '''; +'''; await checkCompleteFunctionCallInsertText( content, @@ -717,7 +717,7 @@ void f() { [[myFu^]] } - '''; +'''; await checkCompleteFunctionCallInsertText( content, @@ -735,7 +735,7 @@ void f() { [[myFu^]] } - '''; +'''; await provideConfig( () => initialize( @@ -768,7 +768,7 @@ void f() { [[myFu^]] } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await provideConfig( @@ -814,7 +814,7 @@ // Now, we never supply `insertText` and always use `textEdit`. final content = ''' final a = Stri^ - '''; +'''; /// Helper to verify a completion is as expected. void expectCorrectCompletion(CompletionItem item) { @@ -852,7 +852,7 @@ Future<void> test_completeFunctionCalls_show() async { final content = ''' import 'dart:math' show mi^ - '''; +'''; await provideConfig( () => initialize( @@ -953,7 +953,7 @@ MyClass a; a.abc^ } - '''; +'''; // Tell the server we only support the Field CompletionItemKind. await initialize( @@ -975,7 +975,7 @@ // Brace should not trigger completion if a normal code block. final content = r''' main () {^} - '''; +'''; await _checkResultsForTriggerCharacters(content, ['{'], isEmpty); } @@ -984,7 +984,7 @@ // Brace should trigger completion if at the start of an interpolated expression final content = r''' var a = '${^'; - '''; +'''; await _checkResultsForTriggerCharacters(content, [r'{'], isNotEmpty); } @@ -992,7 +992,7 @@ // Brace should not trigger completion if in a raw string. final content = r''' var a = r'${^'; - '''; +'''; await _checkResultsForTriggerCharacters(content, [r'{'], isEmpty); } @@ -1001,7 +1001,7 @@ // expression. final content = r''' var a = '{^'; - '''; +'''; await _checkResultsForTriggerCharacters(content, [r'{'], isEmpty); } @@ -1011,7 +1011,7 @@ void f({int? a}) { f(a:^ } - '''; +'''; await _checkResultsForTriggerCharacters(content, [r':'], isNotEmpty); } @@ -1023,7 +1023,7 @@ case:^ } } - '''; +'''; await _checkResultsForTriggerCharacters(content, [r':'], isEmpty); } @@ -1035,7 +1035,7 @@ default:^ } } - '''; +'''; await _checkResultsForTriggerCharacters(content, [r':'], isEmpty); } @@ -1043,7 +1043,7 @@ // Colons should trigger completion after argument names. final content = r''' import 'package:^'; - '''; +'''; await _checkResultsForTriggerCharacters(content, [r':'], isNotEmpty); } @@ -1076,7 +1076,7 @@ // after typing 'package:foo/' completion should give the next folder segments. final content = r''' import 'package:test/^'; - '''; +'''; await _checkResultsForTriggerCharacters(content, [r'/'], isNotEmpty); } @@ -1084,7 +1084,7 @@ // Slashes should not trigger completion when typing in a normal expression. final content = r''' var a = 1 /^ - '''; +'''; await _checkResultsForTriggerCharacters(content, [r'/'], isEmpty); } @@ -1151,7 +1151,7 @@ class Student extends Person { nam^ } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -1174,7 +1174,7 @@ var x = ''; print(^); } - '''; +'''; final pluginResult = plugin.CompletionGetSuggestionsResult( content.indexOf('^'), @@ -1210,7 +1210,7 @@ void f() { ^ } - '''; +'''; final pluginResult = plugin.CompletionGetSuggestionsResult( content.indexOf('^'), @@ -1253,7 +1253,7 @@ void f() { fooFromDartIO } - ''')); +''')); } Future<void> test_fromPlugin_nonDartFile() async { @@ -1266,7 +1266,7 @@ ); query: SELECT ^ FROM foo; - '''; +'''; final pluginResult = plugin.CompletionGetSuggestionsResult( content.indexOf('^'), @@ -1304,7 +1304,7 @@ var x = ''; print(^); } - '''; +'''; final pluginResult = plugin.CompletionGetSuggestionsResult( content.indexOf('^'), @@ -1361,7 +1361,7 @@ } abstract class MyItem implements NotNullableName, NullableName {} - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -1383,7 +1383,7 @@ MyClass a; a.^ } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -1475,7 +1475,7 @@ MyClass a; a.abc^def } - '''; +'''; await initialize( textDocumentCapabilities: withCompletionItemInsertReplaceSupport( @@ -1512,7 +1512,7 @@ return const Placeholder(); } } - '''; +'''; await initialize( textDocumentCapabilities: withCompletionItemInsertTextModeSupport( @@ -1533,7 +1533,7 @@ void foo() { ^ } - '''; +'''; await initialize( textDocumentCapabilities: withCompletionItemInsertTextModeSupport( @@ -1553,7 +1553,7 @@ Future<void> test_insideString() async { final content = ''' var a = "This is ^a test" - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -1572,7 +1572,7 @@ MyClass a; a.abc^ } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -1595,7 +1595,7 @@ MyClass a; a.abc^ } - '''; +'''; await initialize( textDocumentCapabilities: withCompletionItemDeprecatedFlagSupport( @@ -1620,7 +1620,7 @@ MyClass a; a.abc^ } - '''; +'''; await initialize( textDocumentCapabilities: withCompletionItemTagSupport( @@ -1642,7 +1642,7 @@ A a = A(); a.^ } - '''; +'''; // Create a class with fields aaa1 to aaa500 in the other file. newFile( @@ -1675,7 +1675,7 @@ A a = A(); a.^ } - '''; +'''; // Create a class with fields aaa1 to aaa500 in the other file. newFile( @@ -1714,7 +1714,7 @@ void myFunction() { [[myFunctio^]] } - '''; +'''; await initialize( textDocumentCapabilities: withCompletionItemInsertReplaceSupport( @@ -1756,7 +1756,7 @@ void f(String a, {String? b}) { f([[^b]]); } - '''; +'''; await initialize( textDocumentCapabilities: withCompletionItemInsertReplaceSupport( @@ -1811,7 +1811,7 @@ return const Placeholder(); } } - '''; +'''; await initialize( textDocumentCapabilities: withCompletionItemInsertTextModeSupport( @@ -1840,7 +1840,7 @@ void f() { var a = Item^ } - '''; +'''; // Create classes `Item1` to `Item20` along with a field named `item`. // The classes will rank higher in the position above and push @@ -1886,7 +1886,7 @@ void f() { fo^ } - '''; +'''; // Create fields for1 to for20 in the other file. newFile( @@ -2077,7 +2077,7 @@ } void myFunction({String aaaa, String aaab, String aaac}) {} - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -2090,7 +2090,7 @@ class A { const A({int one}); } @A(^) void f() { } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -2114,7 +2114,7 @@ class A { const A({int one}); } @A(^) void f() { } - '''; +'''; await initialize( textDocumentCapabilities: withCompletionItemSnippetSupport( @@ -2147,7 +2147,7 @@ two: 2, ); } - '''; +'''; await initialize( textDocumentCapabilities: withCompletionItemSnippetSupport( @@ -2186,7 +2186,7 @@ void f() { fo^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize(); @@ -2205,7 +2205,7 @@ void f() { MyClass a = new MyCla^ } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -2228,7 +2228,7 @@ MyClass a; a.abc^ } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -2255,7 +2255,7 @@ // Should match only Two and Three UniqueNamedClassForLspT^ } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -2275,7 +2275,7 @@ // Should match only Two and Three UniqueNamedClassForLspT^hree } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -2295,7 +2295,7 @@ // Should match all three ^UniqueNamedClassForLspT } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -2318,7 +2318,7 @@ MyClass a; a.^ } - '''; +'''; await initialize(); await openFile(mainFileUri, withoutMarkers(content)); @@ -2353,7 +2353,7 @@ void f() { InOtherF^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -2410,7 +2410,7 @@ void f() { InOtherFile } - ''')); +''')); } Future<void> test_unimportedSymbols_dartDocPreference_full() => @@ -2460,7 +2460,7 @@ void f() { MyExported^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -2504,7 +2504,7 @@ void f() { MyExported^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -2538,7 +2538,7 @@ void f() { MyDuplicated^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -2585,7 +2585,7 @@ void f() { x(MyExported^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -2637,7 +2637,7 @@ void f() { x(MyExportedEnum.One } - ''')); +''')); } Future<void> test_unimportedSymbols_enumValuesAlreadyImported() async { @@ -2668,7 +2668,7 @@ void f() { x(MyExported^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -2712,7 +2712,7 @@ void f() { MyExported^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -2739,7 +2739,7 @@ void f() { MyClas^ } - '''; +'''; final expectedContent = ''' import 'package:test/my_class.dart'; @@ -2747,7 +2747,7 @@ void f() { MyClass } - '''; +'''; final completionLabel = 'MyClass'; @@ -2771,7 +2771,7 @@ void f() { ''.myExtensionMet^ } - '''; +'''; final expectedContent = ''' import 'package:test/my_extension.dart'; @@ -2779,7 +2779,7 @@ void f() { ''.myExtensionMethod } - '''; +'''; final completionLabel = 'myExtensionMethod()'; await _checkCompletionEdits( @@ -2815,7 +2815,7 @@ void f() { MyExported^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -2850,7 +2850,7 @@ void f() { InOtherF^il } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -2918,7 +2918,7 @@ void f() { InOtherFile } - ''')); +''')); // In insert mode, we'd have the trailing "il" still after the caret. expect(newContentInsertMode, equals(''' import '../other_file.dart'; @@ -2926,22 +2926,26 @@ void f() { InOtherFileil } - ''')); +''')); } Future<void> test_unimportedSymbols_insertsIntoPartFiles() async { // File we'll be adding an import for. newFile( join(projectFolderPath, 'other_file.dart'), - 'class InOtherFile {}', + '''' +class InOtherFile {} +''', ); // File that will have the import added. - final parentContent = '''part 'main.dart';'''; - final parentFilePath = newFile( + final parentContent = ''' +part 'main.dart'; +'''; + newFile( join(projectFolderPath, 'lib', 'parent.dart'), parentContent, - ).path; + ); // File that we're invoking completion in. final content = ''' @@ -2949,7 +2953,7 @@ void f() { InOtherF^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -2983,41 +2987,14 @@ void f() { InOtherFile } - ''')); +''')); - // Execute the associated command (which will handle edits in other files). - ApplyWorkspaceEditParams? editParams; - final commandResponse = await handleExpectedRequest<Object?, - ApplyWorkspaceEditParams, ApplyWorkspaceEditResult>( - Method.workspace_applyEdit, - ApplyWorkspaceEditParams.fromJson, - () => executeCommand(resolved.command!), - handler: (edit) { - // When the server sends the edit back, just keep a copy and say we - // applied successfully (it'll be verified below). - editParams = edit; - return ApplyWorkspaceEditResult(applied: true); - }, - ); - // Successful edits return an empty success() response. - expect(commandResponse, isNull); - - // Ensure the edit came back. - expect(editParams, isNotNull); - expect(editParams!.edit.changes, isNotNull); - - // Ensure applying the changes will give us the expected content. - final contents = { - parentFilePath: withoutMarkers(parentContent), - }; - applyChanges(contents, editParams!.edit.changes!); - - // Check the parent file was modified to include the import by the edits - // that came from the server. - expect(contents[parentFilePath], equals(''' + await verifyCommandEdits(resolved.command!, ''' +>>>>>>>>>> lib/parent.dart import '../other_file.dart'; -part 'main.dart';''')); +part 'main.dart'; +'''); } Future<void> @@ -3026,7 +3003,7 @@ void f() { InOtherF^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -3056,7 +3033,7 @@ void f() { InOtherF^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -3127,7 +3104,7 @@ void f() { var a = InOtherF^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -3168,7 +3145,7 @@ void f() { var a = InOtherFile.fromJson } - ''')); +''')); } Future<void> test_unimportedSymbols_overrides() async { @@ -3202,7 +3179,7 @@ class BaseImpl extends Base { myMet^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize( @@ -3238,7 +3215,7 @@ return super.myMethod(a, b, c); } } - ''')); +''')); } Future<void> @@ -3257,7 +3234,7 @@ void f() { MyClas^ } - '''; +'''; final expectedContent = ''' import '../nested2/imported.dart'; @@ -3265,7 +3242,7 @@ void f() { MyClass } - '''; +'''; final completionLabel = 'MyClass'; @@ -3295,7 +3272,7 @@ void f() { MyClas^ } - '''; +'''; final expectedContent = ''' import 'package:test/nested2/imported.dart'; @@ -3303,7 +3280,7 @@ void f() { MyClass } - '''; +'''; final completionLabel = 'MyClass'; @@ -3325,7 +3302,7 @@ void f() { InOtherF^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); // Support applyEdit, but explicitly disable the suggestions. @@ -3360,7 +3337,7 @@ void f() { InOtherF^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initialize(); @@ -3384,7 +3361,7 @@ MyClass a; a.abc^ } - '''; +'''; newFile(mainFilePath, withoutMarkers(content)); await initialize(); @@ -3533,7 +3510,7 @@ void f() { ^ } - '''; +'''; final initialAnalysis = waitForAnalysisComplete(); await initializeWithSnippetSupport();
diff --git a/pkg/analysis_server/test/lsp/rename_test.dart b/pkg/analysis_server/test/lsp/rename_test.dart index 973e6ce..7ba81a2 100644 --- a/pkg/analysis_server/test/lsp/rename_test.dart +++ b/pkg/analysis_server/test/lsp/rename_test.dart
@@ -281,9 +281,11 @@ withResourceOperationKinds(emptyWorkspaceClientCapabilities, [ResourceOperationKind.Rename])), ); - // Ensure we now only have the newly-renamed file and not the old one - // (its contents will have been checked by the function above). - expect(contents.keys.single, equals(newMainFilePath)); + + expect(contents, hasLength(2)); + expect(contents[newMainFilePath], expectedContent); + expect(contents.containsKey(mainFilePath), isTrue); + expect(contents[mainFilePath], isNull); // Deleted (renamed) } /// Helper that will respond to the window/showMessageRequest request from @@ -337,9 +339,11 @@ withResourceOperationKinds(emptyWorkspaceClientCapabilities, [ResourceOperationKind.Rename])), ); - // Ensure we now only have the newly-renamed file and not the old one - // (its contents will have been checked by the function above). - expect(contents.keys.single, equals(newMainFilePath)); + + expect(contents, hasLength(2)); + expect(contents[newMainFilePath], expectedContent); + expect(contents.containsKey(mainFilePath), isTrue); + expect(contents[mainFilePath], isNull); // Deleted (renamed) }, {'renameFilesWithClasses': 'always'}, ); @@ -387,9 +391,8 @@ ); // Expect that main was renamed to my_new_main and the other file was // updated. - expect(contents.containsKey(mainFilePath), isFalse); - expect(contents.containsKey(newMainFilePath), isTrue); - expect(contents.containsKey(otherFilePath), isTrue); + expect(contents.containsKey(mainFilePath), isTrue); + expect(contents[mainFilePath], isNull); // Deleted (renamed) expect(contents[newMainFilePath], expectedContent); expect(contents[otherFilePath], expectedOtherContent); }, @@ -1013,7 +1016,7 @@ ); } - Future<Map<String, String>> _test_rename_withDocumentChanges( + Future<Map<String, String?>> _test_rename_withDocumentChanges( String content, String newName, String? expectedContent, { @@ -1022,7 +1025,7 @@ bool sendRenameVersion = true, WorkspaceClientCapabilities? workspaceCapabilities, bool supportsWindowShowMessageRequest = true, - Map<String, String>? contents, + Map<String, String?>? contents, }) async { contents ??= {}; filePath ??= mainFilePath;
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart index 2bfda56..2262c1c 100644 --- a/pkg/analysis_server/test/lsp/server_abstract.dart +++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -101,10 +101,99 @@ return info; } + /// Executes [command] which is expected to call back to the client to apply + /// a [WorkspaceEdit]. + /// + /// Changes are applied to [contents] to be verified by the caller. + Future<void> executeCommandForEdits( + Command command, + Map<String, String?> contents, { + bool expectDocumentChanges = false, + ProgressToken? workDoneToken, + }) async { + ApplyWorkspaceEditParams? editParams; + + final commandResponse = await handleExpectedRequest<Object?, + ApplyWorkspaceEditParams, ApplyWorkspaceEditResult>( + Method.workspace_applyEdit, + ApplyWorkspaceEditParams.fromJson, + () => executeCommand(command, workDoneToken: workDoneToken), + handler: (edit) { + // When the server sends the edit back, just keep a copy and say we + // applied successfully (it'll be verified by the caller). + editParams = edit; + return ApplyWorkspaceEditResult(applied: true); + }, + ); + // Successful edits return an empty success() response. + expect(commandResponse, isNull); + + // Ensure the edit came back, and using the expected change type. + expect(editParams, isNotNull); + final edit = editParams!.edit; + if (expectDocumentChanges) { + expect(edit.changes, isNull); + expect(edit.documentChanges, isNotNull); + applyDocumentChanges(contents, edit.documentChanges!); + } else { + expect(edit.changes, isNotNull); + expect(edit.documentChanges, isNull); + applyChanges(contents, edit.changes!); + } + } + + void expectChanges(Map<Uri, List<TextEdit>> changes, String expected) { + final editedContents = <String, String?>{}; + applyChanges(editedContents, changes); + expectEditedContent(editedContents, expected); + } + void expectContextBuilds() => expect(server.contextBuilds - _previousContextBuilds, greaterThan(0), reason: 'Contexts should have been rebuilt'); + Map<String, String?> expectDocumentChanges( + List<Either4<CreateFile, DeleteFile, RenameFile, TextDocumentEdit>> changes, + String expected, + ) { + final editedContents = <String, String?>{}; + applyDocumentChanges(editedContents, changes); + expectEditedContent(editedContents, expected); + return editedContents; + } + + void expectEditedContent( + Map<String, String?> editedContents, String expected) { + final buffer = StringBuffer(); + for (final entry in editedContents.entries.sortedBy((entry) => entry.key)) { + // Write the path in a common format for Windows/non-Windows. + final relativePath = path + .relative( + entry.key, + from: projectFolderPath, + ) + .replaceAll(r'\', '/'); + final content = entry.value; + // TODO(dantup): Extract this (and the applying of edits) to a class + // that can also update the test expectations, and record renames better + // than just a delete/create. + if (content == null) { + buffer.write('>>>>>>>>>> $relativePath deleted\n'); + } else if (content.trim().isEmpty) { + buffer.write('>>>>>>>>>> $relativePath empty\n'); + } else { + buffer.write('>>>>>>>>>> $relativePath\n$content'); + // If the content didn't end with a newline we need to add one, but + // add a marked so it's clear there was no trailing newline. + if (!content.endsWith('\n')) { + buffer.write('<<<<<<<<<<\n'); + } + } + } + + expect(buffer.toString().trim(), equals(expected.trim())); + } + void expectNoContextBuilds() => expect(server.contextBuilds - _previousContextBuilds, equals(0), reason: 'Contexts should not have been rebuilt'); @@ -124,6 +213,17 @@ } } + @override + String? getCurrentFileContent(Uri uri) { + try { + return server.resourceProvider + .getFile(uri.toFilePath()) + .readAsStringSync(); + } catch (_) { + return null; + } + } + /// Finds the registration for a given LSP method. Registration? registrationFor( List<Registration> registrations, @@ -239,6 +339,27 @@ await server.shutdown(); } + /// Verifies that executing the given command on the server results in an edit + /// being sent in the client that updates the files to match the expected + /// content. + Future<void> verifyCommandEdits( + Command command, + String expectedContent, { + bool expectDocumentChanges = false, + ProgressToken? workDoneToken, + }) async { + final contents = <String, String?>{}; + + await executeCommandForEdits( + command, + contents, + expectDocumentChanges: expectDocumentChanges, + workDoneToken: workDoneToken, + ); + + expectEditedContent(contents, expectedContent); + } + /// Adds a trailing slash (direction based on path context) to [path]. /// /// Throws if the path already has a trailing slash. @@ -771,17 +892,20 @@ Stream<Message> get serverToClient; void applyChanges( - Map<String, String> fileContents, + Map<String, String?> editedContents, Map<Uri, List<TextEdit>> changes, ) { changes.forEach((fileUri, edits) { - final path = fileUri.toFilePath(); - fileContents[path] = applyTextEdits(fileContents[path]!, edits); + final filePath = fileUri.toFilePath(); + final currentContent = editedContents.containsKey(filePath) + ? editedContents[filePath] + : getCurrentFileContent(fileUri); + editedContents[filePath] = applyTextEdits(currentContent!, edits); }); } void applyDocumentChanges( - Map<String, String> fileContents, + Map<String, String?> editedContent, List<Either4<CreateFile, DeleteFile, RenameFile, TextDocumentEdit>> documentChanges, { Map<String, int>? expectedVersions, @@ -791,41 +915,72 @@ if (expectedVersions != null) { expectDocumentVersions(documentChanges, expectedVersions); } - applyResourceChanges(fileContents, documentChanges); + applyResourceChanges(editedContent, documentChanges); } void applyResourceChanges( - Map<String, String> oldFileContent, + Map<String, String?> editedContent, List<Either4<CreateFile, DeleteFile, RenameFile, TextDocumentEdit>> changes, ) { for (final change in changes) { change.map( - (create) => applyResourceCreate(oldFileContent, create), - (delete) => throw 'applyResourceChanges:Delete not currently supported', - (rename) => applyResourceRename(oldFileContent, rename), - (textDocEdit) => applyTextDocumentEdits(oldFileContent, [textDocEdit]), + (create) => applyResourceCreate(editedContent, create), + (delete) => applyResourceDelete(editedContent, delete), + (rename) => applyResourceRename(editedContent, rename), + (textDocEdit) => applyTextDocumentEdits(editedContent, [textDocEdit]), ); } } void applyResourceCreate( - Map<String, String> oldFileContent, CreateFile create) { - final path = create.uri.toFilePath(); - if (oldFileContent.containsKey(path)) { - throw 'Received create instruction for $path which already existed.'; + Map<String, String?> editedContent, CreateFile create) { + final uri = create.uri; + final path = uri.toFilePath(); + final currentContent = editedContent.containsKey(path) + ? editedContent[path] + : getCurrentFileContent(uri); + if (currentContent != null) { + throw 'Received create instruction for $path which already exists'; } - oldFileContent[path] = ''; + editedContent[path] = ''; + } + + void applyResourceDelete( + Map<String, String?> editedContent, DeleteFile delete) { + final uri = delete.uri; + final path = uri.toFilePath(); + final currentContent = editedContent.containsKey(path) + ? editedContent[path] + : getCurrentFileContent(uri); + + if (currentContent == null) { + throw 'Received delete instruction for $path which does not exist'; + } + + editedContent[path] = null; } void applyResourceRename( - Map<String, String> oldFileContent, RenameFile rename) { - final oldPath = rename.oldUri.toFilePath(); - final newPath = rename.newUri.toFilePath(); - if (!oldFileContent.containsKey(oldPath)) { - throw 'Received rename instruction for $oldPath which did not exist.'; + Map<String, String?> editedContent, RenameFile rename) { + final oldUri = rename.oldUri; + final newUri = rename.newUri; + final oldPath = oldUri.toFilePath(); + final newPath = newUri.toFilePath(); + + final oldContent = editedContent.containsKey(oldPath) + ? editedContent[oldPath] + : getCurrentFileContent(oldUri); + final newContent = editedContent.containsKey(newPath) + ? editedContent[newPath] + : getCurrentFileContent(newUri); + + if (oldContent == null) { + throw 'Received rename instruction from $oldPath which did not exist'; + } else if (newContent != null) { + throw 'Received rename instruction to $newPath which already exists'; } - oldFileContent[newPath] = oldFileContent[oldPath]!; - oldFileContent.remove(oldPath); + editedContent[newPath] = oldContent; + editedContent[oldPath] = null; } String applyTextDocumentEdit(String content, TextDocumentEdit edit) { @@ -843,14 +998,19 @@ } void applyTextDocumentEdits( - Map<String, String> oldFileContent, List<TextDocumentEdit> edits) { + Map<String, String?> editedContent, List<TextDocumentEdit> edits) { for (var edit in edits) { - final path = edit.textDocument.uri.toFilePath(); - if (!oldFileContent.containsKey(path)) { - throw 'Received edits for $path which was not provided as a file to be edited. ' + final uri = edit.textDocument.uri; + final path = uri.toFilePath(); + + final currentContent = editedContent.containsKey(path) + ? editedContent[path] + : getCurrentFileContent(uri); + if (currentContent == null) { + throw 'Received edits for $path which does not exist. ' 'Perhaps a CreateFile change was missing from the edits?'; } - oldFileContent[path] = applyTextDocumentEdit(oldFileContent[path]!, edit); + editedContent[path] = applyTextDocumentEdit(currentContent, edit); } } @@ -1202,6 +1362,13 @@ return expectSuccessfulResponseTo(request, CompletionList.fromJson); } + /// Gets the current contents of a file. + /// + /// This is used to apply edits when the server sends workspace/applyEdit. It + /// should reflect the content that the client would have in this case, which + /// would be an overlay (if the file is open) or the underlying file. + String? getCurrentFileContent(Uri uri); + Future<Either2<List<Location>, List<LocationLink>>> getDefinition( Uri uri, Position pos) { final request = makeRequest(
diff --git a/pkg/analysis_server/test/src/services/refactoring/convert_all_formal_parameters_to_named_test.dart b/pkg/analysis_server/test/src/services/refactoring/convert_all_formal_parameters_to_named_test.dart index 41adfbd..7397aa0 100644 --- a/pkg/analysis_server/test/src/services/refactoring/convert_all_formal_parameters_to_named_test.dart +++ b/pkg/analysis_server/test/src/services/refactoring/convert_all_formal_parameters_to_named_test.dart
@@ -27,7 +27,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({required int? a}) {} void f() { @@ -45,7 +46,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({required int a}) {} void f() { @@ -63,7 +65,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({required int? a}) {} void f() { @@ -81,7 +84,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({required int a}) {} void f() { @@ -93,7 +97,7 @@ Future<void> test_multiple_files() async { // TODO(scheglov) Unify behind `testPackageLibPath` final a = getFile('$projectFolderPath/lib/a.dart'); - addSource(a.path, r''' + newFile(a.path, r''' import 'main.dart'; void f2() { @@ -109,33 +113,19 @@ } '''); - await _executeRefactoring(r''' -void test({required int a}) {} - -void f() { - test(a: 0); -} -'''); - - // TODO(scheglov) Ask me, if you want more of this opinion. - // This is bad code. - // I don't like using content for verifying refactoring results. - // We need to check all changes, without a way to check only some portion. - // See how _writeSourceChangeToBuffer is done. - // - // And addSource() above is another hack that we rely on to support these - // checks here. - // I don't like these too. - // We have newFile() already, this should be enough. - // Don't invent more way to add files. - // I worked hard in DAS legacy tests to get away from it. - // Don't add them back. - assertTextExpectation(content[a.path]!, r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/a.dart import 'main.dart'; void f2() { test(a: 1); } +>>>>>>>>>> lib/main.dart +void test({required int a}) {} + +void f() { + test(a: 0); +} '''); } @@ -168,7 +158,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({required int a}) {} void f() { @@ -186,7 +177,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({required int a}) {} void f() { @@ -195,23 +187,22 @@ '''); } - Future<void> _assertNoRefactoring() async { - await initializeServer(); - - await expectNoCodeAction( - ConvertAllFormalParametersToNamed.constTitle, - ); - } - - Future<void> _executeRefactoring(String expected) async { + Future<void> verifyRefactoring(String expected) async { await initializeServer(); final codeAction = await expectCodeAction( ConvertAllFormalParametersToNamed.constTitle, ); - await executeRefactor(codeAction); + await verifyCommandEdits(codeAction.command!, expected, + expectDocumentChanges: true); + } - assertTextExpectation(content[mainFilePath]!, expected); + Future<void> _assertNoRefactoring() async { + await initializeServer(); + + await expectNoCodeAction( + ConvertAllFormalParametersToNamed.constTitle, + ); } }
diff --git a/pkg/analysis_server/test/src/services/refactoring/convert_selected_formal_parameters_to_named_test.dart b/pkg/analysis_server/test/src/services/refactoring/convert_selected_formal_parameters_to_named_test.dart index ed69b2d..0814dea 100644 --- a/pkg/analysis_server/test/src/services/refactoring/convert_selected_formal_parameters_to_named_test.dart +++ b/pkg/analysis_server/test/src/services/refactoring/convert_selected_formal_parameters_to_named_test.dart
@@ -28,7 +28,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({int a, required int b, required int c, int d}) {} void f() { @@ -46,7 +47,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int a, {required int b, required int c}) {} void f() { @@ -93,7 +95,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int a, int d, {required int b, required int c}) {} void f() { @@ -111,7 +114,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int a, {required int b}) {} void f() { @@ -129,7 +133,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int a, {required int b, int c}) {} void f() { @@ -147,7 +152,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int a, {required int? b}) {} void f() { @@ -189,7 +195,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int b, {required int a}) {} void f() { @@ -207,7 +214,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int a, {required int b}) {} void f() { @@ -225,7 +233,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int a, int c, {required int b}) {} void f() { @@ -245,7 +254,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({ required int b, required int a, @@ -269,23 +279,22 @@ await _assertNoRefactoring(); } - Future<void> _assertNoRefactoring() async { - await initializeServer(); - - await expectNoCodeAction( - ConvertSelectedFormalParametersToNamed.constTitle, - ); - } - - Future<void> _executeRefactoring(String expected) async { + Future<void> verifyRefactoring(String expected) async { await initializeServer(); final codeAction = await expectCodeAction( ConvertSelectedFormalParametersToNamed.constTitle, ); - await executeRefactor(codeAction); + await verifyCommandEdits(codeAction.command!, expected, + expectDocumentChanges: true); + } - assertTextExpectation(content[mainFilePath]!, expected); + Future<void> _assertNoRefactoring() async { + await initializeServer(); + + await expectNoCodeAction( + ConvertSelectedFormalParametersToNamed.constTitle, + ); } }
diff --git a/pkg/analysis_server/test/src/services/refactoring/move_selected_formal_parameters_left_test.dart b/pkg/analysis_server/test/src/services/refactoring/move_selected_formal_parameters_left_test.dart index 504b820..366061b 100644 --- a/pkg/analysis_server/test/src/services/refactoring/move_selected_formal_parameters_left_test.dart +++ b/pkg/analysis_server/test/src/services/refactoring/move_selected_formal_parameters_left_test.dart
@@ -49,7 +49,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({ required int b, required int c, @@ -84,7 +85,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int a, int c, int d, int b, int e) {} void f() { @@ -102,7 +104,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int b, int c, int a, int d) {} void f() { @@ -124,7 +127,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({ int? b, int? a, @@ -150,7 +154,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({ int? b, required int? a, @@ -184,7 +189,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test([int b, int a, int c]) {} void f() { @@ -237,7 +243,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({ required int a, required int c, @@ -264,7 +271,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({ required int a, required int c, @@ -291,7 +299,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test({ required int b, required int a, @@ -325,7 +334,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int a, int c, int b) {} void f() { @@ -343,7 +353,8 @@ } '''); - await _executeRefactoring(r''' + await verifyRefactoring(r''' +>>>>>>>>>> lib/main.dart void test(int b, int a, int c) {} void f() { @@ -352,23 +363,22 @@ '''); } - Future<void> _assertNoRefactoring() async { - await initializeServer(); - - await expectNoCodeAction( - MoveSelectedFormalParametersLeft.constTitle, - ); - } - - Future<void> _executeRefactoring(String expected) async { + Future<void> verifyRefactoring(String expected) async { await initializeServer(); final codeAction = await expectCodeAction( MoveSelectedFormalParametersLeft.constTitle, ); - await executeRefactor(codeAction); + await verifyCommandEdits(codeAction.command!, expected, + expectDocumentChanges: true); + } - assertTextExpectation(content[mainFilePath]!, expected); + Future<void> _assertNoRefactoring() async { + await initializeServer(); + + await expectNoCodeAction( + MoveSelectedFormalParametersLeft.constTitle, + ); } }
diff --git a/pkg/analysis_server/test/src/services/refactoring/move_top_level_to_file_test.dart b/pkg/analysis_server/test/src/services/refactoring/move_top_level_to_file_test.dart index 9a8a252..1f7b1dc 100644 --- a/pkg/analysis_server/test/src/services/refactoring/move_top_level_to_file_test.dart +++ b/pkg/analysis_server/test/src/services/refactoring/move_top_level_to_file_test.dart
@@ -5,7 +5,6 @@ import 'package:analysis_server/lsp_protocol/protocol.dart'; import 'package:analysis_server/src/services/refactoring/move_top_level_to_file.dart'; import 'package:analyzer/src/test_utilities/test_code_format.dart'; -import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; import 'refactoring_test_support.dart'; @@ -40,10 +39,10 @@ /// Test that references to getter/setters in different libraries used in /// a compound assignment are both imported into the destination file. Future<void> test_compoundAssignment_multipleLibraries() async { - addSource('$projectFolderPath/lib/getter.dart', ''' + newFile('$projectFolderPath/lib/getter.dart', ''' int get splitVariable => 0; '''); - addSource('$projectFolderPath/lib/setter.dart', ''' + newFile('$projectFolderPath/lib/setter.dart', ''' set splitVariable(num _) {} '''); @@ -55,26 +54,26 @@ splitVariable += 1; } '''; - var modifiedSource = ''' -import 'package:test/getter.dart'; -import 'package:test/setter.dart'; -'''; var declarationName = 'functionToMove'; - var newFileName = 'function_to_move.dart'; - var newFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/function_to_move.dart import 'package:test/getter.dart'; import 'package:test/setter.dart'; void functionToMove() { splitVariable += 1; } +>>>>>>>>>> lib/main.dart +import 'package:test/getter.dart'; +import 'package:test/setter.dart'; + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_copyFileHeader() async { @@ -87,26 +86,25 @@ class B {} '''; - var modifiedSource = ''' + var declarationName = 'ClassToMove'; + + var expected = ''' +>>>>>>>>>> lib/class_to_move.dart +// File header. + +class ClassToMove {} +>>>>>>>>>> lib/main.dart // File header. class A {} class B {} '''; - var declarationName = 'ClassToMove'; - var newFileName = 'class_to_move.dart'; - var newFileContent = ''' -// File header. - -class ClassToMove {} -'''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_existingFile() async { @@ -114,22 +112,23 @@ /// Existing new file contents where 'ClassToMove' will be moved to. final newFilePath = join(projectFolderPath, 'lib', 'a.dart'); - addSource(newFilePath, ''' + newFile(newFilePath, ''' int? a; '''); /// Expected updated new file contents. - const expectedNewFileContent = ''' + const expected = ''' +>>>>>>>>>> lib/a.dart int? a; class A {} +>>>>>>>>>> lib/main.dart empty '''; await initializeServer(); final action = await expectCodeAction(simpleClassRefactorTitle); - await executeRefactor(action); - - expect(content[newFilePath], expectedNewFileContent); + await verifyCommandEdits(action.command!, expected, + expectDocumentChanges: true); } Future<void> test_existingFile_withHeader() async { @@ -137,26 +136,27 @@ /// Existing new file contents where 'ClassToMove' will be moved to. final newFilePath = join(projectFolderPath, 'lib', 'a.dart'); - addSource(newFilePath, ''' + newFile(newFilePath, ''' // This is a file header int? a; '''); /// Expected updated new file contents. - const expectedNewFileContent = ''' + const expected = ''' +>>>>>>>>>> lib/a.dart // This is a file header int? a; class A {} +>>>>>>>>>> lib/main.dart empty '''; await initializeServer(); final action = await expectCodeAction(simpleClassRefactorTitle); - await executeRefactor(action); - - expect(content[newFilePath], expectedNewFileContent); + await verifyCommandEdits(action.command!, expected, + expectDocumentChanges: true); } Future<void> test_existingFile_withImports() async { @@ -164,57 +164,58 @@ /// Existing new file contents where 'ClassToMove' will be moved to. final newFilePath = join(projectFolderPath, 'lib', 'a.dart'); - addSource(newFilePath, ''' + newFile(newFilePath, ''' import 'dart:async'; FutureOr<int>? a; '''); /// Expected updated new file contents. - const expectedNewFileContent = ''' + const expected = ''' +>>>>>>>>>> lib/a.dart import 'dart:async'; FutureOr<int>? a; class A {} +>>>>>>>>>> lib/main.dart empty '''; await initializeServer(); final action = await expectCodeAction(simpleClassRefactorTitle); - await executeRefactor(action); - - expect(content[newFilePath], expectedNewFileContent); + await verifyCommandEdits(action.command!, expected, + expectDocumentChanges: true); } Future<void> test_imports_declarationInSrc() async { var libFilePath = join(projectFolderPath, 'lib', 'a.dart'); var srcFilePath = join(projectFolderPath, 'lib', 'src', 'a.dart'); - addSource(libFilePath, 'export "src/a.dart";'); - addSource(srcFilePath, 'class A {}'); + newFile(libFilePath, 'export "src/a.dart";'); + newFile(srcFilePath, 'class A {}'); var originalSource = ''' import 'package:test/a.dart'; A? staying; A? mov^ing; '''; - var modifiedSource = ''' + var declarationName = 'moving'; + + var expected = ''' +>>>>>>>>>> lib/main.dart import 'package:test/a.dart'; A? staying; -'''; - var declarationName = 'moving'; - var newFileName = 'moving.dart'; - var newFileContent = ''' +>>>>>>>>>> lib/moving.dart import 'package:test/a.dart'; A? moving; + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_imports_extensionMethod() async { @@ -236,28 +237,26 @@ A().extensionMethod(); } '''; - var modifiedSource = ''' -import 'package:test/extensions.dart'; - -class A {} -'''; var declarationName = 'f'; - var newFileName = 'f.dart'; - var newFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/f.dart import 'package:test/extensions.dart'; import 'package:test/main.dart'; void f() { A().extensionMethod(); } +>>>>>>>>>> lib/main.dart +import 'package:test/extensions.dart'; + +class A {} '''; await _singleDeclaration( originalSource: originalSource, - modifiedSource: modifiedSource, + expected: expected, declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent, otherFilePath: otherFilePath, otherFileContent: otherFileContent); } @@ -281,28 +280,26 @@ A() + A(); } '''; - var modifiedSource = ''' -import 'package:test/extensions.dart'; - -class A {} -'''; var declarationName = 'f'; - var newFileName = 'f.dart'; - var newFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/f.dart import 'package:test/extensions.dart'; import 'package:test/main.dart'; void f() { A() + A(); } +>>>>>>>>>> lib/main.dart +import 'package:test/extensions.dart'; + +class A {} '''; await _singleDeclaration( originalSource: originalSource, - modifiedSource: modifiedSource, + expected: expected, declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent, otherFilePath: otherFilePath, otherFileContent: otherFileContent); } @@ -457,27 +454,26 @@ A().extensionMethod(); } '''; - var modifiedSource = ''' + var movingDeclarationName = 'moving'; + + var expected = ''' +>>>>>>>>>> lib/main.dart import 'package:test/extensions.dart' as other; class A {} -'''; - var movingDeclarationName = 'moving'; - var newFileName = 'moving.dart'; - var newFileContent = ''' +>>>>>>>>>> lib/moving.dart import 'package:test/extensions.dart' as other; import 'package:test/main.dart'; void moving() { A().extensionMethod(); } + '''; await _singleDeclaration( originalSource: originalSource, - modifiedSource: modifiedSource, + expected: expected, declarationName: movingDeclarationName, - newFileName: newFileName, - newFileContent: newFileContent, otherFilePath: otherFilePath, otherFileContent: otherFileContent); } @@ -501,27 +497,26 @@ A() + A(); } '''; - var modifiedSource = ''' + var movingDeclarationName = 'moving'; + + var expected = ''' +>>>>>>>>>> lib/main.dart import 'package:test/extensions.dart' as other; class A {} -'''; - var movingDeclarationName = 'moving'; - var newFileName = 'moving.dart'; - var newFileContent = ''' +>>>>>>>>>> lib/moving.dart import 'package:test/extensions.dart' as other; import 'package:test/main.dart'; void moving() { A() + A(); } + '''; await _singleDeclaration( originalSource: originalSource, - modifiedSource: modifiedSource, + expected: expected, declarationName: movingDeclarationName, - newFileName: newFileName, - newFileContent: newFileContent, otherFilePath: otherFilePath, otherFileContent: otherFileContent); } @@ -757,26 +752,27 @@ File? f; } '''; - var modifiedSource = ''' -import 'dart:io'; - -class A {} -'''; var declarationName = 'B'; - var newFileName = 'b.dart'; - var newFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/b.dart import 'dart:io'; class B { File? f; } +>>>>>>>>>> lib/main.dart +import 'dart:io'; + +class A {} + + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_imports_referenceFromMovingToStaying() async { @@ -785,22 +781,23 @@ class ClassToMove^ extends A {} '''; - var modifiedSource = ''' -class A {} -'''; var declarationName = 'ClassToMove'; - var newFileName = 'class_to_move.dart'; - var newFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/class_to_move.dart import 'package:test/main.dart'; class ClassToMove extends A {} +>>>>>>>>>> lib/main.dart +class A {} + + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_imports_referenceFromStayingToMoving() async { @@ -809,22 +806,22 @@ class B^ {} '''; - var modifiedSource = ''' + var declarationName = 'B'; + + var expected = ''' +>>>>>>>>>> lib/b.dart +class B {} +>>>>>>>>>> lib/main.dart import 'package:test/b.dart'; class A extends B {} -'''; - var declarationName = 'B'; - var newFileName = 'b.dart'; - var newFileContent = ''' -class B {} + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_imports_referenceInThirdFile_noPrefix() async { @@ -833,35 +830,34 @@ class B^ {} '''; - var modifiedSource = ''' -class A {} -'''; var declarationName = 'B'; - var newFileName = 'b.dart'; - var newFileContent = ''' -class B {} -'''; var otherFilePath = '$projectFolderPath/lib/c.dart'; var otherFileContent = ''' import 'package:test/main.dart'; B? b; '''; - var modifiedOtherFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/b.dart +class B {} +>>>>>>>>>> lib/c.dart import 'package:test/b.dart'; import 'package:test/main.dart'; B? b; +>>>>>>>>>> lib/main.dart +class A {} + + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent, - otherFilePath: otherFilePath, - otherFileContent: otherFileContent, - modifiedOtherFileContent: modifiedOtherFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + otherFilePath: otherFilePath, + otherFileContent: otherFileContent, + ); } Future<void> test_imports_referenceInThirdFile_withMultiplePrefixes() async { @@ -870,14 +866,7 @@ class B^ {} '''; - var modifiedSource = ''' -class A {} -'''; var declarationName = 'B'; - var newFileName = 'b.dart'; - var newFileContent = ''' -class B {} -'''; var otherFilePath = '$projectFolderPath/lib/c.dart'; var otherFileContent = ''' import 'package:test/main.dart'; @@ -886,7 +875,11 @@ void f(p.B b, q.B b, B b) {} '''; - var modifiedOtherFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/b.dart +class B {} +>>>>>>>>>> lib/c.dart import 'package:test/b.dart'; import 'package:test/b.dart' as p; import 'package:test/b.dart' as q; @@ -895,16 +888,18 @@ import 'package:test/main.dart' as q; void f(p.B b, q.B b, B b) {} +>>>>>>>>>> lib/main.dart +class A {} + + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent, - otherFilePath: otherFilePath, - otherFileContent: otherFileContent, - modifiedOtherFileContent: modifiedOtherFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + otherFilePath: otherFilePath, + otherFileContent: otherFileContent, + ); } Future<void> test_imports_referenceInThirdFile_withSinglePrefix() async { @@ -913,35 +908,34 @@ class B^ {} '''; - var modifiedSource = ''' -class A {} -'''; var declarationName = 'B'; - var newFileName = 'b.dart'; - var newFileContent = ''' -class B {} -'''; var otherFilePath = '$projectFolderPath/lib/c.dart'; var otherFileContent = ''' import 'package:test/main.dart' as p; p.B? b; '''; - var modifiedOtherFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/b.dart +class B {} +>>>>>>>>>> lib/c.dart import 'package:test/b.dart' as p; import 'package:test/main.dart' as p; p.B? b; +>>>>>>>>>> lib/main.dart +class A {} + + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent, - otherFilePath: otherFilePath, - otherFileContent: otherFileContent, - modifiedOtherFileContent: modifiedOtherFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + otherFilePath: otherFilePath, + otherFileContent: otherFileContent, + ); } /// Test moving declarations to a file that imports a library that exports a @@ -952,9 +946,9 @@ var destinationFileName = 'moving.dart'; var destinationFilePath = join(projectFolderPath, 'lib', destinationFileName); - addSource(libFilePath, 'export "src/a.dart";'); - addSource(srcFilePath, 'class A {}'); - addSource(destinationFilePath, ''' + newFile(libFilePath, 'export "src/a.dart";'); + newFile(srcFilePath, 'class A {}'); + newFile(destinationFilePath, ''' import 'package:test/a.dart' hide A; '''); var originalSource = ''' @@ -963,25 +957,25 @@ A? staying; A? mov^ing; '''; - var modifiedSource = ''' + var declarationName = 'moving'; + + var expected = ''' +>>>>>>>>>> lib/main.dart import 'package:test/a.dart'; A? staying; -'''; - var declarationName = 'moving'; - - var expectedDestinationContent = ''' +>>>>>>>>>> lib/moving.dart import 'package:test/a.dart' hide A; import 'package:test/a.dart'; A? moving; + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: destinationFileName, - newFileContent: expectedDestinationContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } /// Test moving declarations to a file that imports a library that exports a @@ -992,9 +986,9 @@ var destinationFileName = 'moving.dart'; var destinationFilePath = join(projectFolderPath, 'lib', destinationFileName); - addSource(libFilePath, 'export "src/a.dart";'); - addSource(srcFilePath, 'class A {}'); - addSource(destinationFilePath, ''' + newFile(libFilePath, 'export "src/a.dart";'); + newFile(srcFilePath, 'class A {}'); + newFile(destinationFilePath, ''' import 'package:test/a.dart' hide A; '''); var originalSource = ''' @@ -1003,25 +997,25 @@ A? staying; A? mov^ing; '''; - var modifiedSource = ''' + var declarationName = 'moving'; + + var expected = ''' +>>>>>>>>>> lib/main.dart import 'package:test/a.dart' show A; A? staying; -'''; - var declarationName = 'moving'; - - var expectedDestinationContent = ''' +>>>>>>>>>> lib/moving.dart import 'package:test/a.dart' hide A; import 'package:test/a.dart' show A; A? moving; + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: destinationFileName, - newFileContent: expectedDestinationContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } /// Test that if the moving declaration was imported with 'show' that any new @@ -1029,32 +1023,32 @@ Future<void> test_imports_showHide_sourceShows() async { var libFilePath = join(projectFolderPath, 'lib', 'a.dart'); var srcFilePath = join(projectFolderPath, 'lib', 'src', 'a.dart'); - addSource(libFilePath, 'export "src/a.dart";'); - addSource(srcFilePath, 'class A {}'); + newFile(libFilePath, 'export "src/a.dart";'); + newFile(srcFilePath, 'class A {}'); var originalSource = ''' import 'package:test/a.dart' show A; A? staying; A? mov^ing; '''; - var modifiedSource = ''' + var declarationName = 'moving'; + + var expected = ''' +>>>>>>>>>> lib/main.dart import 'package:test/a.dart' show A; A? staying; -'''; - var declarationName = 'moving'; - var newFileName = 'moving.dart'; - var newFileContent = ''' +>>>>>>>>>> lib/moving.dart import 'package:test/a.dart' show A; A? moving; + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_kind_class() async { @@ -1065,22 +1059,22 @@ class B {} '''; - var modifiedSource = ''' + var declarationName = 'ClassToMove'; + + var expected = ''' +>>>>>>>>>> lib/class_to_move.dart +class ClassToMove {} +>>>>>>>>>> lib/main.dart class A {} class B {} -'''; - var declarationName = 'ClassToMove'; - var newFileName = 'class_to_move.dart'; - var newFileContent = ''' -class ClassToMove {} + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_logsAction() async { @@ -1102,23 +1096,23 @@ class B {} '''; - var modifiedSource = ''' -class A {} -class B {} -'''; - var newFileName = 'class_to_move1.dart'; - var newFileContent = ''' + var expected = ''' +>>>>>>>>>> lib/class_to_move1.dart class ClassToMove1 {} class ClassToMove2 {} +>>>>>>>>>> lib/main.dart +class A {} + +class B {} + '''; await _multipleDeclarations( - originalSource: originalSource, - modifiedSource: modifiedSource, - count: 2, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + count: 2, + ); } Future<void> test_none_comment() async { @@ -1126,6 +1120,7 @@ // Comm^ent class A {} + '''); await initializeServer(experimentalOptInFlag: false); await expectNoCodeAction(null); @@ -1136,6 +1131,7 @@ imp^ort 'dart:core'; class A {} + '''); await initializeServer(experimentalOptInFlag: false); await expectNoCodeAction(null); @@ -1144,12 +1140,12 @@ /// Test that references to getter/setters in different libraries used in /// a postfix increment are both imported into the destination file. Future<void> test_postfixIncrement_multipleLibraries() async { - addSource('$projectFolderPath/lib/getter.dart', ''' -int get splitVariable => 0; -'''); - addSource('$projectFolderPath/lib/setter.dart', ''' -set splitVariable(num _) {} -'''); + newFile('$projectFolderPath/lib/getter.dart', ''' + int get splitVariable => 0; + '''); + newFile('$projectFolderPath/lib/setter.dart', ''' + set splitVariable(num _) {} + '''); var originalSource = ''' import 'package:test/getter.dart'; @@ -1159,26 +1155,26 @@ splitVariable++; } '''; - var modifiedSource = ''' -import 'package:test/getter.dart'; -import 'package:test/setter.dart'; -'''; var declarationName = 'functionToMove'; - var newFileName = 'function_to_move.dart'; - var newFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/function_to_move.dart import 'package:test/getter.dart'; import 'package:test/setter.dart'; void functionToMove() { splitVariable++; } +>>>>>>>>>> lib/main.dart +import 'package:test/getter.dart'; +import 'package:test/setter.dart'; + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> @@ -1211,7 +1207,9 @@ final newFileUri = Uri.file(newFilePath); /// Expected new file content. - const expectedNewFileContent = ''' + const expected = ''' +>>>>>>>>>> lib/main.dart empty +>>>>>>>>>> lib/my_new_class.dart class A {} '''; @@ -1219,9 +1217,8 @@ final action = await expectCodeAction(simpleClassRefactorTitle); // Replace the file URI argument with our custom path. replaceSaveUriArgument(action, newFileUri); - await executeRefactor(action); - - expect(content[newFilePath], expectedNewFileContent); + await verifyCommandEdits(action.command!, expected, + expectDocumentChanges: true); } Future<void> test_protocol_unavailable_withoutFileCreateSupport() async { @@ -1239,23 +1236,23 @@ class Neither {} '''; - var modifiedSource = ''' -class Neither {} -'''; - var newFileName = 'either.dart'; - var newFileContent = ''' + var expected = ''' +>>>>>>>>>> lib/either.dart sealed class Either {} class Left extends Either {} class Right extends Either {} +>>>>>>>>>> lib/main.dart + +class Neither {} + '''; await _multipleDeclarations( - originalSource: originalSource, - modifiedSource: modifiedSource, - count: 3, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + count: 3, + ); } /// The code action is not available if you select a subclass of a sealed @@ -1286,7 +1283,7 @@ class Left extends Either {} '''; - addSource(otherFilePath, otherFileContent); + newFile(otherFilePath, otherFileContent); await initializeServer(); await expectNoCodeAction(null); @@ -1304,28 +1301,28 @@ class Neither {} '''; + // TODO(dantup): Track down where this extra newline is coming from. - var modifiedSource = ''' + var expected = ''' +>>>>>>>>>> lib/either.dart +sealed class Either {} + +class Left extends Either {} +class Right extends Either {} +>>>>>>>>>> lib/main.dart import 'package:test/either.dart'; class LeftSub extends Left {} class Neither {} -'''; - var newFileName = 'either.dart'; - var newFileContent = ''' -sealed class Either {} -class Left extends Either {} -class Right extends Either {} '''; await _multipleDeclarations( - originalSource: originalSource, - modifiedSource: modifiedSource, - count: 3, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + count: 3, + ); } Future<void> test_sealedClass_extends_superclassAndSubclass() async { @@ -1337,23 +1334,23 @@ class Neither {} '''; - var modifiedSource = ''' -class Neither {} -'''; - var newFileName = 'either.dart'; - var newFileContent = ''' + var expected = ''' +>>>>>>>>>> lib/either.dart sealed class Either {} class Left extends Either {} class Right extends Either {} +>>>>>>>>>> lib/main.dart + +class Neither {} + '''; await _multipleDeclarations( - originalSource: originalSource, - modifiedSource: modifiedSource, - count: 3, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + count: 3, + ); } Future<void> test_sealedClass_implements() async { @@ -1365,23 +1362,23 @@ class Neither {} '''; - var modifiedSource = ''' -class Neither {} -'''; - var newFileName = 'either.dart'; - var newFileContent = ''' + var expected = ''' +>>>>>>>>>> lib/either.dart sealed class Either {} class Left implements Either {} class Right implements Either {} +>>>>>>>>>> lib/main.dart + +class Neither {} + '''; await _multipleDeclarations( - originalSource: originalSource, - modifiedSource: modifiedSource, - count: 3, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + count: 3, + ); } Future<void> test_sealedClass_sealedSubclass_extends_superclass() async { @@ -1395,27 +1392,27 @@ class SubSubSubclass extends SubSubclass {} '''; - var modifiedSource = ''' + + var expected = ''' +>>>>>>>>>> lib/main.dart import 'package:test/sealed_root.dart'; class SubSubSubclass extends SubSubclass {} -'''; - var newFileName = 'sealed_root.dart'; - var newFileContent = ''' +>>>>>>>>>> lib/sealed_root.dart sealed class SealedRoot {} class Subclass extends SealedRoot {} sealed class SealedSubclass extends SealedRoot {} class SubSubclass extends SealedSubclass {} + '''; await _multipleDeclarations( - originalSource: originalSource, - modifiedSource: modifiedSource, - count: 4, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + count: 4, + ); } Future<void> test_single_class_withTypeParameters() async { @@ -1426,22 +1423,22 @@ class B {} '''; - var modifiedSource = ''' + var declarationName = 'ClassToMove'; + + var expected = ''' +>>>>>>>>>> lib/class_to_move.dart +class ClassToMove<T> {} +>>>>>>>>>> lib/main.dart class A {} class B {} -'''; - var declarationName = 'ClassToMove'; - var newFileName = 'class_to_move.dart'; - var newFileContent = ''' -class ClassToMove<T> {} + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_single_enum() async { @@ -1452,22 +1449,22 @@ class B {} '''; - var modifiedSource = ''' + var declarationName = 'EnumToMove'; + + var expected = ''' +>>>>>>>>>> lib/enum_to_move.dart +enum EnumToMove { a, b } +>>>>>>>>>> lib/main.dart class A {} class B {} -'''; - var declarationName = 'EnumToMove'; - var newFileName = 'enum_to_move.dart'; - var newFileContent = ''' -enum EnumToMove { a, b } + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_single_extension() async { @@ -1478,22 +1475,22 @@ class B {} '''; - var modifiedSource = ''' + var declarationName = 'ExtensionToMove'; + + var expected = ''' +>>>>>>>>>> lib/extension_to_move.dart +extension ExtensionToMove on int { } +>>>>>>>>>> lib/main.dart class A {} class B {} -'''; - var declarationName = 'ExtensionToMove'; - var newFileName = 'extension_to_move.dart'; - var newFileContent = ''' -extension ExtensionToMove on int { } + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_single_function_endOfName() async { @@ -1504,22 +1501,22 @@ class B {} '''; - var modifiedSource = ''' + var declarationName = 'functionToMove'; + + var expected = ''' +>>>>>>>>>> lib/function_to_move.dart +void functionToMove() { } +>>>>>>>>>> lib/main.dart class A {} class B {} -'''; - var declarationName = 'functionToMove'; - var newFileName = 'function_to_move.dart'; - var newFileContent = ''' -void functionToMove() { } + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_single_function_middleOfName() async { @@ -1530,22 +1527,22 @@ class B {} '''; - var modifiedSource = ''' + var declarationName = 'functionToMove'; + + var expected = ''' +>>>>>>>>>> lib/function_to_move.dart +void functionToMove() { } +>>>>>>>>>> lib/main.dart class A {} class B {} -'''; - var declarationName = 'functionToMove'; - var newFileName = 'function_to_move.dart'; - var newFileContent = ''' -void functionToMove() { } + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_single_mixin() async { @@ -1556,22 +1553,22 @@ class B {} '''; - var modifiedSource = ''' + var declarationName = 'MixinToMove'; + + var expected = ''' +>>>>>>>>>> lib/main.dart class A {} class B {} -'''; - var declarationName = 'MixinToMove'; - var newFileName = 'mixin_to_move.dart'; - var newFileContent = ''' +>>>>>>>>>> lib/mixin_to_move.dart mixin MixinToMove { } + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_single_parts_libraryToPart() async { @@ -1580,28 +1577,29 @@ class Clas^sToMove {} '''; - var modifiedSource = ''' -part 'class_to_move.dart'; -'''; var declarationName = 'ClassToMove'; var destinationFileName = 'class_to_move.dart'; var destinationFilePath = join(projectFolderPath, 'lib', destinationFileName); - addSource(destinationFilePath, ''' + newFile(destinationFilePath, ''' part of 'main.dart'; '''); - var destinationFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/class_to_move.dart part of 'main.dart'; class ClassToMove {} +>>>>>>>>>> lib/main.dart +part 'class_to_move.dart'; + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: destinationFileName, - newFileContent: destinationFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_single_parts_partToLibrary() async { @@ -1610,28 +1608,29 @@ class Clas^sToMove {} '''; - var modifiedSource = ''' -part of 'class_to_move.dart'; -'''; var declarationName = 'ClassToMove'; var destinationFileName = 'class_to_move.dart'; var destinationFilePath = join(projectFolderPath, 'lib', destinationFileName); - addSource(destinationFilePath, ''' + newFile(destinationFilePath, ''' part 'main.dart'; '''); - var destinationFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/class_to_move.dart part 'main.dart'; class ClassToMove {} +>>>>>>>>>> lib/main.dart +part of 'class_to_move.dart'; + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: destinationFileName, - newFileContent: destinationFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_single_parts_partToPart() async { @@ -1640,21 +1639,13 @@ class Clas^sToMove {} '''; - var modifiedSource = ''' -part of 'containing_library.dart'; -'''; var declarationName = 'ClassToMove'; var destinationFileName = 'class_to_move.dart'; var destinationFilePath = join(projectFolderPath, 'lib', destinationFileName); - addSource(destinationFilePath, ''' + newFile(destinationFilePath, ''' part of 'containing_library.dart'; '''); - var destinationFileContent = ''' -part of 'containing_library.dart'; - -class ClassToMove {} -'''; var containingLibraryFilePath = join(projectFolderPath, 'lib', 'containing_library.dart'); var containingLibraryFileContent = ''' @@ -1662,12 +1653,19 @@ part 'class_to_move.dart'; '''; + var expected = ''' +>>>>>>>>>> lib/class_to_move.dart +part of 'containing_library.dart'; + +class ClassToMove {} +>>>>>>>>>> lib/main.dart +part of 'containing_library.dart'; + +'''; await _singleDeclaration( originalSource: originalSource, - modifiedSource: modifiedSource, + expected: expected, declarationName: declarationName, - newFileName: destinationFileName, - newFileContent: destinationFileContent, otherFilePath: containingLibraryFilePath, otherFileContent: containingLibraryFileContent); } @@ -1680,48 +1678,49 @@ class B {} '''; - var modifiedSource = ''' + var declarationName = 'TypeToMove'; + + var expected = ''' +>>>>>>>>>> lib/main.dart class A {} class B {} -'''; - var declarationName = 'TypeToMove'; - var newFileName = 'type_to_move.dart'; - var newFileContent = ''' +>>>>>>>>>> lib/type_to_move.dart typedef TypeToMove = void Function(); + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_single_variable() async { var originalSource = ''' class A {} + int variableT^oMove = 3; class B {} '''; - var modifiedSource = ''' + var declarationName = 'variableToMove'; + + var expected = ''' +>>>>>>>>>> lib/main.dart class A {} class B {} -'''; - var declarationName = 'variableToMove'; - var newFileName = 'variable_to_move.dart'; - var newFileContent = ''' +>>>>>>>>>> lib/variable_to_move.dart int variableToMove = 3; + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } Future<void> test_single_variable_firstDartDoc() async { @@ -1731,93 +1730,76 @@ class B {} '''; - var modifiedSource = ''' - -class B {} -'''; var declarationName = 'A'; - var newFileName = 'a.dart'; - var newFileContent = ''' + + var expected = ''' +>>>>>>>>>> lib/a.dart /// class A {} +>>>>>>>>>> lib/main.dart + +class B {} + '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: declarationName, - newFileName: newFileName, - newFileContent: newFileContent); + originalSource: originalSource, + expected: expected, + declarationName: declarationName, + ); } - Future<void> _multipleDeclarations( - {required String originalSource, - required String modifiedSource, - required int count, - required String newFileName, - required String newFileContent, - String? otherFilePath, - String? otherFileContent, - String? modifiedOtherFileContent}) async { + Future<void> _multipleDeclarations({ + required String originalSource, + required int count, + required String expected, + String? otherFilePath, + String? otherFileContent, + }) async { await _refactor( - originalSource: originalSource, - modifiedSource: modifiedSource, - actionTitle: "Move $count declarations to file", - newFileName: newFileName, - newFileContent: newFileContent, - otherFilePath: otherFilePath, - otherFileContent: otherFileContent, - modifiedOtherFileContent: modifiedOtherFileContent); + originalSource: originalSource, + expected: expected, + actionTitle: "Move $count declarations to file", + otherFilePath: otherFilePath, + otherFileContent: otherFileContent, + ); } - Future<void> _refactor( - {required String originalSource, - required String modifiedSource, - required String actionTitle, - required String newFileName, - required String newFileContent, - String? otherFilePath, - String? otherFileContent, - String? modifiedOtherFileContent}) async { + Future<void> _refactor({ + required String originalSource, + required String actionTitle, + required String expected, + String? otherFilePath, + String? otherFileContent, + }) async { + if (originalSource.contains('>>>>') || + (otherFileContent?.contains('>>>>>') ?? false)) { + throw '>>>>>'; + } addTestSource(originalSource); if (otherFilePath != null) { - addSource(otherFilePath, otherFileContent!); + newFile(otherFilePath, otherFileContent!); } - /// Expected new file path/content. - final expectedNewFilePath = join(projectFolderPath, 'lib', newFileName); - await initializeServer(); final action = await expectCodeAction(actionTitle); - await executeRefactor(action); - - expect(content[mainFilePath], modifiedSource); - // Check the new file was added to `content`. If no CreateFile resource - // was sent, the executeRefactor helper would've thrown when trying to - // apply the changes. - expect(content[expectedNewFilePath], newFileContent); - if (modifiedOtherFileContent != null) { - expect(content[convertPath(otherFilePath!)], modifiedOtherFileContent); - } + await verifyCommandEdits(action.command!, expected, + expectDocumentChanges: true); } - Future<void> _singleDeclaration( - {required String originalSource, - required String modifiedSource, - required String declarationName, - required String newFileName, - required String newFileContent, - String? otherFilePath, - String? otherFileContent, - String? modifiedOtherFileContent}) async { + Future<void> _singleDeclaration({ + required String originalSource, + required String declarationName, + required String expected, + String? otherFilePath, + String? otherFileContent, + }) async { await _refactor( - originalSource: originalSource, - modifiedSource: modifiedSource, - actionTitle: "Move '$declarationName' to file", - newFileName: newFileName, - newFileContent: newFileContent, - otherFilePath: otherFilePath, - otherFileContent: otherFileContent, - modifiedOtherFileContent: modifiedOtherFileContent); + originalSource: originalSource, + expected: expected, + actionTitle: "Move '$declarationName' to file", + otherFilePath: otherFilePath, + otherFileContent: otherFileContent, + ); } /// Tests that prefixes are included in imports copied to the new code. @@ -1838,22 +1820,21 @@ ${code.rawCode} '''; - var modifiedSource = ''' + + var expected = ''' +>>>>>>>>>> lib/main.dart import 'package:test/other.dart' as other; -'''; - var newFileName = 'moving.dart'; - var newFileContent = ''' +>>>>>>>>>> lib/moving.dart import 'package:test/other.dart' as other; ${code.code} '''; await _singleDeclaration( - originalSource: originalSource, - modifiedSource: modifiedSource, - declarationName: movingDeclarationName, - newFileName: newFileName, - newFileContent: newFileContent, - otherFilePath: otherFilePath, - otherFileContent: otherFileContent); + originalSource: originalSource, + expected: expected, + declarationName: movingDeclarationName, + otherFilePath: otherFilePath, + otherFileContent: otherFileContent, + ); } }
diff --git a/pkg/analysis_server/test/src/services/refactoring/refactoring_test_support.dart b/pkg/analysis_server/test/src/services/refactoring/refactoring_test_support.dart index 647537d..596fc97 100644 --- a/pkg/analysis_server/test/src/services/refactoring/refactoring_test_support.dart +++ b/pkg/analysis_server/test/src/services/refactoring/refactoring_test_support.dart
@@ -16,21 +16,10 @@ /// The range of characters that were selected. Range? _range; - /// A map of file paths to their current content. - /// - /// Methods like [executeRefactor] will update this as workspace edits are - /// sent from the server back to the client. - Map<String, String> content = {}; - /// Return the title of the refactoring command that is expected to be /// available. String get refactoringName; - void addSource(String filePath, String code) { - var file = newFile(filePath, code); - content[file.path] = code; - } - void addTestSource(String markedCode) { var testCode = TestCode.parse(markedCode); var positions = testCode.positions; @@ -42,7 +31,7 @@ _range = ranges[0].range; } } - addSource(mainFilePath, testCode.code); + newFile(mainFilePath, testCode.code); } void assertTextExpectation(String actual, String expected) { @@ -54,11 +43,11 @@ expect(actual, expected); } - /// Executes the [action], updating [content] with edits sent by the server. + /// Executes the refactor in [action]. Future<void> executeRefactor(CodeAction action) async { await executeCommandForEdits( action.command!, - content, + {}, expectDocumentChanges: true, ); }