All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlinx.jupyter.test.InMemoryResultTests.kt Maven / Gradle / Ivy

package org.jetbrains.kotlinx.jupyter.test

import io.kotest.matchers.maps.shouldContainKey
import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.shouldBeInstanceOf
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import org.jetbrains.kotlinx.jupyter.api.InMemoryMimeTypes
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResultEx
import org.jetbrains.kotlinx.jupyter.api.takeScreenshot
import org.jetbrains.kotlinx.jupyter.test.repl.AbstractSingleReplTest
import org.jetbrains.kotlinx.jupyter.util.EMPTY
import org.junit.jupiter.api.Assertions.assertNotEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Assumptions
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.parallel.ResourceLock
import java.awt.Dimension
import java.awt.image.BufferedImage
import javax.swing.JButton
import javax.swing.JComponent
import javax.swing.JDialog
import javax.swing.JFrame
import javax.swing.JPanel
import kotlin.reflect.KClass
import kotlin.test.DefaultAsserter.fail
import kotlin.test.assertEquals

/**
 * Class responsible for testing how in-memory results are handled by the embedded kernel.
 */
class InMemoryResultTests : AbstractSingleReplTest() {
    companion object {
        // Lock to prevent multiple tests accessing the screen at the same time. It looks like if multiple
        // tests are opening JFrame/JDialogs, then taking screenshots can fail with
        // "Cannot invoke "java.awt.Window.isOpaque()" because "w" is null", if they overlap.
        const val SCREEN_LOCK = "screenLock"
    }

    override val repl = makeEmbeddedRepl()

    // Skip tests always for now as they are unstable
    private val skipGraphicsTests = true // GraphicsEnvironment.isHeadless()

    private fun assumeGraphicsSupported() {
        Assumptions.assumeFalse(skipGraphicsTests, "Test is skipped: graphics is disabled")
    }

    @Test
    @ResourceLock(SCREEN_LOCK)
    fun testJFrame() {
        assumeGraphicsSupported()
        doInMemoryTest(
            JFrame::class,
            """
            import javax.swing.JFrame
            val frame = JFrame("panel")
            frame.setSize(300, 300)
            frame.isVisible = true
            frame
            """.trimIndent(),
        )
    }

    @Test
    @ResourceLock(SCREEN_LOCK)
    fun testJDialog() {
        assumeGraphicsSupported()
        doInMemoryTest(
            JDialog::class,
            """
            import javax.swing.JDialog
            val dialog = JDialog()
            dialog.setSize(300, 300)
            dialog.isVisible = true
            dialog
            """.trimIndent(),
        )
    }

    @Test
    @ResourceLock(SCREEN_LOCK)
    fun testJComponent() {
        doInMemoryTest(
            JComponent::class,
            """
            import javax.swing.JPanel
            val panel = JPanel()
            panel.setSize(300, 300)
            panel
            """.trimIndent(),
        )
    }

    @Test
    @ResourceLock(SCREEN_LOCK)
    fun testScreenshotWithNoSize() {
        val panel = JPanel()
        assertNull(panel.takeScreenshot())
    }

    @Test
    @ResourceLock(SCREEN_LOCK)
    fun testScreenshotOfJFrame() {
        assumeGraphicsSupported()
        val frame = JFrame()
        frame.size = Dimension(100, 50)
        val button = JButton("Button 1")
        frame.contentPane.add(button)
        frame.isVisible = true
        val screenshot = frame.takeScreenshot()
        assertNotEmptyImage(screenshot)
    }

    @Test
    @ResourceLock(SCREEN_LOCK)
    fun testScreenshotOfJDialog() {
        assumeGraphicsSupported()
        val dialog = JDialog()
        dialog.size = Dimension(100, 50)
        val button = JButton("Button 1")
        dialog.contentPane.add(button)
        dialog.isVisible = true
        val screenshot = dialog.takeScreenshot()
        assertNotEmptyImage(screenshot)
    }

    @Test
    @ResourceLock(SCREEN_LOCK)
    fun testScreenshotOfJComponent() {
        val panel = JPanel()
        panel.size = Dimension(100, 50)
        val button = JButton("Button 1")
        button.size = Dimension(100, 50)
        panel.add(button)
        val screenshot = panel.takeScreenshot()
        assertNotEmptyImage(screenshot)
    }

    private fun doInMemoryTest(
        expectedOutputClass: KClass<*>,
        code: String,
    ) {
        val result = eval(code)
        result.renderedValue.shouldBeInstanceOf()
        result.displayValue.shouldBeInstanceOf()
        val displayObj = result.displayValue as MimeTypedResultEx
        val displayDataJson = displayObj.toJson(Json.EMPTY, null)
        val displayData = displayDataJson["data"] as JsonObject
        displayData.size.shouldBe(2)
        displayData.shouldContainKey("image/png")
        displayData.shouldContainKey(InMemoryMimeTypes.SWING)
        assertEquals("-1", (displayData[InMemoryMimeTypes.SWING] as JsonPrimitive).content)
        val inMemHolder = repl.notebook.sharedReplContext!!.inMemoryReplResultsHolder
        inMemHolder.size.shouldBe(1)
        inMemHolder.getReplResult("-1").shouldBeInstanceOf(expectedOutputClass)
    }

    // Check if a screenshot actually contains anything useful.
    // We assume "useful" means an image with width/length > 0 and doesn't only consist of
    // one color.
    private fun assertNotEmptyImage(image: BufferedImage?) {
        if (image == null) {
            fail("`null` image was returned")
        }
        assertNotEquals(0, image.width)
        assertNotEquals(0, image.height)
        val topLeftColor = image.getRGB(0, 0)
        for (x in 0 until image.width) {
            for (y in 0 until image.height) {
                if (image.getRGB(x, y) != topLeftColor) {
                    return
                }
            }
        }
        fail("Image only contained a single color: $topLeftColor")
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy