From 823395a263133dd17db76912de9c9047af3bf6a0 Mon Sep 17 00:00:00 2001 From: Teodora Sandu Date: Wed, 27 Mar 2024 11:34:08 +0000 Subject: [PATCH] test: add tests --- .../panels/IssueDescriptionPanelBase.kt | 12 +- src/main/kotlin/snyk/common/lsp/Types.kt | 2 +- .../SuggestionDescriptionPanelFromLSTest.kt | 126 ++++++++++++++++++ src/test/kotlin/snyk/UIComponentFinder.kt | 17 +++ 4 files changed, 149 insertions(+), 8 deletions(-) create mode 100644 src/test/kotlin/io/snyk/plugin/ui/toolwindow/SuggestionDescriptionPanelFromLSTest.kt diff --git a/src/main/kotlin/io/snyk/plugin/ui/toolwindow/panels/IssueDescriptionPanelBase.kt b/src/main/kotlin/io/snyk/plugin/ui/toolwindow/panels/IssueDescriptionPanelBase.kt index 88ae70c7f..9e6e2cf6b 100644 --- a/src/main/kotlin/io/snyk/plugin/ui/toolwindow/panels/IssueDescriptionPanelBase.kt +++ b/src/main/kotlin/io/snyk/plugin/ui/toolwindow/panels/IssueDescriptionPanelBase.kt @@ -19,6 +19,7 @@ import io.snyk.plugin.ui.addSpacer import io.snyk.plugin.ui.baseGridConstraints import io.snyk.plugin.ui.baseGridConstraintsAnchorWest import io.snyk.plugin.ui.panelGridConstraints +import io.snyk.plugin.ui.toolwindow.SnykToolWindowPanel import io.snyk.plugin.ui.wrapWithScrollPane import org.cef.browser.CefBrowser import org.cef.browser.CefFrame @@ -39,14 +40,16 @@ abstract class IssueDescriptionPanelBase( private val severity: Severity, private val details: String? ) : JPanel(BorderLayout()), IssueDescriptionPanel { + private val unexpectedErrorMessage = "Snyk encountered an issue while rendering the vulnerability description. Please try again, or contact support if the problem persists. We apologize for any inconvenience caused."; + /** * **MUST** be invoked in derived class to actually create the UI elements. * Can't be part of constructor due to `state` usage in underling abstract/open methods/props: */ protected fun createUI() { - if (pluginSettings().isGlobalIgnoresFeatureEnabled) { + if (pluginSettings().isGlobalIgnoresFeatureEnabled && details != null) { if (!JBCefApp.isSupported()) { - SnykBalloonNotificationHelper.showError("Something went wrong.", null) + SnykBalloonNotificationHelper.showError(unexpectedErrorMessage, null) return } @@ -60,11 +63,6 @@ abstract class IssueDescriptionPanelBase( BorderLayout.CENTER ) - if (this.details == null) { - SnykBalloonNotificationHelper.showError("Something went wrong.", null) - return - } - jbCefBrowser.loadHTML(this.details, jbCefBrowser.cefBrowser.url) } else { diff --git a/src/main/kotlin/snyk/common/lsp/Types.kt b/src/main/kotlin/snyk/common/lsp/Types.kt index 07f6c8dee..5fa2ae934 100644 --- a/src/main/kotlin/snyk/common/lsp/Types.kt +++ b/src/main/kotlin/snyk/common/lsp/Types.kt @@ -201,7 +201,7 @@ data class IssueData( @SerializedName("priorityScore") val priorityScore: Int, @SerializedName("hasAIFix") val hasAIFix: Boolean, @SerializedName("dataFlow") val dataFlow: List, - @SerializedName("details") val details: String, + @SerializedName("details") val details: String?, ) { override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/src/test/kotlin/io/snyk/plugin/ui/toolwindow/SuggestionDescriptionPanelFromLSTest.kt b/src/test/kotlin/io/snyk/plugin/ui/toolwindow/SuggestionDescriptionPanelFromLSTest.kt new file mode 100644 index 000000000..d28d3977c --- /dev/null +++ b/src/test/kotlin/io/snyk/plugin/ui/toolwindow/SuggestionDescriptionPanelFromLSTest.kt @@ -0,0 +1,126 @@ +@file:Suppress("FunctionName") +package io.snyk.plugin.ui.toolwindow + +import com.google.gson.Gson +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings +import com.intellij.openapi.application.Application +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ModalityState +import com.intellij.openapi.application.WriteAction +import com.intellij.openapi.command.undo.UndoManager +import com.intellij.openapi.progress.impl.CoreProgressManager +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.newvfs.RefreshQueue +import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager +import com.intellij.psi.PsiFile +import com.intellij.psi.codeStyle.CodeStyleSchemes +import com.intellij.psi.impl.DocumentCommitProcessor +import com.intellij.psi.stubs.StubIndex +import com.intellij.testFramework.fixtures.BasePlatformTestCase +import com.intellij.ui.components.ActionLink +import com.intellij.util.indexing.FileBasedIndex +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkAll +import io.snyk.plugin.Severity +import io.snyk.plugin.pluginSettings +import io.snyk.plugin.resetSettings +import io.snyk.plugin.services.SnykApplicationSettingsStateService +import io.snyk.plugin.snykcode.core.SnykCodeFile +import io.snyk.plugin.ui.toolwindow.panels.SuggestionDescriptionPanelFromLS +import io.snyk.plugin.ui.toolwindow.panels.VulnerabilityDescriptionPanel +import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertNotNull +import org.eclipse.lsp4j.Position +import org.eclipse.lsp4j.Range +import org.junit.Before +import org.junit.Test +import snyk.UIComponentFinder.getJBCEFBrowser +import snyk.UIComponentFinder.getJButtonByText +import snyk.UIComponentFinder.getJLabelByText +import snyk.code.annotator.SnykCodeAnnotator +import snyk.common.lsp.CommitChangeLine +import snyk.common.lsp.DataFlow +import snyk.common.lsp.ExampleCommitFix +import snyk.common.lsp.ScanIssue +import snyk.oss.Vulnerability +import java.io.FileReader +import java.nio.file.Paths + +class SuggestionDescriptionPanelFromLSTest : BasePlatformTestCase() { + private lateinit var cut: SuggestionDescriptionPanelFromLS + private val fileName = "app.js" + private lateinit var snykCodeFile: SnykCodeFile + private lateinit var issue: ScanIssue + + private lateinit var file: VirtualFile + private lateinit var psiFile: PsiFile + + override fun getTestDataPath(): String { + val resource = SnykCodeAnnotator::class.java.getResource("/test-fixtures/code/annotator") + requireNotNull(resource) { "Make sure that the resource $resource exists!" } + return Paths.get(resource.toURI()).toString() + } + + @Before + override fun setUp() { + super.setUp() + unmockkAll() + resetSettings(project) + + file = myFixture.copyFileToProject(fileName) + psiFile = WriteAction.computeAndWait { psiManager.findFile(file)!! } + snykCodeFile = SnykCodeFile(psiFile.project, psiFile.virtualFile) + + issue = mockk() + every { issue.additionalData.message } returns "Test message" + every { issue.additionalData.isSecurityType } returns true + every { issue.additionalData.cwe } returns null + every { issue.additionalData.repoDatasetSize } returns 1 + every { issue.additionalData.exampleCommitFixes } returns listOf(ExampleCommitFix("https://commit-url", listOf( + CommitChangeLine("1", 1, "lineChange") + ))) + every { issue.additionalData.dataFlow } returns listOf(DataFlow(0, getTestDataPath(), Range(Position(1, 1), Position(1, 1)), "")) + every { issue.title } returns "Test title" + every { issue.getSeverityAsEnum() } returns Severity.CRITICAL + } + + @Test + fun `test createUI should build panel with issue message as overview label if the feature flag is not enabled`() { + every { issue.additionalData.details } returns "HTML message" + every { issue.additionalData.details } returns null + cut = SuggestionDescriptionPanelFromLS(snykCodeFile, issue) + + val actual = getJLabelByText(cut, "Test message") + assertNotNull(actual) + + val actualBrowser = getJBCEFBrowser(cut) + assertNull(actualBrowser) + } + + @Test + fun `test createUI should build panel with issue message as overview label if the details are empty even if feature flag is enabled`() { + pluginSettings().isGlobalIgnoresFeatureEnabled = true + + every { issue.additionalData.details } returns null + cut = SuggestionDescriptionPanelFromLS(snykCodeFile, issue) + + val actual = getJLabelByText(cut, "Test message") + assertNotNull(actual) + + val actualBrowser = getJBCEFBrowser(cut) + assertNull(actualBrowser) + } + + @Test + fun `test createUI should build panel with HTML from details if feature flag is enabled`() { + pluginSettings().isGlobalIgnoresFeatureEnabled = true + + every { issue.additionalData.details } returns "HTML message" + cut = SuggestionDescriptionPanelFromLS(snykCodeFile, issue) + + val actualBrowser = getJBCEFBrowser(cut) + assertNotNull(actualBrowser) + } +} diff --git a/src/test/kotlin/snyk/UIComponentFinder.kt b/src/test/kotlin/snyk/UIComponentFinder.kt index 1b20702ef..250f76cfc 100644 --- a/src/test/kotlin/snyk/UIComponentFinder.kt +++ b/src/test/kotlin/snyk/UIComponentFinder.kt @@ -1,5 +1,6 @@ package snyk +import com.intellij.ui.jcef.JBCefBrowser import java.awt.Container import javax.swing.JButton import javax.swing.JLabel @@ -53,4 +54,20 @@ object UIComponentFinder { } return found } + + fun getJBCEFBrowser(parent: Container): JBCefBrowser.MyPanel? { + val components = parent.components + var found: JBCefBrowser.MyPanel? = null + for (component in components) { + if (component is JBCefBrowser.MyPanel) { + found = component + } else if (component is Container) { + found = getJBCEFBrowser(component) + } + if (found != null) { + break + } + } + return found + } }