diff --git a/build.sbt b/build.sbt index 2dd1b2fb053..5e69fbedd9c 100644 --- a/build.sbt +++ b/build.sbt @@ -1747,9 +1747,10 @@ lazy val runtime = (project in file("engine/runtime")) "ENSO_TEST_DISABLE_IR_CACHE" -> "false", "ENSO_EDITION_PATH" -> file("distribution/editions").getCanonicalPath ), - Test / compile := (Test / compile) - .dependsOn(`runtime-fat-jar` / Compile / compileModuleInfo) - .value + Test / compile := { + (LocalProject("runtime-instrument-common") / Test / compile).value + (Test / compile).value + } ) .settings( (Compile / javacOptions) ++= Seq( @@ -1898,13 +1899,18 @@ lazy val `runtime-instrument-common` = Test / fork := true, Test / envVars ++= distributionEnvironmentOverrides ++ Map( "ENSO_TEST_DISABLE_IR_CACHE" -> "false" + ), + libraryDependencies ++= Seq( + "junit" % "junit" % junitVersion % Test, + "com.github.sbt" % "junit-interface" % junitIfVersion % Test, + "org.scalatest" %% "scalatest" % scalatestVersion % Test ) ) .dependsOn(`refactoring-utils`) .dependsOn( LocalProject( "runtime" - ) % "compile->compile;test->test;runtime->runtime;bench->bench" + ) % "compile->compile;runtime->runtime;bench->bench" ) lazy val `runtime-instrument-id-execution` = diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/LibrariesTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/LibrariesTest.scala index 8176c14ff91..06014b89ffb 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/LibrariesTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/LibrariesTest.scala @@ -59,7 +59,7 @@ class LibrariesTest ) "LocalLibraryManager" should { - "create a library project and include it on the list of local projects" taggedAs Flaky in { + "create a library project and include it on the list of local projects" taggedAs SkipOnFailure in { val client = getInitialisedWsClient() val testLibraryName = LibraryName("user", "My_Local_Lib") diff --git a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/command/AttachVisualizationCmd.scala b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/command/AttachVisualizationCmd.scala index df9d2baec70..1bfe1f5a649 100644 --- a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/command/AttachVisualizationCmd.scala +++ b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/command/AttachVisualizationCmd.scala @@ -34,7 +34,7 @@ class AttachVisualizationCmd( ) val maybeFutureExecutable = ctx.jobProcessor.run( - new UpsertVisualizationJob( + upsertVisualization( maybeRequestId, request.visualizationId, request.expressionId, @@ -48,6 +48,20 @@ class AttachVisualizationCmd( } } + def upsertVisualization( + maybeRequestId: Option[Api.RequestId], + visualizationId: Api.VisualizationId, + expressionId: Api.ExpressionId, + config: Api.VisualizationConfiguration + ): UpsertVisualizationJob = { + new UpsertVisualizationJob( + maybeRequestId, + visualizationId, + expressionId, + config + ) + } + override def toString: String = { "AttachVisualizationCmd(visualizationId: " + request.visualizationId + ",expressionId=" + request.expressionId + ")" } diff --git a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/command/ModifyVisualizationCmd.scala b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/command/ModifyVisualizationCmd.scala index d2abe393b29..8dc048b3ac4 100644 --- a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/command/ModifyVisualizationCmd.scala +++ b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/command/ModifyVisualizationCmd.scala @@ -33,7 +33,7 @@ class ModifyVisualizationCmd( ctx.executionService.getLogger.log( Level.FINE, "Modify visualization cmd for request id [{}] and visualization id [{}]", - Array(maybeRequestId, request.visualizationId) + Array[Object](maybeRequestId, request.visualizationId) ) val existingVisualization = ctx.contextManager.getVisualizationById( request.visualizationConfig.executionContextId, diff --git a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/DeserializeLibrarySuggestionsJob.scala b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/DeserializeLibrarySuggestionsJob.scala index a10b4865fa7..77e2950162a 100644 --- a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/DeserializeLibrarySuggestionsJob.scala +++ b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/DeserializeLibrarySuggestionsJob.scala @@ -30,7 +30,8 @@ final class DeserializeLibrarySuggestionsJob( override def run(implicit ctx: RuntimeContext): Unit = { ctx.executionService.getLogger.log( Level.FINE, - s"Deserializing suggestions for library [$libraryName]." + "Deserializing suggestions for library [{}].", + libraryName ) val serializationManager = SerializationManager( ctx.executionService.getContext.getCompiler.context diff --git a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledJob.scala b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledJob.scala index c085e7c5f81..a36e2c5b995 100644 --- a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledJob.scala +++ b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledJob.scala @@ -429,7 +429,8 @@ final class EnsureCompiledJob( if (invalidatedVisualizations.nonEmpty) { ctx.executionService.getLogger.log( Level.FINEST, - s"Invalidated visualizations [${invalidatedVisualizations.map(_.id)}]" + "Invalidated visualizations [{}]", + invalidatedVisualizations.map(_.id) ) } diff --git a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala index d1fe27e0552..d3c227ce00e 100644 --- a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala +++ b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala @@ -53,7 +53,7 @@ class UpsertVisualizationJob( override def equalsTo(that: UniqueJob[_]): Boolean = that match { case that: UpsertVisualizationJob => - this.expressionId == that.expressionId + this.expressionId == that.expressionId && this.visualizationId == that.visualizationId case _ => false } @@ -146,7 +146,7 @@ class UpsertVisualizationJob( ctx.executionService.getLogger.log( Level.SEVERE, "Visualization for expression {0} failed: {1} (evaluation result: {2})", - Array(expressionId, message, executionResult) + Array[Object](expressionId, message, executionResult) ) ctx.endpoint.sendToClient( Api.Response( @@ -159,6 +159,10 @@ class UpsertVisualizationJob( ) } + override def toString: String = { + s"UpsertVisualizationJob(visualizationId=$visualizationId, expressionId=$expressionId)" + } + } object UpsertVisualizationJob { diff --git a/engine/runtime-instrument-common/src/test/java/org/enso/interpreter/instrument/MockHandler.java b/engine/runtime-instrument-common/src/test/java/org/enso/interpreter/instrument/MockHandler.java index 479127dd828..20840b43228 100644 --- a/engine/runtime-instrument-common/src/test/java/org/enso/interpreter/instrument/MockHandler.java +++ b/engine/runtime-instrument-common/src/test/java/org/enso/interpreter/instrument/MockHandler.java @@ -1,11 +1,11 @@ package org.enso.interpreter.instrument; import org.enso.interpreter.instrument.command.CommandFactory; -import org.enso.interpreter.instrument.command.MockedCommandFactory$; +import org.enso.interpreter.instrument.command.MockedCommandFactory; public class MockHandler extends Handler { - private CommandFactory _cmdFactory = MockedCommandFactory$.MODULE$; + private CommandFactory _cmdFactory = new MockedCommandFactory(); @Override public CommandFactory cmdFactory() { diff --git a/engine/runtime-instrument-common/src/test/java/org/enso/interpreter/instrument/job/JobsTest.java b/engine/runtime-instrument-common/src/test/java/org/enso/interpreter/instrument/job/JobsTest.java new file mode 100644 index 00000000000..dc59bdae000 --- /dev/null +++ b/engine/runtime-instrument-common/src/test/java/org/enso/interpreter/instrument/job/JobsTest.java @@ -0,0 +1,37 @@ +package org.enso.interpreter.instrument.job; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.UUID; +import org.enso.polyglot.runtime.Runtime$Api$VisualizationConfiguration; +import org.enso.polyglot.runtime.Runtime$Api$VisualizationExpression$Text; +import org.junit.Test; +import scala.Option; + +public class JobsTest { + @Test + public void upsertJobUniqueness() { + var config = + new Runtime$Api$VisualizationConfiguration( + UUID.randomUUID(), new Runtime$Api$VisualizationExpression$Text("foo", "bar"), "test"); + var expression1 = UUID.randomUUID(); + var expression2 = UUID.randomUUID(); + var visualization1 = UUID.randomUUID(); + var visualization2 = UUID.randomUUID(); + var visualization3 = UUID.randomUUID(); + + var upsert1 = new UpsertVisualizationJob(Option.empty(), visualization1, expression1, config); + var upsert2 = new UpsertVisualizationJob(Option.empty(), visualization2, expression1, config); + var upsert3 = new UpsertVisualizationJob(Option.empty(), visualization3, expression2, config); + var upsert4 = new UpsertVisualizationJob(Option.empty(), visualization1, expression1, config); + var upsert5 = new UpsertVisualizationJob(Option.empty(), visualization1, expression2, config); + + assertFalse(upsert1.equalsTo(upsert2)); + assertFalse(upsert2.equalsTo(upsert3)); + assertFalse(upsert1.equalsTo(upsert3)); + assertTrue(upsert1.equalsTo(upsert4)); + assertFalse(upsert3.equalsTo(upsert4)); + assertFalse(upsert5.equalsTo(upsert3)); + } +} diff --git a/engine/runtime-instrument-common/src/test/java/org/enso/interpreter/runtime/ModuleTestUtils.java b/engine/runtime-instrument-common/src/test/java/org/enso/interpreter/runtime/ModuleTestUtils.java new file mode 100644 index 00000000000..5e6c24f59cd --- /dev/null +++ b/engine/runtime-instrument-common/src/test/java/org/enso/interpreter/runtime/ModuleTestUtils.java @@ -0,0 +1,15 @@ +package org.enso.interpreter.runtime; + +import org.enso.polyglot.CompilationStage; + +public final class ModuleTestUtils { + private ModuleTestUtils() {} + + public static void unsafeSetIr(Module m, org.enso.compiler.core.ir.Module ir) { + m.unsafeSetIr(ir); + } + + public static void unsafeSetCompilationStage(Module m, CompilationStage s) { + m.unsafeSetCompilationStage(s); + } +} diff --git a/engine/runtime-instrument-common/src/test/scala/org/enso/compiler/test/CompilerTestSetup.scala b/engine/runtime-instrument-common/src/test/scala/org/enso/compiler/test/CompilerTestSetup.scala new file mode 100644 index 00000000000..3c64093d646 --- /dev/null +++ b/engine/runtime-instrument-common/src/test/scala/org/enso/compiler/test/CompilerTestSetup.scala @@ -0,0 +1,228 @@ +package org.enso.compiler.test + +import org.enso.compiler.context.{FreshNameSupply, InlineContext, ModuleContext} +import org.enso.compiler.core.EnsoParser +import org.enso.compiler.core.Implicits.AsMetadata +import org.enso.compiler.core.ir.{Expression, Module} +import org.enso.compiler.core.ir.MetadataStorage.MetadataPair +import org.enso.compiler.data.BindingsMap.ModuleReference +import org.enso.compiler.data.{BindingsMap, CompilerConfig} +import org.enso.compiler.pass.analyse.BindingAnalysis +import org.enso.compiler.pass.{PassConfiguration, PassManager} +import org.enso.interpreter.runtime +import org.enso.interpreter.runtime.ModuleTestUtils +import org.enso.compiler.context.LocalScope +import org.enso.pkg.QualifiedName +import org.enso.polyglot.CompilationStage + +/** A reduced version of [[org.enso.compiler.test.CompilerRunner]] that avoids introducing a cyclic dependency + * to `runtime-instrument-common` subject. + */ +trait CompilerTestSetup { + // === IR Utilities ========================================================= + + /** An extension method to allow converting string source code to IR as a + * module. + * + * @param source the source code to convert + */ + implicit private class ToIrModule(source: String) { + + /** Converts program text to a top-level Enso module. + * + * @return the [[IR]] representing [[source]] + */ + def toIrModule: Module = { + val compiler = new EnsoParser() + try compiler.compile(source) + finally compiler.close() + } + } + + /** An extension method to allow converting string source code to IR as an + * expression. + * + * @param source the source code to convert + */ + implicit private class ToIrExpression(source: String) { + + /** Converts the program text to an Enso expression. + * + * @return the [[IR]] representing [[source]], if it is a valid expression + */ + def toIrExpression: Option[Expression] = { + val compiler = new EnsoParser() + try compiler.generateIRInline(compiler.parse(source)) + finally compiler.close() + } + } + + /** Provides an extension method allowing the running of a specified list of + * passes on the provided IR. + * + * @param ir the IR to run the passes on + */ + implicit private class RunPassesOnModule(ir: Module) { + + /** Executes the passes using `passManager` on the input [[ir]]. + * + * @param passManager the pass configuration + * @param moduleContext the module context it is executing in + * @return the result of executing the passes in `passManager` on [[ir]] + */ + def runPasses( + passManager: PassManager, + moduleContext: ModuleContext + ): Module = { + passManager.runPassesOnModule(ir, moduleContext) + } + } + + /** Provides an extension method allowing the running of a specified list of + * passes on the provided IR. + * + * @param ir the IR to run the passes on + */ + implicit private class RunPassesOnExpression(ir: Expression) { + + /** Executes the passes using `passManager` on the input [[ir]]. + * + * @param passManager the pass configuration + * @param inlineContext the inline context it is executing in + * @return the result of executing the passes in `passManager` on [[ir]] + */ + def runPasses( + passManager: PassManager, + inlineContext: InlineContext + ): Expression = { + passManager.runPassesInline(ir, inlineContext) + } + } + + /** Adds an extension method to preprocess the source as IR. + * + * @param source the source code to preprocess + */ + implicit class Preprocess(source: String)(implicit + passManager: PassManager + ) { + + /** Translates the source code into appropriate IR for testing this pass. + * + * @return IR appropriate for testing the alias analysis pass as a module + */ + def preprocessModule(implicit moduleContext: ModuleContext): Module = { + source.toIrModule.runPasses(passManager, moduleContext) + } + + /** Translates the source code into appropriate IR for testing this pass + * + * @return IR appropriate for testing the alias analysis pass as an + * expression + */ + def preprocessExpression(implicit + inlineContext: InlineContext + ): Option[Expression] = { + source.toIrExpression.map(_.runPasses(passManager, inlineContext)) + } + } + + // === IR Testing Utils ===================================================== + + /** Builds a module context with a mocked module for testing purposes. + * + * @param moduleName the name of the test module. + * @param freshNameSupply the fresh name supply to use in tests. + * @param passConfiguration any additional pass configuration. + * @return an instance of module context. + */ + def buildModuleContext( + moduleName: QualifiedName = QualifiedName.simpleName("Test_Module"), + freshNameSupply: Option[FreshNameSupply] = None, + passConfiguration: Option[PassConfiguration] = None, + compilerConfig: CompilerConfig = defaultConfig, + isGeneratingDocs: Boolean = false + ): ModuleContext = buildModuleContextModule( + moduleName, + freshNameSupply, + passConfiguration, + compilerConfig, + isGeneratingDocs + )._1 + + /** Builds a module context with a mocked module for testing purposes. + * + * @param moduleName the name of the test module. + * @param freshNameSupply the fresh name supply to use in tests. + * @param passConfiguration any additional pass configuration. + * @return an pair of module context and module. + */ + def buildModuleContextModule( + moduleName: QualifiedName = QualifiedName.simpleName("Test_Module"), + freshNameSupply: Option[FreshNameSupply] = None, + passConfiguration: Option[PassConfiguration] = None, + compilerConfig: CompilerConfig = defaultConfig, + isGeneratingDocs: Boolean = false + ): (ModuleContext, runtime.Module) = { + val mod = runtime.Module.empty(moduleName, null) + val ctx = ModuleContext( + module = mod.asCompilerModule(), + freshNameSupply = freshNameSupply, + passConfiguration = passConfiguration, + compilerConfig = compilerConfig, + isGeneratingDocs = isGeneratingDocs + ) + (ctx, mod) + } + + /** Builds an inline context with a mocked module for testing purposes. + * + * @param localScope the local scope for variable resolution. + * @param isInTailPosition whether the expression is being evaluated in + * a tail position. + * @param freshNameSupply the fresh name supply to use for name generation. + * @param passConfiguration any additional pass configuration. + * @return an instance of inline context. + */ + def buildInlineContext( + localScope: Option[LocalScope] = None, + isInTailPosition: Option[Boolean] = None, + freshNameSupply: Option[FreshNameSupply] = None, + passConfiguration: Option[PassConfiguration] = None, + compilerConfig: CompilerConfig = defaultConfig + ): InlineContext = { + val mod = + runtime.Module.empty(QualifiedName.simpleName("Test_Module"), null) + ModuleTestUtils.unsafeSetIr( + mod, + Module(List(), List(), List(), false, None) + .updateMetadata( + new MetadataPair( + BindingAnalysis, + BindingsMap( + List(), + ModuleReference.Concrete(mod.asCompilerModule()) + ) + ) + ) + ) + ModuleTestUtils.unsafeSetCompilationStage( + mod, + CompilationStage.AFTER_CODEGEN + ) + val mc = ModuleContext( + module = mod.asCompilerModule(), + compilerConfig = compilerConfig + ) + InlineContext( + module = mc, + freshNameSupply = freshNameSupply, + passConfiguration = passConfiguration, + localScope = localScope, + isInTailPosition = isInTailPosition, + compilerConfig = compilerConfig + ) + } + + val defaultConfig: CompilerConfig = CompilerConfig() +} diff --git a/engine/runtime-instrument-common/src/test/scala/org/enso/compiler/test/context/ChangesetBuilderTest.scala b/engine/runtime-instrument-common/src/test/scala/org/enso/compiler/test/context/ChangesetBuilderTest.scala index feef93103b4..f50c44759fe 100644 --- a/engine/runtime-instrument-common/src/test/scala/org/enso/compiler/test/context/ChangesetBuilderTest.scala +++ b/engine/runtime-instrument-common/src/test/scala/org/enso/compiler/test/context/ChangesetBuilderTest.scala @@ -13,15 +13,20 @@ import org.enso.compiler.core.ir.expression.Application import org.enso.compiler.core.ir.expression.errors import org.enso.compiler.core.ir.module.scope.definition import org.enso.compiler.pass.PassManager -import org.enso.compiler.test.CompilerTest +import org.enso.compiler.test.CompilerTestSetup import org.enso.compiler.context.LocalScope import org.enso.text.buffer.Rope import org.enso.text.editing.JavaEditorAdapter import org.enso.text.editing.model.{Position, Range, TextEdit} +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpecLike import java.util.UUID -class ChangesetBuilderTest extends CompilerTest { +class ChangesetBuilderTest + extends AnyWordSpecLike + with Matchers + with CompilerTestSetup { implicit val passManager: PassManager = new Passes(defaultConfig).passManager diff --git a/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/command/MockedCommandFactory.scala b/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/command/MockedCommandFactory.scala index 0e78fffd974..b251a96a19c 100644 --- a/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/command/MockedCommandFactory.scala +++ b/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/command/MockedCommandFactory.scala @@ -1,16 +1,25 @@ package org.enso.interpreter.instrument.command import org.enso.polyglot.runtime.Runtime.Api -object MockedCommandFactory extends CommandFactory { +class MockedCommandFactory extends CommandFactory { - private var editRequestCounter = 0 + private var editRequestCounter = 0 + private var attachVisualizationCounter = 0 override def createCommand(request: Api.Request): Command = { request.payload match { case payload: Api.EditFileNotification => - val cmd = new SlowEditFileCmd(payload, editRequestCounter) + val cmd = new SlowEditFileCmd(payload, editRequestCounter % 2 == 0) editRequestCounter += 1 cmd + case payload: Api.AttachVisualization => + val cmd = new SlowAttachVisualizationCmd( + request.requestId, + payload, + attachVisualizationCounter % 2 == 0 + ) + attachVisualizationCounter += 1 + cmd case _ => super.createCommand(request) } diff --git a/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/command/SlowAttachVisualizationCmd.scala b/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/command/SlowAttachVisualizationCmd.scala new file mode 100644 index 00000000000..d1c328889a9 --- /dev/null +++ b/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/command/SlowAttachVisualizationCmd.scala @@ -0,0 +1,35 @@ +package org.enso.interpreter.instrument.command + +import org.enso.interpreter.instrument.job.{ + SlowUpsertVisualizationJob, + UpsertVisualizationJob +} +import org.enso.polyglot.runtime.Runtime.Api +import org.slf4j.LoggerFactory + +class SlowAttachVisualizationCmd( + maybeRequestId: Option[Api.RequestId], + request: Api.AttachVisualization, + delay: Boolean +) extends AttachVisualizationCmd(maybeRequestId, request) { + + private val logger = + LoggerFactory.getLogger(classOf[SlowAttachVisualizationCmd]) + + override def upsertVisualization( + maybeRequestId: Option[Api.RequestId], + visualizationId: Api.VisualizationId, + expressionId: Api.ExpressionId, + config: Api.VisualizationConfiguration + ): UpsertVisualizationJob = { + + logger.info("Delaying upsert for {}: {}", request.visualizationId, delay) + new SlowUpsertVisualizationJob( + maybeRequestId, + visualizationId, + expressionId, + config, + delay + ) + } +} diff --git a/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/command/SlowEditFileCmd.scala b/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/command/SlowEditFileCmd.scala index 9f85c279a32..a1ae78c2628 100644 --- a/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/command/SlowEditFileCmd.scala +++ b/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/command/SlowEditFileCmd.scala @@ -5,7 +5,7 @@ import org.enso.polyglot.runtime.Runtime.Api import scala.concurrent.ExecutionContext -class SlowEditFileCmd(request: Api.EditFileNotification, counter: Int) +class SlowEditFileCmd(request: Api.EditFileNotification, delay: Boolean) extends EditFileCmd(request) { override def executeSynchronously(implicit @@ -13,7 +13,7 @@ class SlowEditFileCmd(request: Api.EditFileNotification, counter: Int) ec: ExecutionContext ): Unit = { if ( - ctx.executionService.getContext.isRandomDelayedCommandExecution && counter % 2 == 0 + ctx.executionService.getContext.isRandomDelayedCommandExecution && delay ) { try { Thread.sleep(2000) diff --git a/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/job/SlowUpsertVisualizationJob.scala b/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/job/SlowUpsertVisualizationJob.scala new file mode 100644 index 00000000000..0f1834648c7 --- /dev/null +++ b/engine/runtime-instrument-common/src/test/scala/org/enso/interpreter/instrument/job/SlowUpsertVisualizationJob.scala @@ -0,0 +1,33 @@ +package org.enso.interpreter.instrument.job + +import org.enso.interpreter.instrument.execution.{Executable, RuntimeContext} +import org.enso.polyglot.runtime.Runtime.Api + +import scala.annotation.unused + +class SlowUpsertVisualizationJob( + @unused requestId: Option[Api.RequestId], + visualizationId: Api.VisualizationId, + expressionId: Api.ExpressionId, + config: Api.VisualizationConfiguration, + delay: Boolean +) extends UpsertVisualizationJob( + requestId, + visualizationId, + expressionId, + config + ) { + + override val isCancellable: Boolean = true + override val mayInterruptIfRunning: Boolean = true + + override def run(implicit ctx: RuntimeContext): Option[Executable] = { + if ( + ctx.executionService.getContext.isRandomDelayedCommandExecution && delay + ) { + Thread.sleep(1000) + } + + super.run(ctx) + } +} diff --git a/engine/runtime/src/test/resources/application-test.conf b/engine/runtime/src/test/resources/application-test.conf index c646131acb5..6f5255389f6 100644 --- a/engine/runtime/src/test/resources/application-test.conf +++ b/engine/runtime/src/test/resources/application-test.conf @@ -1 +1,26 @@ akka.coordinated-shutdown.run-by-actor-system-terminate = off +logging-service { + logger { + akka.actor = info + akka.event = error + akka.routing = error + akka.io = error + akka.stream = error + slick.jdbc.JdbcBackend.statement = error # log SQL queries on debug level + slick."*" = error + org.eclipse.jgit = error + io.methvin.watcher = error + } + appenders = [ + { + name = "memory" + forward-to = console + }, + { + name = "console" + pattern = "[%level] [%d{yyyy-MM-ddTHH:mm:ssXXX}] [%logger] %msg%n" + } + ] + default-appender = memory + log-level = "error" +} diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala index 8a6529aa4a1..9f195c28c70 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala @@ -8,7 +8,6 @@ import org.enso.polyglot.runtime.Runtime.Api import org.enso.text.editing.model import org.enso.text.editing.model.TextEdit import org.graalvm.polyglot.Context -import org.scalatest.BeforeAndAfterEach import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers @@ -19,16 +18,11 @@ import java.util.UUID import java.util.logging.Level @scala.annotation.nowarn("msg=multiarg infix syntax") -class RuntimeVisualizationsTest - extends AnyFlatSpec - with Matchers - with BeforeAndAfterEach { +class RuntimeVisualizationsTest extends AnyFlatSpec with Matchers { // === Test Utilities ======================================================= - var context: TestContext = _ - - class TestContext(packageName: String) + class TestContext(packageName: String, sequentialExecution: Boolean) extends InstrumentTestContext(packageName) { val out: ByteArrayOutputStream = new ByteArrayOutputStream() @@ -39,7 +33,14 @@ class RuntimeVisualizationsTest .allowAllAccess(true) .option(RuntimeOptions.PROJECT_ROOT, pkg.root.getAbsolutePath) .option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName()) - .option(RuntimeOptions.INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION, "true") + .option( + RuntimeOptions.INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION, + sequentialExecution.toString + ) + .option( + RuntimeOptions.INTERPRETER_RANDOM_DELAYED_COMMAND_EXECUTION, + (!sequentialExecution).toString + ) .option(RuntimeOptions.ENABLE_PROJECT_SUGGESTIONS, "false") .option(RuntimeOptions.ENABLE_GLOBAL_SUGGESTIONS, "false") .option(RuntimeOptions.ENABLE_EXECUTION_TIMER, "false") @@ -83,7 +84,7 @@ class RuntimeVisualizationsTest // === The Tests ========================================================== - object Main { + object Main { context => val metadata = new Metadata @@ -301,797 +302,812 @@ class RuntimeVisualizationsTest } - override protected def beforeEach(): Unit = { - context = new TestContext("Test") - context.init() - val Some(Api.Response(_, Api.InitializedNotification())) = context.receive - } - - override protected def afterEach(): Unit = { - if (context != null) { - context.close() - context.out.reset() - context = null + def withContext( + sequentialExecution: Boolean = true + )(f: TestContext => Unit): Unit = { + val context = new TestContext("Test", sequentialExecution) + try { + context.init() + val Some(Api.Response(_, Api.InitializedNotification())) = context.receive + f(context) + } finally { + if (context != null) { + context.close() + context.out.reset() + } } } - it should "emit visualization update when expression is computed" in { - val idMainRes = context.Main.metadata.addItem(99, 1) - val contents = context.Main.code - val mainFile = context.writeMain(context.Main.code) - val moduleName = "Enso_Test.Test.Main" - val visualizationFile = - context.writeInSrcDir("Visualization", context.Visualization.code) + it should "emit visualization update when expression is computed" in withContext() { + context => + val idMainRes = context.Main.metadata.addItem(99, 1) + val contents = context.Main.code + val mainFile = context.writeMain(context.Main.code) + val moduleName = "Enso_Test.Test.Main" + val visualizationFile = + context.writeInSrcDir("Visualization", context.Visualization.code) - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() - context.send( - Api.Request( - requestId, - Api.OpenFileRequest( - visualizationFile, - context.Visualization.code - ) - ) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 6 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - TestMessages.update(contextId, idMainRes, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMainRes, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Visualization", - "x -> encode x" - ), - "Enso_Test.Test.Visualization" + context.send( + Api.Request( + requestId, + Api.OpenFileRequest( + visualizationFile, + context.Visualization.code ) ) ) - ) - val attachVisualizationResponses = - context.receiveNIgnoreExpressionUpdates(3) - attachVisualizationResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMainRes` - ), - data - ) - ) => - data - } - data.sameElements("50".getBytes) shouldBe true - - // recompute - context.send( - Api.Request(requestId, Api.RecomputeContextRequest(contextId, None, None)) - ) - - val recomputeResponses = context.receiveNIgnoreExpressionUpdates(3) - recomputeResponses should contain allOf ( - Api.Response(requestId, Api.RecomputeContextResponse(contextId)), - context.executionComplete(contextId) - ) - val Some(data2) = recomputeResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMainRes` - ), - data - ) - ) => - data - } - data2.sameElements("50".getBytes) shouldBe true - } - - it should "emit visualization update when expression is cached" in { - val contents = context.Main.code - val mainFile = context.writeMain(context.Main.code) - val moduleName = "Enso_Test.Test.Main" - val visualizationFile = - context.writeInSrcDir("Visualization", context.Visualization.code) - - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - - context.send( - Api.Request( - requestId, - Api.OpenFileRequest( - visualizationFile, - context.Visualization.code - ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) ) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 5 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - context.executionComplete(contextId) - ) + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 6 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + TestMessages.update(contextId, idMainRes, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - context.Main.idMainX, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Visualization", - "x -> encode x" - ), - "Enso_Test.Test.Visualization" + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMainRes, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Visualization", + "x -> encode x" + ), + "Enso_Test.Test.Visualization" + ) ) ) ) - ) - val attachVisualizationResponses = context.receiveN(2) - attachVisualizationResponses should contain( - Api.Response(requestId, Api.VisualizationAttached()) - ) - val expectedExpressionId = context.Main.idMainX - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `expectedExpressionId` + val attachVisualizationResponses = + context.receiveNIgnoreExpressionUpdates(3) + attachVisualizationResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMainRes` + ), + data + ) + ) => + data + } + data.sameElements("50".getBytes) shouldBe true + + // recompute + context.send( + Api.Request( + requestId, + Api.RecomputeContextRequest(contextId, None, None) + ) + ) + + val recomputeResponses = context.receiveNIgnoreExpressionUpdates(3) + recomputeResponses should contain allOf ( + Api.Response(requestId, Api.RecomputeContextResponse(contextId)), + context.executionComplete(contextId) + ) + val Some(data2) = recomputeResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMainRes` + ), + data + ) + ) => + data + } + data2.sameElements("50".getBytes) shouldBe true + } + + it should "emit visualization update when expression is cached" in withContext() { + context => + val contents = context.Main.code + val mainFile = context.writeMain(context.Main.code) + val moduleName = "Enso_Test.Test.Main" + val visualizationFile = + context.writeInSrcDir("Visualization", context.Visualization.code) + + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + + context.send( + Api.Request( + requestId, + Api.OpenFileRequest( + visualizationFile, + context.Visualization.code + ) + ) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 5 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + context.Main.idMainX, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Visualization", + "x -> encode x" ), - data + "Enso_Test.Test.Visualization" ) - ) => - data - } - data.sameElements("6".getBytes) shouldBe true + ) + ) + ) + val attachVisualizationResponses = context.receiveN(2) + attachVisualizationResponses should contain( + Api.Response(requestId, Api.VisualizationAttached()) + ) + val expectedExpressionId = context.Main.idMainX + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId` + ), + data + ) + ) => + data + } + data.sameElements("6".getBytes) shouldBe true - // recompute - context.send( - Api.Request(requestId, Api.RecomputeContextRequest(contextId, None, None)) - ) - context.receiveNIgnoreExpressionUpdates(2) should contain allOf ( - Api.Response(requestId, Api.RecomputeContextResponse(contextId)), - context.executionComplete(contextId) - ) + // recompute + context.send( + Api.Request( + requestId, + Api.RecomputeContextRequest(contextId, None, None) + ) + ) + context.receiveNIgnoreExpressionUpdates(2) should contain allOf ( + Api.Response(requestId, Api.RecomputeContextResponse(contextId)), + context.executionComplete(contextId) + ) - // recompute invalidating x - context.send( - Api.Request( - requestId, - Api.RecomputeContextRequest( + // recompute invalidating x + context.send( + Api.Request( + requestId, + Api.RecomputeContextRequest( + contextId, + Some( + Api.InvalidatedExpressions.Expressions( + Vector(context.Main.idMainX) + ) + ), + None + ) + ) + ) + val recomputeResponses2 = context.receiveNIgnoreExpressionUpdates(3) + recomputeResponses2 should contain allOf ( + Api.Response(requestId, Api.RecomputeContextResponse(contextId)), + context.executionComplete(contextId) + ) + val Some(data2) = recomputeResponses2.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId` + ), + data + ) + ) => + data + } + data2.sameElements("6".getBytes) shouldBe true + } + + it should "emit visualization update when expression is modified" in withContext() { + context => + val contents = context.Main.code + val moduleName = "Enso_Test.Test.Main" + val mainFile = context.writeMain(contents) + val visualizationFile = + context.writeInSrcDir("Visualization", context.Visualization.code) + + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + + // open files + context.send( + Api.Request( + requestId, + Api.OpenFileRequest( + visualizationFile, + context.Visualization.code + ) + ) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + + context.receiveNIgnorePendingExpressionUpdates( + 5 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + context.Main.idMainX, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Visualization", + "x -> encode x" + ), + "Enso_Test.Test.Visualization" + ) + ) + ) + ) + val attachVisualizationResponses = context.receiveN(2) + attachVisualizationResponses should contain( + Api.Response(requestId, Api.VisualizationAttached()) + ) + val expectedExpressionId = context.Main.idMainX + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId` + ), + data + ) + ) => + data + } + data.sameElements("6".getBytes) shouldBe true + + // Modify the file + context.send( + Api.Request( + Api.EditFileNotification( + mainFile, + Seq( + TextEdit( + model.Range(model.Position(4, 8), model.Position(4, 9)), + "5" + ) + ), + execute = true + ) + ) + ) + + val editFileResponse = context.receiveNIgnoreExpressionUpdates(2) + editFileResponse should contain( + context.executionComplete(contextId) + ) + val Some(data1) = editFileResponse.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId` + ), + data + ) + ) => + data + } + data1.sameElements("5".getBytes) shouldBe true + } + + it should "emit visualization update when transitive expression is modified" in withContext() { + context => + val contents = context.Main.code + val moduleName = "Enso_Test.Test.Main" + val mainFile = context.writeMain(contents) + val visualizationFile = + context.writeInSrcDir("Visualization", context.Visualization.code) + + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + + // open files + context.send( + Api.Request( + requestId, + Api.OpenFileRequest( + visualizationFile, + context.Visualization.code + ) + ) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + + context.receiveNIgnorePendingExpressionUpdates( + 5 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + context.Main.idMainZ, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Visualization", + "encode" + ), + "Enso_Test.Test.Visualization" + ) + ) + ) + ) + val attachVisualizationResponses = context.receiveN(2) + attachVisualizationResponses should contain( + Api.Response(requestId, Api.VisualizationAttached()) + ) + val expectedExpressionId = context.Main.idMainZ + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId` + ), + data + ) + ) => + data + } + data.sameElements("50".getBytes) shouldBe true + + // Modify the file + context.send( + Api.Request( + Api.EditFileNotification( + mainFile, + Seq( + TextEdit( + model.Range(model.Position(4, 8), model.Position(4, 9)), + "5" + ) + ), + execute = true + ) + ) + ) + + val editFileResponse = context.receiveNIgnoreExpressionUpdates(2) + editFileResponse should contain( + context.executionComplete(contextId) + ) + val Some(data1) = editFileResponse.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId` + ), + data + ) + ) => + data + } + data1.sameElements("45".getBytes) shouldBe true + } + + it should "emit visualization update when frame popped" in withContext() { + context => + val contents = context.Main.code + val moduleName = "Enso_Test.Test.Main" + val mainFile = context.writeMain(contents) + val visualizationFile = + context.writeInSrcDir("Visualization", context.Visualization.code) + + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + + // open files + context.send( + Api.Request( + requestId, + Api.OpenFileRequest( + visualizationFile, + context.Visualization.code + ) + ) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + + context.receiveNIgnorePendingExpressionUpdates( + 5 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + context.Main.idMainZ, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Visualization", + "encode" + ), + "Enso_Test.Test.Visualization" + ) + ) + ) + ) + val attachVisualizationResponses = context.receiveN(2) + attachVisualizationResponses should contain( + Api.Response(requestId, Api.VisualizationAttached()) + ) + val expectedExpressionId = context.Main.idMainZ + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId` + ), + data + ) + ) => + data + } + new String(data) shouldEqual "50" + + // push foo call + val item2 = Api.StackItem.LocalCall(context.Main.idMainY) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item2)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 4 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.fooY(contextId), + context.Main.Update.fooZ(contextId), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + context.Main.idFooZ, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Visualization", + "encode" + ), + "Enso_Test.Test.Visualization" + ) + ) + ) + ) + val attachVisualizationResponses2 = context.receiveN(2) + attachVisualizationResponses2 should contain( + Api.Response(requestId, Api.VisualizationAttached()) + ) + val expectedExpressionId2 = context.Main.idFooZ + val Some(data2) = attachVisualizationResponses2.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId2` + ), + data + ) + ) => + data + } + new String(data2) shouldEqual "45" + + // Modify the file + context.send( + Api.Request( + Api.EditFileNotification( + mainFile, + Seq( + TextEdit( + model.Range(model.Position(10, 15), model.Position(10, 16)), + "5" + ) + ), + execute = true + ) + ) + ) + + val editFileResponse = context.receiveNIgnorePendingExpressionUpdates(4) + editFileResponse should contain allOf ( + TestMessages.update( contextId, - Some( - Api.InvalidatedExpressions.Expressions(Vector(context.Main.idMainX)) - ), - None - ) - ) - ) - val recomputeResponses2 = context.receiveNIgnoreExpressionUpdates(3) - recomputeResponses2 should contain allOf ( - Api.Response(requestId, Api.RecomputeContextResponse(contextId)), - context.executionComplete(contextId) - ) - val Some(data2) = recomputeResponses2.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `expectedExpressionId` - ), - data - ) - ) => - data - } - data2.sameElements("6".getBytes) shouldBe true - } - - it should "emit visualization update when expression is modified" in { - val contents = context.Main.code - val moduleName = "Enso_Test.Test.Main" - val mainFile = context.writeMain(contents) - val visualizationFile = - context.writeInSrcDir("Visualization", context.Visualization.code) - - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - - // open files - context.send( - Api.Request( - requestId, - Api.OpenFileRequest( - visualizationFile, - context.Visualization.code - ) - ) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - - context.receiveNIgnorePendingExpressionUpdates( - 5 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - context.Main.idMainX, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Visualization", - "x -> encode x" - ), - "Enso_Test.Test.Visualization" - ) - ) - ) - ) - val attachVisualizationResponses = context.receiveN(2) - attachVisualizationResponses should contain( - Api.Response(requestId, Api.VisualizationAttached()) - ) - val expectedExpressionId = context.Main.idMainX - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `expectedExpressionId` - ), - data - ) - ) => - data - } - data.sameElements("6".getBytes) shouldBe true - - // Modify the file - context.send( - Api.Request( - Api.EditFileNotification( - mainFile, - Seq( - TextEdit( - model.Range(model.Position(4, 8), model.Position(4, 9)), - "5" + context.Main.idFooY, + ConstantsGen.INTEGER, + methodCall = Some( + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Data.Numbers", + "Standard.Base.Data.Numbers.Integer", + "+" + ) ) ), - execute = true - ) - ) - ) - - val editFileResponse = context.receiveNIgnoreExpressionUpdates(2) - editFileResponse should contain( - context.executionComplete(contextId) - ) - val Some(data1) = editFileResponse.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `expectedExpressionId` - ), - data - ) - ) => - data - } - data1.sameElements("5".getBytes) shouldBe true - } - - it should "emit visualization update when transitive expression is modified" in { - val contents = context.Main.code - val moduleName = "Enso_Test.Test.Main" - val mainFile = context.writeMain(contents) - val visualizationFile = - context.writeInSrcDir("Visualization", context.Visualization.code) - - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - - // open files - context.send( - Api.Request( - requestId, - Api.OpenFileRequest( - visualizationFile, - context.Visualization.code - ) - ) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - - context.receiveNIgnorePendingExpressionUpdates( - 5 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - context.Main.idMainZ, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Visualization", - "encode" - ), - "Enso_Test.Test.Visualization" - ) - ) - ) - ) - val attachVisualizationResponses = context.receiveN(2) - attachVisualizationResponses should contain( - Api.Response(requestId, Api.VisualizationAttached()) - ) - val expectedExpressionId = context.Main.idMainZ - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `expectedExpressionId` - ), - data - ) - ) => - data - } - data.sameElements("50".getBytes) shouldBe true - - // Modify the file - context.send( - Api.Request( - Api.EditFileNotification( - mainFile, - Seq( - TextEdit( - model.Range(model.Position(4, 8), model.Position(4, 9)), - "5" - ) - ), - execute = true - ) - ) - ) - - val editFileResponse = context.receiveNIgnoreExpressionUpdates(2) - editFileResponse should contain( - context.executionComplete(contextId) - ) - val Some(data1) = editFileResponse.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `expectedExpressionId` - ), - data - ) - ) => - data - } - data1.sameElements("45".getBytes) shouldBe true - } - - it should "emit visualization update when frame popped" in { - val contents = context.Main.code - val moduleName = "Enso_Test.Test.Main" - val mainFile = context.writeMain(contents) - val visualizationFile = - context.writeInSrcDir("Visualization", context.Visualization.code) - - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - - // open files - context.send( - Api.Request( - requestId, - Api.OpenFileRequest( - visualizationFile, - context.Visualization.code - ) - ) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - - context.receiveNIgnorePendingExpressionUpdates( - 5 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - context.Main.idMainZ, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Visualization", - "encode" - ), - "Enso_Test.Test.Visualization" - ) - ) - ) - ) - val attachVisualizationResponses = context.receiveN(2) - attachVisualizationResponses should contain( - Api.Response(requestId, Api.VisualizationAttached()) - ) - val expectedExpressionId = context.Main.idMainZ - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `expectedExpressionId` - ), - data - ) - ) => - data - } - new String(data) shouldEqual "50" - - // push foo call - val item2 = Api.StackItem.LocalCall(context.Main.idMainY) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item2)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 4 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.fooY(contextId), - context.Main.Update.fooZ(contextId), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, + typeChanged = false + ), + TestMessages.update( + contextId, context.Main.idFooZ, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Visualization", - "encode" - ), - "Enso_Test.Test.Visualization" - ) - ) - ) - ) - val attachVisualizationResponses2 = context.receiveN(2) - attachVisualizationResponses2 should contain( - Api.Response(requestId, Api.VisualizationAttached()) - ) - val expectedExpressionId2 = context.Main.idFooZ - val Some(data2) = attachVisualizationResponses2.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `expectedExpressionId2` - ), - data - ) - ) => - data - } - new String(data2) shouldEqual "45" - - // Modify the file - context.send( - Api.Request( - Api.EditFileNotification( - mainFile, - Seq( - TextEdit( - model.Range(model.Position(10, 15), model.Position(10, 16)), - "5" + ConstantsGen.INTEGER, + methodCall = Some( + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Data.Numbers", + "Standard.Base.Data.Numbers.Integer", + "*" + ) ) ), - execute = true - ) + typeChanged = false + ), + context.executionComplete(contextId) ) - ) + val Some(data3) = editFileResponse.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId2` + ), + data + ) + ) => + data + } + new String(data3) shouldEqual "55" - val editFileResponse = context.receiveNIgnorePendingExpressionUpdates(4) - editFileResponse should contain allOf ( - TestMessages.update( - contextId, - context.Main.idFooY, - ConstantsGen.INTEGER, - methodCall = Some( - Api.MethodCall( - Api.MethodPointer( - "Standard.Base.Data.Numbers", - "Standard.Base.Data.Numbers.Integer", - "+" - ) - ) - ), - typeChanged = false - ), - TestMessages.update( - contextId, - context.Main.idFooZ, - ConstantsGen.INTEGER, - methodCall = Some( - Api.MethodCall( - Api.MethodPointer( - "Standard.Base.Data.Numbers", - "Standard.Base.Data.Numbers.Integer", - "*" - ) - ) - ), - typeChanged = false - ), - context.executionComplete(contextId) - ) - val Some(data3) = editFileResponse.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `expectedExpressionId2` - ), - data - ) - ) => - data - } - new String(data3) shouldEqual "55" + // pop foo call + context.send(Api.Request(requestId, Api.PopContextRequest(contextId))) + val popContextResponses = context.receiveNIgnorePendingExpressionUpdates( + 5 + ) + popContextResponses should contain allOf ( + Api.Response(requestId, Api.PopContextResponse(contextId)), + context.Main.Update.mainY(contextId, typeChanged = false), + context.Main.Update.mainZ(contextId, typeChanged = false), + context.executionComplete(contextId) + ) - // pop foo call - context.send(Api.Request(requestId, Api.PopContextRequest(contextId))) - val popContextResponses = context.receiveNIgnorePendingExpressionUpdates( - 5 - ) - popContextResponses should contain allOf ( - Api.Response(requestId, Api.PopContextResponse(contextId)), - context.Main.Update.mainY(contextId, typeChanged = false), - context.Main.Update.mainZ(contextId, typeChanged = false), - context.executionComplete(contextId) - ) - - val Some(data4) = popContextResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `expectedExpressionId` - ), - data - ) - ) => - data - } - new String(data4) shouldEqual "60" + val Some(data4) = popContextResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId` + ), + data + ) + ) => + data + } + new String(data4) shouldEqual "60" } - it should "be able to modify visualizations" in { + it should "be able to modify visualizations" in withContext() { context => val contents = context.Main.code val mainFile = context.writeMain(contents) val visualizationFile = @@ -1226,20 +1242,24 @@ class RuntimeVisualizationsTest dataAfterModification.sameElements("7".getBytes) shouldBe true } - it should "not emit visualization update when visualization is detached" in { + it should "be able to modify visualizations for pending visualizations" in withContext( + sequentialExecution = false + ) { context => val contents = context.Main.code val mainFile = context.writeMain(contents) val visualizationFile = context.writeInSrcDir("Visualization", context.Visualization.code) - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val visualizationId2 = UUID.randomUUID() // open files context.send( Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) ) + context.receive shouldEqual Some( Api.Response(Some(requestId), Api.OpenFileResponse) ) @@ -1262,7 +1282,26 @@ class RuntimeVisualizationsTest Api.Response(requestId, Api.CreateContextResponse(contextId)) ) - // attach visualization + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 5 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + context.executionComplete(contextId) + ) + + // attach visualizations context.send( Api.Request( requestId, @@ -1280,36 +1319,348 @@ class RuntimeVisualizationsTest ) ) ) - context.receiveN(2) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.VisualizationAttached()), - Api.Response( - Api.ExecutionFailed( - contextId, - Api.ExecutionResult.Failure("Execution stack is empty.", None) + + context.send( + Api.Request( + Api.EditFileNotification( + mainFile, + Seq( + TextEdit( + model.Range(model.Position(4, 8), model.Position(4, 9)), + "7" + ) + ), + execute = true ) ) ) - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "main"), - None, - Vector() - ) context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId2, + context.Main.idMainX, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Visualization", + "x -> encode x" + ), + "Enso_Test.Test.Visualization" + ) + ) + ) ) - val pushResponses = context.receiveNIgnorePendingExpressionUpdates(6) - pushResponses should contain allOf ( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - context.executionComplete(contextId) + + val attachVisualizationResponses = context.receiveN(2) + + attachVisualizationResponses.filter( + _.payload.isInstanceOf[Api.VisualizationAttached] + ) shouldEqual List( + Api.Response(requestId, Api.VisualizationAttached()), + Api.Response(requestId, Api.VisualizationAttached()) ) + + val responses = context.receiveNIgnoreExpressionUpdates(3) + val visualizationUpdatesResponses = + responses.filter(_.payload.isInstanceOf[Api.VisualizationUpdate]) val expectedExpressionId = context.Main.idMainX - val Some(data) = - pushResponses.collectFirst { + val visualizationUpdates = visualizationUpdatesResponses.map( + _.payload.asInstanceOf[Api.VisualizationUpdate] + ) + val visContexts = visualizationUpdates.map(_.visualizationContext) + visContexts should contain allOf ( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId` + ), + Api.VisualizationContext( + `visualizationId2`, + `contextId`, + `expectedExpressionId` + ), + ) + val data = visualizationUpdates.head.data + data.sameElements("6".getBytes) shouldBe true + + // modify visualization + context.send( + Api.Request( + requestId, + Api.ModifyVisualization( + visualizationId, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Visualization", + "x -> incAndEncode x" + ), + "Enso_Test.Test.Visualization" + ) + ) + ) + ) + val modifyVisualizationResponses = context.receiveN(5) + modifyVisualizationResponses should contain( + Api.Response(requestId, Api.VisualizationModified()) + ) + val Some((dataAfterModification, foundVisualizatonId)) = + modifyVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + modifiedId, + `contextId`, + `expectedExpressionId` + ), + data + ) + ) => + (data, modifiedId) + } + + List(visualizationId, visualizationId2) should contain(foundVisualizatonId) + + dataAfterModification.sameElements("7".getBytes) shouldBe true + } + + it should "not emit visualization update when visualization is detached" in withContext() { + context => + val contents = context.Main.code + val mainFile = context.writeMain(contents) + val visualizationFile = + context.writeInSrcDir("Visualization", context.Visualization.code) + + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + + // open files + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + context.send( + Api.Request( + requestId, + Api.OpenFileRequest( + visualizationFile, + context.Visualization.code + ) + ) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + context.Main.idMainX, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Visualization", + "x -> encode x" + ), + "Enso_Test.Test.Visualization" + ) + ) + ) + ) + context.receiveN(2) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.VisualizationAttached()), + Api.Response( + Api.ExecutionFailed( + contextId, + Api.ExecutionResult.Failure("Execution stack is empty.", None) + ) + ) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + val pushResponses = context.receiveNIgnorePendingExpressionUpdates(6) + pushResponses should contain allOf ( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + context.executionComplete(contextId) + ) + val expectedExpressionId = context.Main.idMainX + val Some(data) = + pushResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `expectedExpressionId` + ), + data + ) + ) => + data + } + data.sameElements("6".getBytes) shouldBe true + + // detach visualization + context.send( + Api.Request( + requestId, + Api.DetachVisualization( + contextId, + visualizationId, + context.Main.idMainX + ) + ) + ) + context.receive shouldEqual Some( + Api.Response(requestId, Api.VisualizationDetached()) + ) + + // recompute + context.send( + Api.Request( + requestId, + Api.RecomputeContextRequest(contextId, None, None) + ) + ) + context.receiveNIgnoreExpressionUpdates( + 2 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.RecomputeContextResponse(contextId)), + context.executionComplete(contextId) + ) + + // recompute invalidating x + context.send( + Api.Request( + requestId, + Api.RecomputeContextRequest( + contextId, + Some( + Api.InvalidatedExpressions.Expressions( + Vector(context.Main.idMainX) + ) + ), + None + ) + ) + ) + context.receiveNIgnoreExpressionUpdates( + 2 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.RecomputeContextResponse(contextId)), + context.executionComplete(contextId) + ) + } + + it should "not emit visualization update when expression is not affected by the change" in withContext() { + context => + val contents = context.Main.code + val moduleName = "Enso_Test.Test.Main" + val mainFile = context.writeMain(contents) + val visualizationFile = + context.writeInSrcDir("Visualization", context.Visualization.code) + + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + + // open files + context.send( + Api.Request( + requestId, + Api.OpenFileRequest( + visualizationFile, + context.Visualization.code + ) + ) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + + context.receiveNIgnorePendingExpressionUpdates( + 5 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + context.Main.idMainX, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Visualization", + "encode" + ), + "Enso_Test.Test.Visualization" + ) + ) + ) + ) + val attachVisualizationResponses = context.receiveN(2) + attachVisualizationResponses should contain( + Api.Response(requestId, Api.VisualizationAttached()) + ) + val expectedExpressionId = context.Main.idMainX + val Some(data) = attachVisualizationResponses.collectFirst { case Api.Response( None, Api.VisualizationUpdate( @@ -1323,175 +1674,32 @@ class RuntimeVisualizationsTest ) => data } - data.sameElements("6".getBytes) shouldBe true + data.sameElements("6".getBytes) shouldBe true - // detach visualization - context.send( - Api.Request( - requestId, - Api.DetachVisualization( - contextId, - visualizationId, - context.Main.idMainX - ) - ) - ) - context.receive shouldEqual Some( - Api.Response(requestId, Api.VisualizationDetached()) - ) - - // recompute - context.send( - Api.Request(requestId, Api.RecomputeContextRequest(contextId, None, None)) - ) - context.receiveNIgnoreExpressionUpdates( - 2 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.RecomputeContextResponse(contextId)), - context.executionComplete(contextId) - ) - - // recompute invalidating x - context.send( - Api.Request( - requestId, - Api.RecomputeContextRequest( - contextId, - Some( - Api.InvalidatedExpressions.Expressions(Vector(context.Main.idMainX)) - ), - None - ) - ) - ) - context.receiveNIgnoreExpressionUpdates( - 2 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.RecomputeContextResponse(contextId)), - context.executionComplete(contextId) - ) - } - - it should "not emit visualization update when expression is not affected by the change" in { - val contents = context.Main.code - val moduleName = "Enso_Test.Test.Main" - val mainFile = context.writeMain(contents) - val visualizationFile = - context.writeInSrcDir("Visualization", context.Visualization.code) - - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - - // open files - context.send( - Api.Request( - requestId, - Api.OpenFileRequest( - visualizationFile, - context.Visualization.code - ) - ) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - - context.receiveNIgnorePendingExpressionUpdates( - 5 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - context.Main.idMainX, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Visualization", - "encode" + // Modify the file + context.send( + Api.Request( + Api.EditFileNotification( + mainFile, + Seq( + TextEdit( + model.Range(model.Position(6, 12), model.Position(6, 13)), + "6" + ) ), - "Enso_Test.Test.Visualization" + execute = true ) ) ) - ) - val attachVisualizationResponses = context.receiveN(2) - attachVisualizationResponses should contain( - Api.Response(requestId, Api.VisualizationAttached()) - ) - val expectedExpressionId = context.Main.idMainX - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `expectedExpressionId` - ), - data - ) - ) => - data - } - data.sameElements("6".getBytes) shouldBe true - // Modify the file - context.send( - Api.Request( - Api.EditFileNotification( - mainFile, - Seq( - TextEdit( - model.Range(model.Position(6, 12), model.Position(6, 13)), - "6" - ) - ), - execute = true - ) + context.receiveNIgnoreExpressionUpdates( + 1 + ) should contain theSameElementsAs Seq( + context.executionComplete(contextId) ) - ) - - context.receiveNIgnoreExpressionUpdates( - 1 - ) should contain theSameElementsAs Seq( - context.executionComplete(contextId) - ) } - it should "not reorder visualization commands" in { + it should "not reorder visualization commands" in withContext() { context => val contents = context.Main.code val mainFile = context.writeMain(contents) val visualizationFile = @@ -1638,710 +1846,719 @@ class RuntimeVisualizationsTest dataAfterModification.sameElements("7".getBytes) shouldBe true } - it should "return ModuleNotFound error when attaching visualization" in { - val idMain = context.Main.metadata.addItem(99, 1) - val contents = context.Main.code - val mainFile = context.writeMain(context.Main.code) - val moduleName = "Enso_Test.Test.Main" + it should "return ModuleNotFound error when attaching visualization" in withContext() { + context => + val idMain = context.Main.metadata.addItem(99, 1) + val contents = context.Main.code + val mainFile = context.writeMain(context.Main.code) + val moduleName = "Enso_Test.Test.Main" - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 6 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMain, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Test.Undefined", - "x -> x" - ), - "Test.Undefined" - ) - ) + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) ) - ) - context.receiveN(2) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.VisualizationAttached()), - Api.Response(Api.ModuleNotFound("Test.Undefined")) - ) - } - it should "be able to use external libraries if they are needed by the visualization" in { - val idMain = context.Main.metadata.addItem(99, 1) - val contents = context.Main.code - val mainFile = context.writeMain(context.Main.code) - val moduleName = "Enso_Test.Test.Main" - - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 6 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMain, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Standard.Visualization.Main", - "x -> x.default_visualization.to_text" - ), - "Standard.Visualization.Main" - ) - ) + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) ) - ) - val attachVisualizationResponses = context.receiveN(8) - attachVisualizationResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 6 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMain` + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMain, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Test.Undefined", + "x -> x" ), - data + "Test.Undefined" ) - ) => - data - } - - data.sameElements("(Builtin 'JSON')".getBytes) shouldBe true - - val loadedLibraries = attachVisualizationResponses - .collect { - case Api.Response(None, Api.LibraryLoaded(namespace, name, _, _)) => - Some((namespace, name)) - case _ => None - } - .filter(_.isDefined) - .flatten - - loadedLibraries should contain(("Standard", "Visualization")) - } - - it should "return VisualizationExpressionFailed error when attaching visualization" in { - val idMain = context.Main.metadata.addItem(99, 1) - val contents = context.Main.code - val mainFile = context.writeMain(context.Main.code) - val moduleName = "Enso_Test.Test.Main" - - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 6 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMain, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Main", - "Main.does_not_exist" - ), - "Enso_Test.Test.Main" ) ) ) - ) - context.receiveN(2) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.VisualizationAttached()), - Api.Response( - Api.VisualizationExpressionFailed( - Api.VisualizationContext(visualizationId, contextId, idMain), - "Method `does_not_exist` of type Main could not be found.", - Some( - Api.ExecutionResult.Diagnostic.error( - message = - "Method `does_not_exist` of type Main could not be found.", - stack = Vector( + context.receiveN(2) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.VisualizationAttached()), + Api.Response(Api.ModuleNotFound("Test.Undefined")) + ) + } + + it should "be able to use external libraries if they are needed by the visualization" in withContext() { + context => + val idMain = context.Main.metadata.addItem(99, 1) + val contents = context.Main.code + val mainFile = context.writeMain(context.Main.code) + val moduleName = "Enso_Test.Test.Main" + + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 6 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMain, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Standard.Visualization.Main", + "x -> x.default_visualization.to_text" + ), + "Standard.Visualization.Main" + ) + ) + ) + ) + + val attachVisualizationResponses = context.receiveN(8) + attachVisualizationResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMain` + ), + data + ) + ) => + data + } + + data.sameElements("(Builtin 'JSON')".getBytes) shouldBe true + + val loadedLibraries = attachVisualizationResponses + .collect { + case Api.Response(None, Api.LibraryLoaded(namespace, name, _, _)) => + Some((namespace, name)) + case _ => None + } + .filter(_.isDefined) + .flatten + + loadedLibraries should contain(("Standard", "Visualization")) + } + + it should "return VisualizationExpressionFailed error when attaching visualization" in withContext() { + context => + val idMain = context.Main.metadata.addItem(99, 1) + val contents = context.Main.code + val mainFile = context.writeMain(context.Main.code) + val moduleName = "Enso_Test.Test.Main" + + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 6 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMain, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Main", + "Main.does_not_exist" + ), + "Enso_Test.Test.Main" + ) + ) + ) + ) + context.receiveN(2) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.VisualizationAttached()), + Api.Response( + Api.VisualizationExpressionFailed( + Api.VisualizationContext(visualizationId, contextId, idMain), + "Method `does_not_exist` of type Main could not be found.", + Some( + Api.ExecutionResult.Diagnostic.error( + message = + "Method `does_not_exist` of type Main could not be found.", + stack = Vector( // empty stack for now // Api.StackTraceElement("", None, None, None), // Api.StackTraceElement("Debug.eval", None, None, None) - ) - ) - ) - ) - ) - ) - } - - it should "return visualization evaluation errors with diagnostic info" in { - val idMain = context.Main.metadata.addItem(99, 1) - val contents = context.Main.code - val mainFile = context.writeMain(context.Main.code) - val moduleName = "Enso_Test.Test.Main" - - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 6 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMain, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - moduleName, - "x -> x.visualise_me" - ), - moduleName - ) - ) - ) - ) - context.receiveNIgnoreExpressionUpdates( - 3 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.VisualizationAttached()), - Api.Response( - Api.VisualizationEvaluationFailed( - Api.VisualizationContext( - visualizationId, - contextId, - idMain - ), - "Method `visualise_me` of type Integer could not be found.", - Some( - Api.ExecutionResult.Diagnostic.error( - "Method `visualise_me` of type Integer could not be found.", - None, - Some(model.Range(model.Position(0, 5), model.Position(0, 19))), - None, - Vector( - Api.StackTraceElement( - "", - None, - Some( - model.Range(model.Position(0, 5), model.Position(0, 19)) - ), - None ) ) ) ) ) - ), - context.executionComplete(contextId) - ) + ) } - it should "return visualization error with a stack trace" in { - val idMain = context.Main.metadata.addItem(99, 1) - val contents = context.Main.code - val mainFile = context.writeMain(context.Main.code) - val moduleName = "Enso_Test.Test.Main" - val visualizationCode = - """ - |encode x = x.visualise_me - | - |inc_and_encode x = encode x+1 - |""".stripMargin.linesIterator.mkString("\n") + it should "return visualization evaluation errors with diagnostic info" in withContext() { + context => + val idMain = context.Main.metadata.addItem(99, 1) + val contents = context.Main.code + val mainFile = context.writeMain(context.Main.code) + val moduleName = "Enso_Test.Test.Main" - val visualizationFile = - context.writeInSrcDir("Visualization", visualizationCode) + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - - context.send( - Api.Request( - requestId, - Api.OpenFileRequest( - visualizationFile, - visualizationCode - ) + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) ) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 6 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMain, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Visualization", - "inc_and_encode" - ), - "Enso_Test.Test.Visualization" - ) - ) + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) ) - ) - context.receiveNIgnoreExpressionUpdates( - 3 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.VisualizationAttached()), - Api.Response( - Api.VisualizationEvaluationFailed( - Api.VisualizationContext( + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 6 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( visualizationId, - contextId, - idMain - ), - "Method `visualise_me` of type Integer could not be found.", - Some( - Api.ExecutionResult.Diagnostic.error( - "Method `visualise_me` of type Integer could not be found.", - Some(visualizationFile), - Some(model.Range(model.Position(1, 11), model.Position(1, 25))), - None, - Vector( - Api.StackTraceElement( - "Visualization.encode", - Some(visualizationFile), - Some( - model.Range(model.Position(1, 11), model.Position(1, 25)) - ), - None - ), - Api.StackTraceElement( - "Visualization.inc_and_encode", - Some(visualizationFile), - Some( - model.Range(model.Position(3, 19), model.Position(3, 29)) - ), - None - ) - ) - ) - ) - ) - ), - context.executionComplete(contextId) - ) - } - - it should "run visualization expression catching error" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata - - val idMain = metadata.addItem(42, 14) - - val code = - """from Standard.Base import all - | - |main = - | Error.throw 42 - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnoreStdLib(3) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.error( - contextId, - idMain, - Api.MethodCall( - Api.MethodPointer( - "Standard.Base.Error", - "Standard.Base.Error.Error", - "throw" - ) - ), - Api.ExpressionUpdate.Payload.DataflowError(Seq(idMain)) - ), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMain, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - moduleName, - "x -> x.catch_primitive _.to_text" - ), - moduleName - ) - ) - ) - ) - val attachVisualizationResponses = context.receiveN(4, timeoutSeconds = 60) - attachVisualizationResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMain` + idMain, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + moduleName, + "x -> x.visualise_me" ), - data + moduleName ) - ) => - data - } - data.sameElements("42".getBytes) shouldBe true - } - - it should "run visualization expression propagating panic" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata - - val idMain = metadata.addItem(42, 14) - - val code = - """from Standard.Base import all - | - |main = - | Panic.throw 42 - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 3 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.panic( - contextId, - idMain, - Api.MethodCall( - Api.MethodPointer( - "Standard.Base.Panic", - "Standard.Base.Panic.Panic", - "throw" - ) - ), - Api.ExpressionUpdate.Payload.Panic("Integer", Seq(idMain)), - Some("Standard.Base.Panic.Panic") - ), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMain, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - moduleName, - "x -> Panic.catch_primitive x caught_panic-> caught_panic.payload.to_text" - ), - moduleName ) ) ) - ) - context.receiveNIgnorePendingExpressionUpdates( - 4 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.VisualizationAttached()), - TestMessages.panic( - contextId, - idMain, - Api.MethodCall( - Api.MethodPointer( - "Standard.Base.Panic", - "Standard.Base.Panic.Panic", - "throw" - ) - ), - Api.ExpressionUpdate.Payload.Panic("Integer", Seq(idMain)), - builtin = false - ), - Api.Response( - Api.VisualizationEvaluationFailed( - Api.VisualizationContext( - visualizationId, - contextId, - idMain - ), - "42", - Some( - Api.ExecutionResult.Diagnostic.error( - message = "42", - file = Some(mainFile), - location = - Some(model.Range(model.Position(3, 4), model.Position(3, 18))), - expressionId = Some(idMain), - stack = Vector( - Api.StackTraceElement( - "Main.main", - Some(mainFile), - Some( - model.Range(model.Position(3, 4), model.Position(3, 18)) - ), - Some(idMain) + context.receiveNIgnoreExpressionUpdates( + 3 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.VisualizationAttached()), + Api.Response( + Api.VisualizationEvaluationFailed( + Api.VisualizationContext( + visualizationId, + contextId, + idMain + ), + "Method `visualise_me` of type Integer could not be found.", + Some( + Api.ExecutionResult.Diagnostic.error( + "Method `visualise_me` of type Integer could not be found.", + None, + Some(model.Range(model.Position(0, 5), model.Position(0, 19))), + None, + Vector( + Api.StackTraceElement( + "", + None, + Some( + model.Range(model.Position(0, 5), model.Position(0, 19)) + ), + None + ) ) ) ) ) - ) - ), - context.executionComplete(contextId) - ) + ), + context.executionComplete(contextId) + ) } - it should "run visualization error preprocessor" in { + it should "return visualization error with a stack trace" in withContext() { + context => + val idMain = context.Main.metadata.addItem(99, 1) + val contents = context.Main.code + val mainFile = context.writeMain(context.Main.code) + val moduleName = "Enso_Test.Test.Main" + val visualizationCode = + """ + |encode x = x.visualise_me + | + |inc_and_encode x = encode x+1 + |""".stripMargin.linesIterator.mkString("\n") + + val visualizationFile = + context.writeInSrcDir("Visualization", visualizationCode) + + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + + context.send( + Api.Request( + requestId, + Api.OpenFileRequest( + visualizationFile, + visualizationCode + ) + ) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 6 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMain, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Visualization", + "inc_and_encode" + ), + "Enso_Test.Test.Visualization" + ) + ) + ) + ) + context.receiveNIgnoreExpressionUpdates( + 3 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.VisualizationAttached()), + Api.Response( + Api.VisualizationEvaluationFailed( + Api.VisualizationContext( + visualizationId, + contextId, + idMain + ), + "Method `visualise_me` of type Integer could not be found.", + Some( + Api.ExecutionResult.Diagnostic.error( + "Method `visualise_me` of type Integer could not be found.", + Some(visualizationFile), + Some(model.Range(model.Position(1, 11), model.Position(1, 25))), + None, + Vector( + Api.StackTraceElement( + "Visualization.encode", + Some(visualizationFile), + Some( + model.Range(model.Position(1, 11), model.Position(1, 25)) + ), + None + ), + Api.StackTraceElement( + "Visualization.inc_and_encode", + Some(visualizationFile), + Some( + model.Range(model.Position(3, 19), model.Position(3, 29)) + ), + None + ) + ) + ) + ) + ) + ), + context.executionComplete(contextId) + ) + } + + it should "run visualization expression catching error" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata + + val idMain = metadata.addItem(42, 14) + + val code = + """from Standard.Base import all + | + |main = + | Error.throw 42 + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnoreStdLib(3) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.error( + contextId, + idMain, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Error", + "Standard.Base.Error.Error", + "throw" + ) + ), + Api.ExpressionUpdate.Payload.DataflowError(Seq(idMain)) + ), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMain, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + moduleName, + "x -> x.catch_primitive _.to_text" + ), + moduleName + ) + ) + ) + ) + val attachVisualizationResponses = + context.receiveN(4, timeoutSeconds = 60) + attachVisualizationResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMain` + ), + data + ) + ) => + data + } + data.sameElements("42".getBytes) shouldBe true + } + + it should "run visualization expression propagating panic" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata + + val idMain = metadata.addItem(42, 14) + + val code = + """from Standard.Base import all + | + |main = + | Panic.throw 42 + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 3 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.panic( + contextId, + idMain, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Panic", + "Standard.Base.Panic.Panic", + "throw" + ) + ), + Api.ExpressionUpdate.Payload.Panic("Integer", Seq(idMain)), + Some("Standard.Base.Panic.Panic") + ), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMain, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + moduleName, + "x -> Panic.catch_primitive x caught_panic-> caught_panic.payload.to_text" + ), + moduleName + ) + ) + ) + ) + context.receiveNIgnorePendingExpressionUpdates( + 4 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.VisualizationAttached()), + TestMessages.panic( + contextId, + idMain, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Panic", + "Standard.Base.Panic.Panic", + "throw" + ) + ), + Api.ExpressionUpdate.Payload.Panic("Integer", Seq(idMain)), + builtin = false + ), + Api.Response( + Api.VisualizationEvaluationFailed( + Api.VisualizationContext( + visualizationId, + contextId, + idMain + ), + "42", + Some( + Api.ExecutionResult.Diagnostic.error( + message = "42", + file = Some(mainFile), + location = Some( + model.Range(model.Position(3, 4), model.Position(3, 18)) + ), + expressionId = Some(idMain), + stack = Vector( + Api.StackTraceElement( + "Main.main", + Some(mainFile), + Some( + model.Range(model.Position(3, 4), model.Position(3, 18)) + ), + Some(idMain) + ) + ) + ) + ) + ) + ), + context.executionComplete(contextId) + ) + } + + it should "run visualization error preprocessor" in withContext() { context => val contextId = UUID.randomUUID() val requestId = UUID.randomUUID() val visualizationId = UUID.randomUUID() @@ -2451,400 +2668,197 @@ class RuntimeVisualizationsTest stringified shouldEqual """{"kind":"Dataflow","message":"The List is empty. (at Main.main(Enso_Test.Test.Main:6:5-38)"}""" } - it should "run visualization default preprocessor" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata + it should "run visualization default preprocessor" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata - val idMain = metadata.addItem(47, 6) + val idMain = metadata.addItem(47, 6) - val code = - """import Standard.Visualization - | - |main = - | fn = x -> x - | fn - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) + val code = + """import Standard.Visualization + | + |main = + | fn = x -> x + | fn + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) - val visualizationModule = "Standard.Visualization.Preprocessor" - val visualizationFunction = "default_preprocessor" + val visualizationModule = "Standard.Visualization.Preprocessor" + val visualizationFunction = "default_preprocessor" - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, moduleName, "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 3 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.update( - contextId, - idMain, - ConstantsGen.FUNCTION - ), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 3 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update( + contextId, idMain, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.ModuleMethod( - Api.MethodPointer( - visualizationModule, - visualizationModule, - visualizationFunction + ConstantsGen.FUNCTION + ), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMain, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.ModuleMethod( + Api.MethodPointer( + visualizationModule, + visualizationModule, + visualizationFunction + ), + Vector() ), - Vector() - ), - visualizationModule + visualizationModule + ) ) ) ) - ) - val attachVisualizationResponses = - context.receiveNIgnoreExpressionUpdates(2) - attachVisualizationResponses should contain( - Api.Response(requestId, Api.VisualizationAttached()) - ) - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMain` - ), - data - ) - ) => - data - } - val stringified = new String(data) - stringified shouldEqual "\"Function\"" + val attachVisualizationResponses = + context.receiveNIgnoreExpressionUpdates(2) + attachVisualizationResponses should contain( + Api.Response(requestId, Api.VisualizationAttached()) + ) + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMain` + ), + data + ) + ) => + data + } + val stringified = new String(data) + stringified shouldEqual "\"Function\"" } - it should "attach method pointer visualization without arguments" in { - val idMainRes = context.Main.metadata.addItem(99, 1) - val contents = context.Main.code - val mainFile = context.writeMain(context.Main.code) - val visualizationFile = - context.writeInSrcDir("Visualization", context.Visualization.code) + it should "attach method pointer visualization without arguments" in withContext() { + context => + val idMainRes = context.Main.metadata.addItem(99, 1) + val contents = context.Main.code + val mainFile = context.writeMain(context.Main.code) + val visualizationFile = + context.writeInSrcDir("Visualization", context.Visualization.code) - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() - context.send( - Api.Request( - requestId, - Api.OpenFileRequest( - visualizationFile, - context.Visualization.code - ) - ) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 6 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - TestMessages.update(contextId, idMainRes, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMainRes, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.ModuleMethod( - Api.MethodPointer( - "Enso_Test.Test.Visualization", - "Enso_Test.Test.Visualization", - "incAndEncode" - ), - Vector() - ), - "Enso_Test.Test.Visualization" + context.send( + Api.Request( + requestId, + Api.OpenFileRequest( + visualizationFile, + context.Visualization.code ) ) ) - ) - val attachVisualizationResponses = - context.receiveNIgnoreExpressionUpdates(3) - attachVisualizationResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMainRes` - ), - data - ) - ) => - data - } - data.sameElements("51".getBytes) shouldBe true - - // recompute - context.send( - Api.Request(requestId, Api.RecomputeContextRequest(contextId, None, None)) - ) - - val recomputeResponses = context.receiveNIgnoreExpressionUpdates(3) - recomputeResponses should contain allOf ( - Api.Response(requestId, Api.RecomputeContextResponse(contextId)), - context.executionComplete(contextId) - ) - val Some(data2) = recomputeResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMainRes` - ), - data - ) - ) => - data - } - data2.sameElements("51".getBytes) shouldBe true - } - - it should "attach method pointer visualization with arguments" in { - val idMainRes = context.Main.metadata.addItem(99, 1) - val contents = context.Main.code - val mainFile = context.writeMain(context.Main.code) - val moduleName = "Enso_Test.Test.Main" - val visualizationFile = - context.writeInSrcDir( - "Visualization", - context.AnnotatedVisualization.code + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) ) - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - - context.send( - Api.Request( - requestId, - Api.OpenFileRequest( - visualizationFile, - context.AnnotatedVisualization.code - ) + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) ) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 6 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + TestMessages.update(contextId, idMainRes, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 6 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - TestMessages.update(contextId, idMainRes, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - context.consumeOut shouldEqual List() - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMainRes, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.ModuleMethod( - Api.MethodPointer( - "Enso_Test.Test.Visualization", - "Enso_Test.Test.Visualization", - "incAndEncode" + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMainRes, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.ModuleMethod( + Api.MethodPointer( + "Enso_Test.Test.Visualization", + "Enso_Test.Test.Visualization", + "incAndEncode" + ), + Vector() ), - Vector("2", "3") - ), - "Enso_Test.Test.Visualization" + "Enso_Test.Test.Visualization" + ) ) ) ) - ) - val attachVisualizationResponses = - context.receiveNIgnoreExpressionUpdates(3) - attachVisualizationResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMainRes` - ), - data - ) - ) => - data - } - data.sameElements("103".getBytes) shouldBe true - context.consumeOut shouldEqual List("encoding...") - - // recompute - context.send( - Api.Request(requestId, Api.RecomputeContextRequest(contextId, None, None)) - ) - - val recomputeResponses = context.receiveNIgnoreExpressionUpdates(3) - recomputeResponses should contain allOf ( - Api.Response(requestId, Api.RecomputeContextResponse(contextId)), - context.executionComplete(contextId) - ) - val Some(data2) = recomputeResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMainRes` - ), - data - ) - ) => - data - } - data2.sameElements("103".getBytes) shouldBe true - context.consumeOut shouldEqual List() - - // modify visualization - context.send( - Api.Request( - requestId, - Api.ModifyVisualization( - visualizationId, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.ModuleMethod( - Api.MethodPointer( - "Enso_Test.Test.Visualization", - "Enso_Test.Test.Visualization", - "incAndEncode" - ), - Vector("2", "4") - ), - "Enso_Test.Test.Visualization" - ) - ) + val attachVisualizationResponses = + context.receiveNIgnoreExpressionUpdates(3) + attachVisualizationResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) ) - ) - val modifyVisualizationResponses = - context.receiveNIgnoreExpressionUpdates(2) - modifyVisualizationResponses should contain( - Api.Response(requestId, Api.VisualizationModified()) - ) - val Some(data3) = - modifyVisualizationResponses.collectFirst { + val Some(data) = attachVisualizationResponses.collectFirst { case Api.Response( None, Api.VisualizationUpdate( @@ -2858,1251 +2872,1478 @@ class RuntimeVisualizationsTest ) => data } - data3.sameElements("104".getBytes) shouldBe true - context.consumeOut shouldEqual List("encoding...") - } + data.sameElements("51".getBytes) shouldBe true - it should "cache intermediate visualization expressions" in { - val idMainRes = context.Main.metadata.addItem(99, 1) - val contents = context.Main.code - val mainFile = context.writeMain(context.Main.code) - val moduleName = "Enso_Test.Test.Main" - val visualizationFile = - context.writeInSrcDir( - "Visualization", - context.AnnotatedVisualization.code + // recompute + context.send( + Api.Request( + requestId, + Api.RecomputeContextRequest(contextId, None, None) + ) ) - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() + val recomputeResponses = context.receiveNIgnoreExpressionUpdates(3) + recomputeResponses should contain allOf ( + Api.Response(requestId, Api.RecomputeContextResponse(contextId)), + context.executionComplete(contextId) + ) + val Some(data2) = recomputeResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMainRes` + ), + data + ) + ) => + data + } + data2.sameElements("51".getBytes) shouldBe true + } - context.send( - Api.Request( - requestId, - Api.OpenFileRequest( - visualizationFile, + it should "attach method pointer visualization with arguments" in withContext() { + context => + val idMainRes = context.Main.metadata.addItem(99, 1) + val contents = context.Main.code + val mainFile = context.writeMain(context.Main.code) + val moduleName = "Enso_Test.Test.Main" + val visualizationFile = + context.writeInSrcDir( + "Visualization", context.AnnotatedVisualization.code ) - ) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 6 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - context.Main.Update.mainX(contextId), - context.Main.Update.mainY(contextId), - context.Main.Update.mainZ(contextId), - TestMessages.update(contextId, idMainRes, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - context.consumeOut shouldEqual List() - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMainRes, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.ModuleMethod( - Api.MethodPointer( - "Enso_Test.Test.Visualization", - "Enso_Test.Test.Visualization", - "incAndEncode" - ), - Vector() - ), - "Enso_Test.Test.Visualization" + context.send( + Api.Request( + requestId, + Api.OpenFileRequest( + visualizationFile, + context.AnnotatedVisualization.code ) ) ) - ) - val attachVisualizationResponses = - context.receiveNIgnoreExpressionUpdates(3) - attachVisualizationResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMainRes` + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 6 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + TestMessages.update(contextId, idMainRes, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) + context.consumeOut shouldEqual List() + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMainRes, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.ModuleMethod( + Api.MethodPointer( + "Enso_Test.Test.Visualization", + "Enso_Test.Test.Visualization", + "incAndEncode" + ), + Vector("2", "3") ), - data + "Enso_Test.Test.Visualization" ) - ) => - data - } - data.sameElements("51".getBytes) shouldBe true - context.consumeOut shouldEqual List("encoding...") + ) + ) + ) + val attachVisualizationResponses = + context.receiveNIgnoreExpressionUpdates(3) + attachVisualizationResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMainRes` + ), + data + ) + ) => + data + } + data.sameElements("103".getBytes) shouldBe true + context.consumeOut shouldEqual List("encoding...") - // recompute - context.send( - Api.Request(requestId, Api.RecomputeContextRequest(contextId, None, None)) - ) + // recompute + context.send( + Api.Request( + requestId, + Api.RecomputeContextRequest(contextId, None, None) + ) + ) - val recomputeResponses = context.receiveNIgnoreExpressionUpdates(3) - recomputeResponses should contain allOf ( - Api.Response(requestId, Api.RecomputeContextResponse(contextId)), - context.executionComplete(contextId) - ) - val Some(data2) = recomputeResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMainRes` + val recomputeResponses = context.receiveNIgnoreExpressionUpdates(3) + recomputeResponses should contain allOf ( + Api.Response(requestId, Api.RecomputeContextResponse(contextId)), + context.executionComplete(contextId) + ) + val Some(data2) = recomputeResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMainRes` + ), + data + ) + ) => + data + } + data2.sameElements("103".getBytes) shouldBe true + context.consumeOut shouldEqual List() + + // modify visualization + context.send( + Api.Request( + requestId, + Api.ModifyVisualization( + visualizationId, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.ModuleMethod( + Api.MethodPointer( + "Enso_Test.Test.Visualization", + "Enso_Test.Test.Visualization", + "incAndEncode" + ), + Vector("2", "4") ), - data + "Enso_Test.Test.Visualization" ) - ) => - data - } - data2.sameElements("51".getBytes) shouldBe true - context.consumeOut shouldEqual List() + ) + ) + ) + val modifyVisualizationResponses = + context.receiveNIgnoreExpressionUpdates(2) + modifyVisualizationResponses should contain( + Api.Response(requestId, Api.VisualizationModified()) + ) + val Some(data3) = + modifyVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMainRes` + ), + data + ) + ) => + data + } + data3.sameElements("104".getBytes) shouldBe true + context.consumeOut shouldEqual List("encoding...") + } - // Modify the visualization file - context.send( - Api.Request( - Api.EditFileNotification( - visualizationFile, - Seq( - TextEdit( - model.Range(model.Position(6, 21), model.Position(6, 22)), - "2" + it should "cache intermediate visualization expressions" in withContext() { + context => + val idMainRes = context.Main.metadata.addItem(99, 1) + val contents = context.Main.code + val mainFile = context.writeMain(context.Main.code) + val moduleName = "Enso_Test.Test.Main" + val visualizationFile = + context.writeInSrcDir( + "Visualization", + context.AnnotatedVisualization.code + ) + + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + + context.send( + Api.Request( + requestId, + Api.OpenFileRequest( + visualizationFile, + context.AnnotatedVisualization.code + ) + ) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 6 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.Main.Update.mainX(contextId), + context.Main.Update.mainY(contextId), + context.Main.Update.mainZ(contextId), + TestMessages.update(contextId, idMainRes, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) + context.consumeOut shouldEqual List() + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMainRes, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.ModuleMethod( + Api.MethodPointer( + "Enso_Test.Test.Visualization", + "Enso_Test.Test.Visualization", + "incAndEncode" + ), + Vector() + ), + "Enso_Test.Test.Visualization" + ) + ) + ) + ) + val attachVisualizationResponses = + context.receiveNIgnoreExpressionUpdates(3) + attachVisualizationResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMainRes` + ), + data + ) + ) => + data + } + data.sameElements("51".getBytes) shouldBe true + context.consumeOut shouldEqual List("encoding...") + + // recompute + context.send( + Api.Request( + requestId, + Api.RecomputeContextRequest(contextId, None, None) + ) + ) + + val recomputeResponses = context.receiveNIgnoreExpressionUpdates(3) + recomputeResponses should contain allOf ( + Api.Response(requestId, Api.RecomputeContextResponse(contextId)), + context.executionComplete(contextId) + ) + val Some(data2) = recomputeResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMainRes` + ), + data + ) + ) => + data + } + data2.sameElements("51".getBytes) shouldBe true + context.consumeOut shouldEqual List() + + // Modify the visualization file + context.send( + Api.Request( + Api.EditFileNotification( + visualizationFile, + Seq( + TextEdit( + model.Range(model.Position(6, 21), model.Position(6, 22)), + "2" + ) + ), + execute = true + ) + ) + ) + + val editFileResponse = context.receiveNIgnoreExpressionUpdates(2) + editFileResponse should contain( + context.executionComplete(contextId) + ) + val Some(data3) = editFileResponse.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMainRes` + ), + data + ) + ) => + data + } + data3.sameElements("52".getBytes) shouldBe true + context.consumeOut shouldEqual List("encoding...") + } + + it should "emit visualization update for values annotated with warnings" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata + + val idMain = metadata.addItem(37, 26) + + val code = + """from Standard.Base import all + | + |main = + | Warning.attach "y" 42 + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 3 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update( + contextId, + idMain, + ConstantsGen.INTEGER, + payload = Api.ExpressionUpdate.Payload.Value( + Some( + Api.ExpressionUpdate.Payload.Value.Warnings(1, Some("'y'"), false) + ) + ) + ), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMain, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Main", + "x -> x.to_text" + ), + "Enso_Test.Test.Main" + ) + ) + ) + ) + val attachVisualizationResponses = + context.receiveNIgnoreExpressionUpdates(3) + attachVisualizationResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMain` + ), + data + ) + ) => + data + } + new String(data, StandardCharsets.UTF_8) shouldEqual "42" + } + + it should "emit visualization update for values in array annotated with warnings" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata + + val idMain = metadata.addItem(37, 28) + + val code = + """from Standard.Base import all + | + |main = + | [Warning.attach "y" 42] + |""".stripMargin.linesIterator.mkString("\n") + + metadata.assertInCode(idMain, code, "\n [Warning.attach \"y\" 42]") + + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 3 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update( + contextId, + idMain, + ConstantsGen.VECTOR, + payload = Api.ExpressionUpdate.Payload.Value( + Some( + Api.ExpressionUpdate.Payload.Value.Warnings(1, Some("'y'"), false) + ) + ) + ), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idMain, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Main", + "x -> x.to_text" + ), + "Enso_Test.Test.Main" + ) + ) + ) + ) + val attachVisualizationResponses = + context.receiveNIgnoreExpressionUpdates(3) + attachVisualizationResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMain` + ), + data + ) + ) => + data + } + new String(data, StandardCharsets.UTF_8) shouldEqual "[42]" + } + + it should "emit visualization update for values in atom annotated with warnings" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val warningTypeName = QualifiedName.fromString(ConstantsGen.WARNING) + val warningModuleName = warningTypeName.getParent.get + val metadata = new Metadata + + val idX = metadata.addItem(81, 21) + val idRes = metadata.addItem(107, 20) + + val code = + """from Standard.Base import all + | + |type Newtype + | Mk_Newtype value + | + |main = + | x = Warning.attach "x" 42 + | Newtype.Mk_Newtype x + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 4 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update( + contextId, + idX, + ConstantsGen.INTEGER, + methodCall = Some( + Api.MethodCall( + Api.MethodPointer( + warningModuleName.toString, + warningTypeName.toString, + "attach" + ) ) ), - execute = true - ) - ) - ) - - val editFileResponse = context.receiveNIgnoreExpressionUpdates(2) - editFileResponse should contain( - context.executionComplete(contextId) - ) - val Some(data3) = editFileResponse.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMainRes` - ), - data + payload = Api.ExpressionUpdate.Payload.Value( + Some( + Api.ExpressionUpdate.Payload.Value.Warnings(1, Some("'x'"), false) ) - ) => - data - } - data3.sameElements("52".getBytes) shouldBe true - context.consumeOut shouldEqual List("encoding...") - } + ) + ), + TestMessages.update( + contextId, + idRes, + s"$moduleName.Newtype", + methodCall = Some( + Api.MethodCall( + Api + .MethodPointer(moduleName, s"$moduleName.Newtype", "Mk_Newtype") + ) + ), + payload = Api.ExpressionUpdate.Payload.Value( + Some( + Api.ExpressionUpdate.Payload.Value.Warnings(1, Some("'x'"), false) + ) + ) + ), + context.executionComplete(contextId) + ) - it should "emit visualization update for values annotated with warnings" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata - - val idMain = metadata.addItem(37, 26) - - val code = - """from Standard.Base import all - | - |main = - | Warning.attach "y" 42 - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 3 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.update( - contextId, - idMain, - ConstantsGen.INTEGER, - payload = Api.ExpressionUpdate.Payload.Value( - Some( - Api.ExpressionUpdate.Payload.Value.Warnings(1, Some("'y'"), false) + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idRes, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Main", + "x -> x.to_text" + ), + "Enso_Test.Test.Main" + ) ) ) - ), - context.executionComplete(contextId) - ) + ) + val attachVisualizationResponses = + context.receiveNIgnoreExpressionUpdates(3) + attachVisualizationResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idRes` + ), + data + ) + ) => + data + } + new String(data, StandardCharsets.UTF_8) shouldEqual "(Mk_Newtype 42)" + } - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMain, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Main", - "x -> x.to_text" + it should "emit visualization update for the target of a method call" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata("import Standard.Base.Data.Numbers\n\n") + + val idX = metadata.addItem(65, 1, "aa") + val idY = metadata.addItem(65, 7, "ab") + val idS = metadata.addItem(81, 1) + val idZ = metadata.addItem(91, 5, "ac") + val idZexprS = metadata.addItem(93, 1) + val idZexpr1 = metadata.addItem(95, 1) + + val code = + """type T + | C + | + | inc self x = x + 1 + | + |main = + | x = T.C + | y = x.inc 7 + | s = 1 + | z = p y s + | z + | + |p x y = x + y + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 8 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update(contextId, idX, s"$moduleName.T"), + TestMessages.update( + contextId, + idY, + ConstantsGen.INTEGER, + Api.MethodCall(Api.MethodPointer(moduleName, s"$moduleName.T", "inc")) + ), + TestMessages.update(contextId, idS, ConstantsGen.INTEGER), + TestMessages.update( + contextId, + idZ, + ConstantsGen.INTEGER, + Api.MethodCall(Api.MethodPointer(moduleName, moduleName, "p")) + ), + TestMessages.update(contextId, idZexprS, ConstantsGen.INTEGER), + TestMessages.update(contextId, idZexpr1, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idX, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + moduleName, + "x -> x.to_text" + ), + moduleName + ) + ) + ) + ) + val attachVisualizationResponses = + context.receiveNIgnoreExpressionUpdates(3) + attachVisualizationResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idX` + ), + data + ) + ) => + data + } + new String(data, StandardCharsets.UTF_8) shouldEqual "C" + + // Modify the file + context.send( + Api.Request( + Api.EditFileNotification( + mainFile, + Seq( + TextEdit( + model.Range(model.Position(9, 8), model.Position(9, 9)), + "x" + ) ), - "Enso_Test.Test.Main" + execute = true ) ) ) - ) - val attachVisualizationResponses = - context.receiveNIgnoreExpressionUpdates(3) - attachVisualizationResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMain` - ), - data - ) - ) => - data - } - new String(data, StandardCharsets.UTF_8) shouldEqual "42" - } - it should "emit visualization update for values in array annotated with warnings" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata - - val idMain = metadata.addItem(37, 28) - - val code = - """from Standard.Base import all - | - |main = - | [Warning.attach "y" 42] - |""".stripMargin.linesIterator.mkString("\n") - - metadata.assertInCode(idMain, code, "\n [Warning.attach \"y\" 42]") - - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 3 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.update( - contextId, - idMain, - ConstantsGen.VECTOR, - payload = Api.ExpressionUpdate.Payload.Value( - Some( - Api.ExpressionUpdate.Payload.Value.Warnings(1, Some("'y'"), false) - ) - ) - ), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idMain, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Main", - "x -> x.to_text" - ), - "Enso_Test.Test.Main" - ) - ) + val editFileResponse = context.receiveNIgnoreExpressionUpdates(2) + editFileResponse should contain( + context.executionComplete(contextId) ) - ) - val attachVisualizationResponses = - context.receiveNIgnoreExpressionUpdates(3) - attachVisualizationResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMain` - ), - data - ) - ) => - data - } - new String(data, StandardCharsets.UTF_8) shouldEqual "[42]" + val Some(data1) = editFileResponse.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idX` + ), + data + ) + ) => + data + } + new String(data1, StandardCharsets.UTF_8) shouldEqual "C" } - it should "emit visualization update for values in atom annotated with warnings" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val warningTypeName = QualifiedName.fromString(ConstantsGen.WARNING) - val warningModuleName = warningTypeName.getParent.get - val metadata = new Metadata + it should "execute expression in the scope of local expression cached" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata("import Standard.Base.Data.Numbers\n\n") - val idX = metadata.addItem(81, 21) - val idRes = metadata.addItem(107, 20) + val idOp1 = metadata.addItem(23, 2) + val idOp2 = metadata.addItem(42, 13) - val code = - """from Standard.Base import all - | - |type Newtype - | Mk_Newtype value - | - |main = - | x = Warning.attach "x" 42 - | Newtype.Mk_Newtype x - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) + val code = + """main = + | operator1 = 42 + | operator2 = operator1 + 1 + | operator2 + | + |fun1 x = x.to_text + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 4 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.update( - contextId, - idX, - ConstantsGen.INTEGER, - methodCall = Some( + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 4 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update(contextId, idOp1, ConstantsGen.INTEGER), + TestMessages.update( + contextId, + idOp2, + ConstantsGen.INTEGER, Api.MethodCall( Api.MethodPointer( - warningModuleName.toString, - warningTypeName.toString, - "attach" + "Standard.Base.Data.Numbers", + ConstantsGen.INTEGER, + "+" ) ) ), - payload = Api.ExpressionUpdate.Payload.Value( - Some( - Api.ExpressionUpdate.Payload.Value.Warnings(1, Some("'x'"), false) - ) - ) - ), - TestMessages.update( - contextId, - idRes, - s"$moduleName.Newtype", - methodCall = Some( - Api.MethodCall( - Api.MethodPointer(moduleName, s"$moduleName.Newtype", "Mk_Newtype") - ) - ), - payload = Api.ExpressionUpdate.Payload.Value( - Some( - Api.ExpressionUpdate.Payload.Value.Warnings(1, Some("'x'"), false) - ) - ) - ), - context.executionComplete(contextId) - ) + context.executionComplete(contextId) + ) - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idRes, - Api.VisualizationConfiguration( + // execute expression + context.send( + Api.Request( + requestId, + Api.ExecuteExpression( contextId, - Api.VisualizationExpression.Text( - "Enso_Test.Test.Main", - "x -> x.to_text" - ), - "Enso_Test.Test.Main" + visualizationId, + idOp2, + "fun1 operator1" ) ) ) - ) - val attachVisualizationResponses = - context.receiveNIgnoreExpressionUpdates(3) - attachVisualizationResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idRes` - ), - data - ) - ) => - data - } - new String(data, StandardCharsets.UTF_8) shouldEqual "(Mk_Newtype 42)" + val executeExpressionResponses = + context.receiveNIgnoreExpressionUpdates(3) + executeExpressionResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = executeExpressionResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idOp2` + ), + data + ) + ) => + data + } + new String(data) shouldEqual "42" } - it should "emit visualization update for the target of a method call" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata("import Standard.Base.Data.Numbers\n\n") + it should "execute expression in the scope of local expression not cached" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata("import Standard.Base.Data.Numbers\n\n") - val idX = metadata.addItem(65, 1, "aa") - val idY = metadata.addItem(65, 7, "ab") - val idS = metadata.addItem(81, 1) - val idZ = metadata.addItem(91, 5, "ac") - val idZexprS = metadata.addItem(93, 1) - val idZexpr1 = metadata.addItem(95, 1) + val idOp1 = metadata.addItem(23, 2) + val idOp2 = metadata.addItem(42, 13) + val idRes = metadata.addItem(60, 9) - val code = - """type T - | C - | - | inc self x = x + 1 - | - |main = - | x = T.C - | y = x.inc 7 - | s = 1 - | z = p y s - | z - | - |p x y = x + y - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) + val code = + """main = + | operator1 = 42 + | operator2 = operator1 + 1 + | operator2 + | + |fun1 x = x.to_text + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 8 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.update(contextId, idX, s"$moduleName.T"), - TestMessages.update( - contextId, - idY, - ConstantsGen.INTEGER, - Api.MethodCall(Api.MethodPointer(moduleName, s"$moduleName.T", "inc")) - ), - TestMessages.update(contextId, idS, ConstantsGen.INTEGER), - TestMessages.update( - contextId, - idZ, - ConstantsGen.INTEGER, - Api.MethodCall(Api.MethodPointer(moduleName, moduleName, "p")) - ), - TestMessages.update(contextId, idZexprS, ConstantsGen.INTEGER), - TestMessages.update(contextId, idZexpr1, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - - // attach visualization - context.send( - Api.Request( - requestId, - Api.AttachVisualization( - visualizationId, - idX, - Api.VisualizationConfiguration( - contextId, - Api.VisualizationExpression.Text( - moduleName, - "x -> x.to_text" - ), - moduleName - ) - ) + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) ) - ) - val attachVisualizationResponses = - context.receiveNIgnoreExpressionUpdates(3) - attachVisualizationResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = attachVisualizationResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idX` - ), - data - ) - ) => - data - } - new String(data, StandardCharsets.UTF_8) shouldEqual "C" - // Modify the file - context.send( - Api.Request( - Api.EditFileNotification( - mainFile, - Seq( - TextEdit( - model.Range(model.Position(9, 8), model.Position(9, 9)), - "x" - ) - ), - execute = true - ) + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) ) - ) - val editFileResponse = context.receiveNIgnoreExpressionUpdates(2) - editFileResponse should contain( - context.executionComplete(contextId) - ) - val Some(data1) = editFileResponse.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idX` - ), - data - ) - ) => - data - } - new String(data1, StandardCharsets.UTF_8) shouldEqual "C" - } - - it should "execute expression in the scope of local expression cached" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata("import Standard.Base.Data.Numbers\n\n") - - val idOp1 = metadata.addItem(23, 2) - val idOp2 = metadata.addItem(42, 13) - - val code = - """main = - | operator1 = 42 - | operator2 = operator1 + 1 - | operator2 - | - |fun1 x = x.to_text - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, moduleName, "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 4 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.update(contextId, idOp1, ConstantsGen.INTEGER), - TestMessages.update( - contextId, - idOp2, - ConstantsGen.INTEGER, - Api.MethodCall( - Api.MethodPointer( - "Standard.Base.Data.Numbers", - ConstantsGen.INTEGER, - "+" - ) - ) - ), - context.executionComplete(contextId) - ) - - // execute expression - context.send( - Api.Request( - requestId, - Api.ExecuteExpression( + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 5 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update(contextId, idOp1, ConstantsGen.INTEGER), + TestMessages.update( contextId, - visualizationId, idOp2, - "fun1 operator1" - ) - ) - ) - val executeExpressionResponses = - context.receiveNIgnoreExpressionUpdates(3) - executeExpressionResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = executeExpressionResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idOp2` - ), - data + ConstantsGen.INTEGER, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Data.Numbers", + ConstantsGen.INTEGER, + "+" ) - ) => - data - } - new String(data) shouldEqual "42" - } + ) + ), + TestMessages.update(contextId, idRes, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) - it should "execute expression in the scope of local expression not cached" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata("import Standard.Base.Data.Numbers\n\n") - - val idOp1 = metadata.addItem(23, 2) - val idOp2 = metadata.addItem(42, 13) - val idRes = metadata.addItem(60, 9) - - val code = - """main = - | operator1 = 42 - | operator2 = operator1 + 1 - | operator2 - | - |fun1 x = x.to_text - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) - - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) - - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) - - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, moduleName, "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 5 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.update(contextId, idOp1, ConstantsGen.INTEGER), - TestMessages.update( - contextId, - idOp2, - ConstantsGen.INTEGER, - Api.MethodCall( - Api.MethodPointer( - "Standard.Base.Data.Numbers", - ConstantsGen.INTEGER, - "+" + // execute expression + context.send( + Api.Request( + requestId, + Api.ExecuteExpression( + contextId, + visualizationId, + idRes, + "fun1 operator1" ) ) - ), - TestMessages.update(contextId, idRes, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - - // execute expression - context.send( - Api.Request( - requestId, - Api.ExecuteExpression( - contextId, - visualizationId, - idRes, - "fun1 operator1" - ) ) - ) - val executeExpressionResponses = - context.receiveNIgnoreExpressionUpdates(3) - executeExpressionResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = executeExpressionResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idRes` - ), - data - ) - ) => - data - } - new String(data) shouldEqual "42" + val executeExpressionResponses = + context.receiveNIgnoreExpressionUpdates(3) + executeExpressionResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = executeExpressionResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idRes` + ), + data + ) + ) => + data + } + new String(data) shouldEqual "42" } - it should "execute expression in the scope of local binding" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata("import Standard.Base.Data.Numbers\n\n") + it should "execute expression in the scope of local binding" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata("import Standard.Base.Data.Numbers\n\n") - val idOp1 = metadata.addItem(23, 2) - val idOp2 = metadata.addItem(42, 13) - val idOp2Binding = metadata.addItem(30, 25) - val idRes = metadata.addItem(60, 9) + val idOp1 = metadata.addItem(23, 2) + val idOp2 = metadata.addItem(42, 13) + val idOp2Binding = metadata.addItem(30, 25) + val idRes = metadata.addItem(60, 9) - val code = - """main = - | operator1 = 42 - | operator2 = operator1 + 1 - | operator2 - | - |fun1 x = x.to_text - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) + val code = + """main = + | operator1 = 42 + | operator2 = operator1 + 1 + | operator2 + | + |fun1 x = x.to_text + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, moduleName, "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 6 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.update(contextId, idOp1, ConstantsGen.INTEGER), - TestMessages.update( - contextId, - idOp2, - ConstantsGen.INTEGER, - Api.MethodCall( - Api.MethodPointer( - "Standard.Base.Data.Numbers", - ConstantsGen.INTEGER, - "+" + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 6 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update(contextId, idOp1, ConstantsGen.INTEGER), + TestMessages.update( + contextId, + idOp2, + ConstantsGen.INTEGER, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Data.Numbers", + ConstantsGen.INTEGER, + "+" + ) + ) + ), + TestMessages + .update(contextId, idOp2Binding, ConstantsGen.NOTHING), + TestMessages.update(contextId, idRes, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) + + // execute expression + context.send( + Api.Request( + requestId, + Api.ExecuteExpression( + contextId, + visualizationId, + idOp2Binding, + "fun1 operator1+operator2" ) ) - ), - TestMessages - .update(contextId, idOp2Binding, ConstantsGen.NOTHING), - TestMessages.update(contextId, idRes, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - - // execute expression - context.send( - Api.Request( - requestId, - Api.ExecuteExpression( - contextId, - visualizationId, - idOp2Binding, - "fun1 operator1+operator2" - ) ) - ) - val executeExpressionResponses = - context.receiveNIgnoreExpressionUpdates(3) - executeExpressionResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = executeExpressionResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idOp2Binding` - ), - data - ) - ) => - data - } - new String(data) shouldEqual "85" + val executeExpressionResponses = + context.receiveNIgnoreExpressionUpdates(3) + executeExpressionResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = executeExpressionResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idOp2Binding` + ), + data + ) + ) => + data + } + new String(data) shouldEqual "85" } - it should "execute expression in the scope of main method" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata("import Standard.Base.Data.Numbers\n\n") + it should "execute expression in the scope of main method" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata("import Standard.Base.Data.Numbers\n\n") - val idOp1 = metadata.addItem(23, 2) - val idOp2 = metadata.addItem(42, 13) - val idMain = metadata.addItem(6, 63) + val idOp1 = metadata.addItem(23, 2) + val idOp2 = metadata.addItem(42, 13) + val idMain = metadata.addItem(6, 63) - val code = - """main = - | operator1 = 42 - | operator2 = operator1 + 1 - | operator2 - | - |fun1 x = x.to_text - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) + val code = + """main = + | operator1 = 42 + | operator2 = operator1 + 1 + | operator2 + | + |fun1 x = x.to_text + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, moduleName, "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 5 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.update(contextId, idOp1, ConstantsGen.INTEGER), - TestMessages.update( - contextId, - idOp2, - ConstantsGen.INTEGER, - Api.MethodCall( - Api.MethodPointer( - "Standard.Base.Data.Numbers", - ConstantsGen.INTEGER, - "+" + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 5 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update(contextId, idOp1, ConstantsGen.INTEGER), + TestMessages.update( + contextId, + idOp2, + ConstantsGen.INTEGER, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Data.Numbers", + ConstantsGen.INTEGER, + "+" + ) + ) + ), + TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), + context.executionComplete(contextId) + ) + + // execute expression + context.send( + Api.Request( + requestId, + Api.ExecuteExpression( + contextId, + visualizationId, + idMain, + "fun1 operator1+operator2" ) ) - ), - TestMessages.update(contextId, idMain, ConstantsGen.INTEGER), - context.executionComplete(contextId) - ) - - // execute expression - context.send( - Api.Request( - requestId, - Api.ExecuteExpression( - contextId, - visualizationId, - idMain, - "fun1 operator1+operator2" - ) ) - ) - val executeExpressionResponses = - context.receiveNIgnoreExpressionUpdates(3) - executeExpressionResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = executeExpressionResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMain` - ), - data - ) - ) => - data - } - new String(data) shouldEqual "85" + val executeExpressionResponses = + context.receiveNIgnoreExpressionUpdates(3) + executeExpressionResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = executeExpressionResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMain` + ), + data + ) + ) => + data + } + new String(data) shouldEqual "85" } - it should "execute default visualization preprocessor" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata + it should "execute default visualization preprocessor" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata - val idMain = metadata.addItem(60, 6) + val idMain = metadata.addItem(60, 6) - val code = - """import Standard.Visualization.Preprocessor - | - |main = - | fn = x -> x - | fn - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) + val code = + """import Standard.Visualization.Preprocessor + | + |main = + | fn = x -> x + | fn + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, moduleName, "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 3 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.update( - contextId, - idMain, - ConstantsGen.FUNCTION - ), - context.executionComplete(contextId) - ) - - // execute expression - context.send( - Api.Request( - requestId, - Api.ExecuteExpression( + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 3 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update( contextId, - visualizationId, idMain, - "Preprocessor.default_preprocessor 85" + ConstantsGen.FUNCTION + ), + context.executionComplete(contextId) + ) + + // execute expression + context.send( + Api.Request( + requestId, + Api.ExecuteExpression( + contextId, + visualizationId, + idMain, + "Preprocessor.default_preprocessor 85" + ) ) ) - ) - val executeExpressionResponses = - context.receiveNIgnoreExpressionUpdates(3) - executeExpressionResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = executeExpressionResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMain` - ), - data - ) - ) => - data - } - new String(data) shouldEqual "85" + val executeExpressionResponses = + context.receiveNIgnoreExpressionUpdates(3) + executeExpressionResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = executeExpressionResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMain` + ), + data + ) + ) => + data + } + new String(data) shouldEqual "85" } - it should "execute default visualization preprocessor with a FQN" in { - val contextId = UUID.randomUUID() - val requestId = UUID.randomUUID() - val visualizationId = UUID.randomUUID() - val moduleName = "Enso_Test.Test.Main" - val metadata = new Metadata + it should "execute default visualization preprocessor with a FQN" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val metadata = new Metadata - val idMain = metadata.addItem(90, 6) + val idMain = metadata.addItem(90, 6) - val code = - """import Standard.Visualization - |import Standard.Visualization.Preprocessor - | - |main = - | fn = x -> x - | fn - |""".stripMargin.linesIterator.mkString("\n") - val contents = metadata.appendToCode(code) - val mainFile = context.writeMain(contents) + val code = + """import Standard.Visualization + |import Standard.Visualization.Preprocessor + | + |main = + | fn = x -> x + | fn + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) - // create context - context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) - context.receive shouldEqual Some( - Api.Response(requestId, Api.CreateContextResponse(contextId)) - ) + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) - // Open the new file - context.send( - Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) - ) - context.receive shouldEqual Some( - Api.Response(Some(requestId), Api.OpenFileResponse) - ) + // Open the new file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) - // push main - val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(moduleName, moduleName, "main"), - None, - Vector() - ) - context.send( - Api.Request(requestId, Api.PushContextRequest(contextId, item1)) - ) - context.receiveNIgnorePendingExpressionUpdates( - 3 - ) should contain theSameElementsAs Seq( - Api.Response(requestId, Api.PushContextResponse(contextId)), - TestMessages.update( - contextId, - idMain, - ConstantsGen.FUNCTION - ), - context.executionComplete(contextId) - ) - - // execute expression - context.send( - Api.Request( - requestId, - Api.ExecuteExpression( + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 3 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update( contextId, - visualizationId, idMain, - "Standard.Visualization.Preprocessor.default_preprocessor 85" + ConstantsGen.FUNCTION + ), + context.executionComplete(contextId) + ) + + // execute expression + context.send( + Api.Request( + requestId, + Api.ExecuteExpression( + contextId, + visualizationId, + idMain, + "Standard.Visualization.Preprocessor.default_preprocessor 85" + ) ) ) - ) - val executeExpressionResponses = - context.receiveNIgnoreExpressionUpdates(3) - executeExpressionResponses should contain allOf ( - Api.Response(requestId, Api.VisualizationAttached()), - context.executionComplete(contextId) - ) - val Some(data) = executeExpressionResponses.collectFirst { - case Api.Response( - None, - Api.VisualizationUpdate( - Api.VisualizationContext( - `visualizationId`, - `contextId`, - `idMain` - ), - data - ) - ) => - data - } - new String(data) shouldEqual "85" + val executeExpressionResponses = + context.receiveNIgnoreExpressionUpdates(3) + executeExpressionResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = executeExpressionResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idMain` + ), + data + ) + ) => + data + } + new String(data) shouldEqual "85" } }