From 95f00522676dff03f64fc715cb1835ad451faa4c Mon Sep 17 00:00:00 2001 From: Danny Tuppeny Date: Fri, 17 Jan 2025 11:50:22 -0800 Subject: [PATCH] [analysis_server] Add tests for unversioned documents for EditableArguments The legacy protocol does not currently version documents, so this adds some additional tests for that. The tests are in the Legacy class and not the shared class because in LSP versions are not optional for opening/changing documents (they are optional in some of the other APIs, but not for open/change). Change-Id: I7e75b813025b3f67ed143e1b3a8b717224bfa80f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/404820 Commit-Queue: Brian Wilkerson Reviewed-by: Brian Wilkerson Reviewed-by: Phil Quitslund --- .../abstract_lsp_over_legacy.dart | 21 +++++ .../editable_arguments_test.dart | 77 ++++++++++++++++++- .../shared_editable_arguments_tests.dart | 63 +++++++-------- 3 files changed, 126 insertions(+), 35 deletions(-) diff --git a/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart b/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart index 95a225a067fd..b9c753b61d61 100644 --- a/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart +++ b/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart @@ -401,11 +401,32 @@ abstract class SharedLspOverLegacyTest extends LspOverLegacyTest @override Future openFile(Uri uri, String content, {int version = 1}) async { + // TODO(dantup): Add version here when legacy protocol supports. + await addOverlay(fromUri(uri), content); + } + + /// Opens a file content without providing a version number. + /// + /// This method should be used only for specifically testing unversioned + /// changes and [openFile] used by default since going forwards, we expect + /// all clients to start providing version numbers. + Future openFileUnversioned(Uri uri, String content) async { await addOverlay(fromUri(uri), content); } @override Future replaceFile(int newVersion, Uri uri, String content) async { + // TODO(dantup): Add version here when legacy protocol supports. + // For legacy, we can use addOverlay to replace the whole file. + await addOverlay(fromUri(uri), content); + } + + /// Replaces a file content without providing a version number. + /// + /// This method should be used only for specifically testing unversioned + /// changes and [replaceFile] used by default since going forwards, we expect + /// all clients to start providing version numbers. + Future replaceFileUnversioned(Uri uri, String content) async { // For legacy, we can use addOverlay to replace the whole file. await addOverlay(fromUri(uri), content); } diff --git a/pkg/analysis_server/test/lsp_over_legacy/editable_arguments_test.dart b/pkg/analysis_server/test/lsp_over_legacy/editable_arguments_test.dart index 5e56fffbce26..d12ff0665942 100644 --- a/pkg/analysis_server/test/lsp_over_legacy/editable_arguments_test.dart +++ b/pkg/analysis_server/test/lsp_over_legacy/editable_arguments_test.dart @@ -2,9 +2,12 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'package:analysis_server/lsp_protocol/protocol.dart'; +import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; import '../shared/shared_editable_arguments_tests.dart'; +import '../utils/test_code_extensions.dart'; import 'abstract_lsp_over_legacy.dart'; void main() { @@ -31,19 +34,85 @@ class EditableArgumentsTest extends SharedLspOverLegacyTest writeTestPackageConfig(flutter: true); } + /// Over the legacy protocol, document versions are optional so we must also + /// support this. + test_textDocument_unversioned() async { + var result = await getEditableArgumentsFor(''' +class MyWidget extends StatelessWidget { + const MyWidget(String a1); + + @override + Widget build(BuildContext context) => MyW^idget('value1'); +} +''', open: openFileUnversioned); + + // Verify initial content has no version. + expect( + result!.textDocument, + isA() + .having((td) => td.uri, 'uri', testFileUri) + .having((td) => td.version, 'version', isNull), + ); + + // Update the content. + await replaceFileUnversioned(testFileUri, '${code.code}\n// extra comment'); + + // Verify new results have no version. + result = await getEditableArguments(testFileUri, code.position.position); + expect( + result!.textDocument, + isA() + .having((td) => td.uri, 'uri', testFileUri) + .having((td) => td.version, 'version', isNull), + ); + } + + /// Over the legacy protocol, document versions are optional so we must also + /// support this. + test_textDocument_unversioned_closedFile() async { + var result = await getEditableArgumentsFor(''' +class MyWidget extends StatelessWidget { + const MyWidget(String a1); + + @override + Widget build(BuildContext context) => MyW^idget('value1'); +} +''', open: openFileUnversioned); + + // Verify initial content has no version. + expect( + result!.textDocument, + isA() + .having((td) => td.uri, 'uri', testFileUri) + .having((td) => td.version, 'version', isNull), + ); + + // Close the file. + await closeFile(testFileUri); + + // Verify new results have no version. + result = await getEditableArguments(testFileUri, code.position.position); + expect( + result!.textDocument, + isA() + .having((td) => td.uri, 'uri', testFileUri) + .having((td) => td.version, 'version', isNull), + ); + } + @override @FailingTest(reason: 'Document versions not currently supported for legacy') - test_textDocument_closedFile() { + test_textDocument_versioned() { // TODO(dantup): Implement support for version numbers in the legacy // protocol. - return super.test_textDocument_closedFile(); + return super.test_textDocument_versioned(); } @override @FailingTest(reason: 'Document versions not currently supported for legacy') - test_textDocument_versions() { + test_textDocument_versioned_closedFile() { // TODO(dantup): Implement support for version numbers in the legacy // protocol. - return super.test_textDocument_versions(); + return super.test_textDocument_versioned_closedFile(); } } diff --git a/pkg/analysis_server/test/shared/shared_editable_arguments_tests.dart b/pkg/analysis_server/test/shared/shared_editable_arguments_tests.dart index dfa990ae933a..373d8a9bfd89 100644 --- a/pkg/analysis_server/test/shared/shared_editable_arguments_tests.dart +++ b/pkg/analysis_server/test/shared/shared_editable_arguments_tests.dart @@ -19,8 +19,11 @@ mixin SharedEditableArgumentsTests /// Initializes the server with [content] and fetches editable arguments. Future getEditableArgumentsFor( String content, { - bool open = true, + Future Function(Uri, String)? open, }) async { + // Default to the standart openFile function if we weren't overridden. + open ??= openFile; + code = TestCode.parse(''' import 'package:flutter/widgets.dart'; @@ -28,9 +31,7 @@ $content '''); createFile(testFilePath, code.code); await initializeServer(); - if (open) { - await openFile(testFileUri, code.code); - } + await open(testFileUri, code.code); await currentAnalysis; return await getEditableArguments(testFileUri, code.position.position); } @@ -755,7 +756,7 @@ class MyWidget extends StatelessWidget { ); } - test_textDocument_closedFile() async { + test_textDocument_unopenedFile() async { var result = await getEditableArgumentsFor(''' class MyWidget extends StatelessWidget { const MyWidget(String a1); @@ -763,30 +764,18 @@ class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) => MyW^idget('value1'); } -'''); +''', open: (_, _) async {}); - // Verify initial content of 1. - expect( - result!.textDocument, - isA() - .having((td) => td.uri, 'uri', testFileUri) - .having((td) => td.version, 'version', 1), - ); - - // Close the file. - await closeFile(testFileUri); - - // Verify new results have null version. - result = await getEditableArguments(testFileUri, code.position.position); + // Verify null version for unopened file. expect( result!.textDocument, isA() .having((td) => td.uri, 'uri', testFileUri) - .having((td) => td.version, 'version', isNull), + .having((td) => td.version, 'version', null), ); } - test_textDocument_unopenedFile() async { + test_textDocument_versioned() async { var result = await getEditableArgumentsFor(''' class MyWidget extends StatelessWidget { const MyWidget(String a1); @@ -794,18 +783,30 @@ class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) => MyW^idget('value1'); } -''', open: false); +'''); - // Verify null version for unopened file. + // Verify initial content of 1. expect( result!.textDocument, - isA() + isA() .having((td) => td.uri, 'uri', testFileUri) - .having((td) => td.version, 'version', null), + .having((td) => td.version, 'version', 1), + ); + + // Update the content to v5. + await replaceFile(5, testFileUri, '${code.code}\n// extra comment'); + + // Verify new results have version 5. + result = await getEditableArguments(testFileUri, code.position.position); + expect( + result!.textDocument, + isA() + .having((td) => td.uri, 'uri', testFileUri) + .having((td) => td.version, 'version', 5), ); } - test_textDocument_versions() async { + test_textDocument_versioned_closedFile() async { var result = await getEditableArgumentsFor(''' class MyWidget extends StatelessWidget { const MyWidget(String a1); @@ -823,16 +824,16 @@ class MyWidget extends StatelessWidget { .having((td) => td.version, 'version', 1), ); - // Update the content to v5. - await replaceFile(5, testFileUri, '${code.code}\n// extra comment'); + // Close the file. + await closeFile(testFileUri); - // Verify new results have version 5. + // Verify new results have null version. result = await getEditableArguments(testFileUri, code.position.position); expect( result!.textDocument, - isA() + isA() .having((td) => td.uri, 'uri', testFileUri) - .having((td) => td.version, 'version', 5), + .having((td) => td.version, 'version', isNull), ); }