Test based on LSP-server functionality

已回答

Hi JetBrains team,

how would I write a test with a project file that my language server supports and assert that the language server creates the right problems for the file?

This is what I've tried so far, but the test does not finish. Many thanks in advance,
Tim

 

package mypkg;

import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.lsp.api.LspServerManager;
import com.intellij.problems.ProblemListener;
import com.intellij.testFramework.HeavyPlatformTestCase;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.util.messages.MessageBusConnection;
import mypkg.lsp.ServerSupportProvider;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;

public class MyTest extends HeavyPlatformTestCase {

    private VirtualFile createFile(VirtualFile folder, String fileName, String content) {
        return WriteCommandAction.runWriteCommandAction(getProject(), (Computable<VirtualFile>) () -> {
            try {
                VirtualFile file = folder.createChildData(this, fileName);
                VfsUtil.saveText(file, content);
                return file;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }

    public void testSyntaxError() throws IOException, InterruptedException {
        Project project = getProject();
        Object lock = new Object();
        MessageBusConnection connection = project.getMessageBus().connect();
        connection.subscribe(ProblemListener.TOPIC, new ProblemListener() {
            @Override
            public void problemsAppeared(@NotNull VirtualFile file) {
                synchronized (lock) {
                    lock.notify();   // This is never called
                }
            }
        });

        VirtualFile rootFolder = PlatformTestUtil.getOrCreateProjectBaseDir(project);
        VirtualFile file = createFile(rootFolder, "a.myext", "syntax errr");

        Editor editor = FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, file), true);
        assertNotNull("Editor should be opened", editor);

        LspServerManager manager = LspServerManager.getInstance(project);
        manager.startServersIfNeeded(ServerSupportProvider.class);

        synchronized (lock) {
            lock.wait();  // This never finishes
        }
    }
}
0
正式评论

Hi,
Off the top of my head, I don't know why your test never completes. Instead of debugging it, I'd recommend using the approach that we use ourselves and that has proven to work. We've already discussed it in https://youtrack.jetbrains.com/issue/IJPL-158887#focus=Comments-27-10326292.0-0

Hi Alexander,

thanks for the pointer back to your previous suggestion. Based on it, my current best guess would be the following runnable source. However, an error occurs during teardown:

Listeners leaked for interface com.intellij.openapi.editor.event.DocumentListener:
[com.intellij.ide.bookmarks.BookmarkManager$MyDocumentListener@1e872505]
java.lang.AssertionError: Listeners leaked for interface com.intellij.openapi.editor.event.DocumentListener:
[com.intellij.ide.bookmarks.BookmarkManager$MyDocumentListener@1e872505]
 at org.junit.Assert.fail(Assert.java:89)
 at com.intellij.testFramework.EditorListenerTracker.checkListenersLeak(EditorListenerTracker.java:56)
 at com.intellij.testFramework.fixtures.impl.HeavyIdeaTestFixtureImpl.lambda$tearDown$7(HeavyIdeaTestFixtureImpl.java:153)
 […]
 at com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl.tearDown(CodeInsightTestFixtureImpl.java:1412)
 at mypkg.MyTest.tearDown(MyTest.java:30)
 […]

This is the test:

package mypkg;
import com.intellij.platform.lsp.api.LspServerManager;
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
import com.intellij.testFramework.fixtures.CodeInsightTestFixture;
import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
import mypkg.lsp.ServerSupportProvider;
public class MyTest extends BasePlatformTestCase {
   protected CodeInsightTestFixture myFixture;
   @Override
   protected void setUp() throws Exception {
       super.setUp();
       IdeaTestFixtureFactory factory = IdeaTestFixtureFactory.getFixtureFactory();
       final IdeaProjectTestFixture fixture = factory.createFixtureBuilder("Proj1").getFixture();
       myFixture = factory.createCodeInsightFixture(fixture);
       myFixture.setTestDataPath(getTestDataPath());
       myFixture.setUp();
   }
   protected String getTestDataPath() {
       return "/path/to/testdata";
   }
   @Override
   protected void tearDown() throws Exception {
//        myFixture.getTestRootDisposable().dispose();
//        myFixture.getProjectDisposable().dispose();
       myFixture.tearDown();
       super.tearDown();
   }
   public void testProj1() {
       myFixture.copyDirectoryToProject("Proj1", ".");
       myFixture.configureByFile("a.myext");
       LspServerManager manager = LspServerManager.getInstance(myFixture.getProject());
       manager.startServersIfNeeded(ServerSupportProvider.class);
       myFixture.checkHighlighting();
   }
}

Second, I noticed that the LSP server is not started (by setting a breakpoint in its overridden methods).

So how would you go about writing an integrative test of the plugin including LSP-server functionality such as problems or Code Actions?

Best regards,
Tim

PS. The stack frame would be in l. 26 in the test source if formatted without empty lines as in the above code box.

0

I've created a sample plugin and a test. The link to the repository is in the issue comment.

1

Many thanks, Alexander. This also clarifies how to correctly listen for and check diagnostics.

0

请先登录再写评论。