diff --git a/src/test/java/com/redhat/devtools/lsp4ij/features/codeAction/WebFilterQuickFixTest.java b/src/test/java/com/redhat/devtools/lsp4ij/features/codeAction/WebFilterQuickFixTest.java index f6539aaf4..2e533a3a5 100644 --- a/src/test/java/com/redhat/devtools/lsp4ij/features/codeAction/WebFilterQuickFixTest.java +++ b/src/test/java/com/redhat/devtools/lsp4ij/features/codeAction/WebFilterQuickFixTest.java @@ -10,8 +10,11 @@ ******************************************************************************/ package com.redhat.devtools.lsp4ij.features.codeAction; +import com.intellij.codeInsight.intention.IntentionAction; import com.redhat.devtools.lsp4ij.fixtures.LSPCodeActionFixtureTestCase; +import java.util.List; + /** * Test case for InvalidWebFilter quick fix */ @@ -25,247 +28,255 @@ public WebFilterQuickFixTest() { super("*." + NOT_JAVA_EXTENSION); } - public void testWebFilterQuickFix() { - var allQuickFixes = assertCodeActions(TEST_FILE_NAME, - IntentionActionKind.QUICK_FIX_ONLY, - // language=JAVA - """ -package io.openliberty.sample.jakarta.servlet; - -import jakarta.servlet.Filter; -import jakarta.servlet.annotation.WebFilter; - -@WebFilter() -public abstract class InvalidWebFilter implements Filter { - -}""", - // language=JSON - """ - [ - { - "title": "Add the `servletNames` attribute to @WebFilter", - "kind": "quickfix", - "diagnostics": [ - { - "range": { - "start": { - "line": 5, - "character": 0 - }, - "end": { - "line": 5, - "character": 12 - } - }, - "severity": 1, - "code": "CompleteWebFilterAttributes", - "source": "jakarta-servlet", - "message": "The annotation @WebFilter must define the attribute \\u0027urlPatterns\\u0027, \\u0027servletNames\\u0027 or \\u0027value\\u0027." - } - ], - "data": { - "participantId": "io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.servlet.CompleteFilterAnnotationQuickFix", - "documentUri": "unused", - "range": { - "start": { - "line": 5, - "character": 0 - }, - "end": { - "line": 5, - "character": 12 - } - }, - "extendedData": { - "annotation": "jakarta.servlet.annotation.WebFilter", - "attribute": "servletNames", - "diagnosticCode": "CompleteWebFilterAttributes" - }, - "resourceOperationSupported": true, - "commandConfigurationUpdateSupported": false - } - }, - { - "title": "Add the `urlPatterns` attribute to @WebFilter", - "kind": "quickfix", - "diagnostics": [ - { - "range": { - "start": { - "line": 5, - "character": 0 - }, - "end": { - "line": 5, - "character": 12 - } - }, - "severity": 1, - "code": "CompleteWebFilterAttributes", - "source": "jakarta-servlet", - "message": "The annotation @WebFilter must define the attribute \\u0027urlPatterns\\u0027, \\u0027servletNames\\u0027 or \\u0027value\\u0027." - } - ], - "data": { - "participantId": "io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.servlet.CompleteFilterAnnotationQuickFix", - "documentUri": "unused", - "range": { - "start": { - "line": 5, - "character": 0 - }, - "end": { - "line": 5, - "character": 12 - } - }, - "extendedData": { - "annotation": "jakarta.servlet.annotation.WebFilter", - "attribute": "urlPatterns", - "diagnosticCode": "CompleteWebFilterAttributes" - }, - "resourceOperationSupported": true, - "commandConfigurationUpdateSupported": false - } - }, - { - "title": "Add the `value` attribute to @WebFilter", - "kind": "quickfix", - "diagnostics": [ - { - "range": { - "start": { - "line": 5, - "character": 0 - }, - "end": { - "line": 5, - "character": 12 - } - }, - "severity": 1, - "code": "CompleteWebFilterAttributes", - "source": "jakarta-servlet", - "message": "The annotation @WebFilter must define the attribute \\u0027urlPatterns\\u0027, \\u0027servletNames\\u0027 or \\u0027value\\u0027." - } - ], - "data": { - "participantId": "io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.servlet.CompleteFilterAnnotationQuickFix", - "documentUri": "unused", - "range": { - "start": { - "line": 5, - "character": 0 - }, - "end": { - "line": 5, - "character": 12 - } - }, - "extendedData": { - "annotation": "jakarta.servlet.annotation.WebFilter", - "attribute": "value", - "diagnosticCode": "CompleteWebFilterAttributes" - }, - "resourceOperationSupported": true, - "commandConfigurationUpdateSupported": false - } - } - ]""" - , - "Add the `servletNames` attribute to @WebFilter", - "Add the `urlPatterns` attribute to @WebFilter", - "Add the `value` attribute to @WebFilter"); + private List assertCodeActions(boolean simulateCancellation) { + return assertCodeActions(TEST_FILE_NAME, + IntentionActionKind.QUICK_FIX_ONLY, + // language=JAVA + """ + package io.openliberty.sample.jakarta.servlet; + + import jakarta.servlet.Filter; + import jakarta.servlet.annotation.WebFilter; + + @WebFilter() + public abstract class InvalidWebFilter implements Filter { + + }""", + // language=JSON + """ + [ + { + "title": "Add the `servletNames` attribute to @WebFilter", + "kind": "quickfix", + "diagnostics": [ + { + "range": { + "start": { + "line": 5, + "character": 0 + }, + "end": { + "line": 5, + "character": 12 + } + }, + "severity": 1, + "code": "CompleteWebFilterAttributes", + "source": "jakarta-servlet", + "message": "The annotation @WebFilter must define the attribute \\u0027urlPatterns\\u0027, \\u0027servletNames\\u0027 or \\u0027value\\u0027." + } + ], + "data": { + "participantId": "io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.servlet.CompleteFilterAnnotationQuickFix", + "documentUri": "unused", + "range": { + "start": { + "line": 5, + "character": 0 + }, + "end": { + "line": 5, + "character": 12 + } + }, + "extendedData": { + "annotation": "jakarta.servlet.annotation.WebFilter", + "attribute": "servletNames", + "diagnosticCode": "CompleteWebFilterAttributes" + }, + "resourceOperationSupported": true, + "commandConfigurationUpdateSupported": false + } + }, + { + "title": "Add the `urlPatterns` attribute to @WebFilter", + "kind": "quickfix", + "diagnostics": [ + { + "range": { + "start": { + "line": 5, + "character": 0 + }, + "end": { + "line": 5, + "character": 12 + } + }, + "severity": 1, + "code": "CompleteWebFilterAttributes", + "source": "jakarta-servlet", + "message": "The annotation @WebFilter must define the attribute \\u0027urlPatterns\\u0027, \\u0027servletNames\\u0027 or \\u0027value\\u0027." + } + ], + "data": { + "participantId": "io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.servlet.CompleteFilterAnnotationQuickFix", + "documentUri": "unused", + "range": { + "start": { + "line": 5, + "character": 0 + }, + "end": { + "line": 5, + "character": 12 + } + }, + "extendedData": { + "annotation": "jakarta.servlet.annotation.WebFilter", + "attribute": "urlPatterns", + "diagnosticCode": "CompleteWebFilterAttributes" + }, + "resourceOperationSupported": true, + "commandConfigurationUpdateSupported": false + } + }, + { + "title": "Add the `value` attribute to @WebFilter", + "kind": "quickfix", + "diagnostics": [ + { + "range": { + "start": { + "line": 5, + "character": 0 + }, + "end": { + "line": 5, + "character": 12 + } + }, + "severity": 1, + "code": "CompleteWebFilterAttributes", + "source": "jakarta-servlet", + "message": "The annotation @WebFilter must define the attribute \\u0027urlPatterns\\u0027, \\u0027servletNames\\u0027 or \\u0027value\\u0027." + } + ], + "data": { + "participantId": "io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.servlet.CompleteFilterAnnotationQuickFix", + "documentUri": "unused", + "range": { + "start": { + "line": 5, + "character": 0 + }, + "end": { + "line": 5, + "character": 12 + } + }, + "extendedData": { + "annotation": "jakarta.servlet.annotation.WebFilter", + "attribute": "value", + "diagnosticCode": "CompleteWebFilterAttributes" + }, + "resourceOperationSupported": true, + "commandConfigurationUpdateSupported": false + } + } + ]""" + , + simulateCancellation, + "Add the `servletNames` attribute to @WebFilter", + "Add the `urlPatterns` attribute to @WebFilter", + "Add the `value` attribute to @WebFilter" + ); + } + public void testWebFilterQuickFix() { + var allQuickFixes = assertCodeActions(false); // Get 'Add the `servletNames` attribute to @WebFilter' quick fix var addServletNameQuickFix = assertFindIntentionByText("Add the `servletNames` attribute to @WebFilter", allQuickFixes); // Apply 'Add the `servletNames` attribute to @WebFilter' quick fix assertApplyCodeAction( - // language=JAVA - """ -package io.openliberty.sample.jakarta.servlet; - -import jakarta.servlet.Filter; -import jakarta.servlet.annotation.WebFilter; - -@WebFilter(servletNames="") -public abstract class InvalidWebFilter implements Filter { - -}""", - // language=JSON - """ - { - "title": "Add the `servletNames` attribute to @WebFilter", - "kind": "quickfix", - "diagnostics": [ - { - "range": { - "start": { - "line": 5, - "character": 0 - }, - "end": { - "line": 5, - "character": 12 - } - }, - "severity": 1, - "code": "CompleteWebFilterAttributes", - "source": "jakarta-servlet", - "message": "The annotation @WebFilter must define the attribute \\u0027urlPatterns\\u0027, \\u0027servletNames\\u0027 or \\u0027value\\u0027." - } - ], - "edit": { - "changes": {}, - "documentChanges": [ - { - "textDocument": { - "version": 0, - "uri": "%s" - }, - "edits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 11, - "character": 0 - } - }, - "newText": "package io.openliberty.sample.jakarta.servlet;\\n\\nimport jakarta.servlet.Filter;\\nimport jakarta.servlet.annotation.WebFilter;\\n\\n@WebFilter(servletNames\\u003d\\"\\")\\npublic abstract class InvalidWebFilter implements Filter {\\n\\n}" - } - ] - } - ] + // language=JAVA + """ + package io.openliberty.sample.jakarta.servlet; + + import jakarta.servlet.Filter; + import jakarta.servlet.annotation.WebFilter; + + @WebFilter(servletNames="") + public abstract class InvalidWebFilter implements Filter { + + }""", + // language=JSON + """ + { + "title": "Add the `servletNames` attribute to @WebFilter", + "kind": "quickfix", + "diagnostics": [ + { + "range": { + "start": { + "line": 5, + "character": 0 + }, + "end": { + "line": 5, + "character": 12 + } + }, + "severity": 1, + "code": "CompleteWebFilterAttributes", + "source": "jakarta-servlet", + "message": "The annotation @WebFilter must define the attribute \\u0027urlPatterns\\u0027, \\u0027servletNames\\u0027 or \\u0027value\\u0027." + } + ], + "edit": { + "changes": {}, + "documentChanges": [ + { + "textDocument": { + "version": 0, + "uri": "%s" + }, + "edits": [ + { + "range": { + "start": { + "line": 0, + "character": 0 }, - "data": { - "participantId": "io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.servlet.CompleteFilterAnnotationQuickFix", - "documentUri": "unused", - "range": { - "start": { - "line": 5, - "character": 0 - }, - "end": { - "line": 5, - "character": 12 - } - }, - "extendedData": { - "annotation": "jakarta.servlet.annotation.WebFilter", - "attribute": "servletNames", - "diagnosticCode": "CompleteWebFilterAttributes" - }, - "resourceOperationSupported": true, - "commandConfigurationUpdateSupported": false + "end": { + "line": 11, + "character": 0 } - } - """, - addServletNameQuickFix); + }, + "newText": "package io.openliberty.sample.jakarta.servlet;\\n\\nimport jakarta.servlet.Filter;\\nimport jakarta.servlet.annotation.WebFilter;\\n\\n@WebFilter(servletNames\\u003d\\"\\")\\npublic abstract class InvalidWebFilter implements Filter {\\n\\n}" + } + ] + } + ] + }, + "data": { + "participantId": "io.openliberty.tools.intellij.lsp4jakarta.lsp4ij.servlet.CompleteFilterAnnotationQuickFix", + "documentUri": "unused", + "range": { + "start": { + "line": 5, + "character": 0 + }, + "end": { + "line": 5, + "character": 12 + } + }, + "extendedData": { + "annotation": "jakarta.servlet.annotation.WebFilter", + "attribute": "servletNames", + "diagnosticCode": "CompleteWebFilterAttributes" + }, + "resourceOperationSupported": true, + "commandConfigurationUpdateSupported": false + } + } + """, + addServletNameQuickFix); } + public void testWebFilterQuickFixWithCancellation() { + assertCodeActions(true); + } } \ No newline at end of file diff --git a/src/test/java/com/redhat/devtools/lsp4ij/fixtures/LSPCodeActionFixtureTestCase.java b/src/test/java/com/redhat/devtools/lsp4ij/fixtures/LSPCodeActionFixtureTestCase.java index fc55a4800..c5df0f941 100644 --- a/src/test/java/com/redhat/devtools/lsp4ij/fixtures/LSPCodeActionFixtureTestCase.java +++ b/src/test/java/com/redhat/devtools/lsp4ij/fixtures/LSPCodeActionFixtureTestCase.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; /** @@ -61,12 +62,13 @@ protected List assertCodeActions(@NotNull String fileName, @NotNull IntentionActionKind kind, @NotNull String editorContentText, @NotNull String codeActionsJson, + boolean simulateCancellation, @NotNull String... expectedActions) { List codeActions = JSONUtils.getLsp4jGson() .fromJson(codeActionsJson, new TypeToken>() { }.getType()); - return assertCodeActions(fileName, kind, editorContentText, codeActions, expectedActions); + return assertCodeActions(fileName, kind, editorContentText, codeActions, simulateCancellation, expectedActions); } /** @@ -82,6 +84,7 @@ protected List assertCodeActions(@NotNull String fileName, @NotNull IntentionActionKind kind, @NotNull String editorContentText, @NotNull List codeActions, + boolean simulateCancellation, @NotNull String... expectedActions) { List> wrappedCodeActions = codeActions.stream() .distinct() @@ -96,8 +99,20 @@ protected List assertCodeActions(@NotNull String fileName, .collect(Collectors.toList()); MockLanguageServer.INSTANCE.setTimeToProceedQueries(200); - MockLanguageServer.INSTANCE.setCodeActions(wrappedCodeActions); MockLanguageServer.INSTANCE.setPublishDiagnostics(diagnostics); + + if (simulateCancellation) { + // Simulate a cancelled CodeAction request + MockLanguageServer.INSTANCE.setCodeActionHandler(params -> { + CompletableFuture>> cancelled = new CompletableFuture<>(); + cancelled.cancel(true); + return cancelled; + }); + } else { + // Normal code action handling + MockLanguageServer.INSTANCE.setCodeActions(wrappedCodeActions); + } + myFixture.configureByText(fileName, editorContentText); // Collect IntelliJ Quick fixes / Intention actions diff --git a/src/test/java/com/redhat/devtools/lsp4ij/mock/MockLanguageServer.java b/src/test/java/com/redhat/devtools/lsp4ij/mock/MockLanguageServer.java index 3ce8ff309..7a6815046 100644 --- a/src/test/java/com/redhat/devtools/lsp4ij/mock/MockLanguageServer.java +++ b/src/test/java/com/redhat/devtools/lsp4ij/mock/MockLanguageServer.java @@ -309,6 +309,12 @@ public void setDocumentSymbols(DocumentSymbol... documentSymbols) { this.textDocumentService.setDocumentSymbols(Arrays.asList(documentSymbols)); } + public void setCodeActionHandler(Function>>> handler) { + if (this.textDocumentService != null) { + this.textDocumentService.setCodeActionHandler(handler); + } + } + @Override public NotebookDocumentService getNotebookDocumentService() { return new NotebookDocumentService() { diff --git a/src/test/java/com/redhat/devtools/lsp4ij/mock/MockTextDocumentService.java b/src/test/java/com/redhat/devtools/lsp4ij/mock/MockTextDocumentService.java index 0b795700f..792e37e06 100644 --- a/src/test/java/com/redhat/devtools/lsp4ij/mock/MockTextDocumentService.java +++ b/src/test/java/com/redhat/devtools/lsp4ij/mock/MockTextDocumentService.java @@ -68,6 +68,7 @@ public class MockTextDocumentService implements TextDocumentService { private SemanticTokens mockSemanticTokens; private List foldingRanges; public int codeActionRequests = 0; + private Function>>> codeActionHandler; public MockTextDocumentService(Function> futureFactory) { this._futureFactory = futureFactory; @@ -147,11 +148,15 @@ public CompletableFuture> documentLink(DocumentLinkParams par @Override public CompletableFuture>> codeAction(CodeActionParams params) { codeActionRequests++; + // For a custom handler + if (codeActionHandler != null) { + return codeActionHandler.apply(params); + } // Filter code actions by using params.getContext().getOnly() var only = (params.getContext() != null && params.getContext().getOnly() != null && !params.getContext().getOnly().isEmpty()) ? params.getContext().getOnly() : null; var filteredCodeActions = mockCodeActions; - if (only != null) { + if (only != null && mockCodeActions != null) { filteredCodeActions = mockCodeActions .stream() .filter(ca -> { @@ -411,6 +416,10 @@ public void setMockSelectionRanges(List mockSelectionRanges) { this.mockSelectionRanges = mockSelectionRanges; } + public void setCodeActionHandler(Function>>> handler) { + this.codeActionHandler = handler; + } + @Override public CompletableFuture> selectionRange(SelectionRangeParams params) { // Find the mock selection ranges that apply to the specified position. This allows us to have a single mock