diff --git a/cli/src/integrationTest/kotlin/com/specificlanguages/mops/cli/CreatedSolutionIntegrationTest.kt b/cli/src/integrationTest/kotlin/com/specificlanguages/mops/cli/CreatedSolutionIntegrationTest.kt new file mode 100644 index 00000000..906ffe4f --- /dev/null +++ b/cli/src/integrationTest/kotlin/com/specificlanguages/mops/cli/CreatedSolutionIntegrationTest.kt @@ -0,0 +1,60 @@ +package com.specificlanguages.mops.cli + +import com.specificlanguages.mops.protocol.MakeOutcome +import com.specificlanguages.mops.protocol.MakeResponse +import com.specificlanguages.mops.protocol.ProtocolJson +import org.junit.jupiter.api.io.CleanupMode +import org.junit.jupiter.api.io.TempDir +import org.junit.jupiter.api.parallel.ResourceLock +import java.nio.file.Path +import kotlin.io.path.createDirectories +import kotlin.io.path.pathString +import kotlin.io.path.writeText +import kotlin.test.Test +import kotlin.test.assertEquals + +/** Creates a solution with `mops create solution`, adds a test to it, and makes and tests it in a worker process. */ +@ResourceLock("system-streams") +class CreatedSolutionIntegrationTest { + @TempDir(cleanup = CleanupMode.ON_SUCCESS) + lateinit var tempDir: Path + + @Test + fun `a solution created with the java-tests preset makes and runs its tests`() { + val project = copyTestProject("base-language-sandbox", tempDir.resolve("project")) + val home = tempDir.resolve("daemon-home").createDirectories() + fun cli(vararg args: String) = runCommandLine(project, "--daemon-home", home.pathString, *javaAndMpsHomeArgs(), *args) + try { + assertEquals(0, cli("create", "solution", "created.tests", "--usage-preset", "java-tests").exitCode) + assertEquals(0, cli("create", "model", "created.tests.main", "--module", "created.tests").exitCode) + val script = tempDir.resolve("content.groovy") + script.writeText(""" + project.command { + def module = mops.lookup.requireModule('created.tests') + def descriptor = module.moduleDescriptor + ['49808fad-9d41-4b96-83fa-9231640f6b2b(JUnit)', '6354ebe7-c22a-4a0f-ac54-50b52ab9b065(JDK)'].each { + descriptor.dependencies.add(new jetbrains.mps.project.structure.modules.Dependency( + org.jetbrains.mps.openapi.persistence.PersistenceFacade.instance.createModuleReference(it), false)) + } + module.setModuleDescriptor(descriptor) + module.save() + mops.parsing.java.addJavaClassesFromString(mops.lookup.requireModel('created.tests.main'), + 'public class CreatedTest extends junit.framework.TestCase { public void testSum() { assertEquals(2, 1 + 1); } }').unresolved + } + """.trimIndent()) + val content = cli("code", "run", script.pathString) + assertEquals(0, content.exitCode, content.output) + val unresolvedReferences = content.stdout.trim() + assertEquals("[]", unresolvedReferences, content.output) + + val make = cli("make", "module", "created.tests", "--json") + assertEquals(0, make.exitCode, make.output) + assertEquals(MakeOutcome.SUCCESS, (ProtocolJson.decodeResponse(make.stdout) as MakeResponse).outcome, make.output) + val test = cli("test", "created.tests", "--no-build", "--json") + assertEquals(0, test.exitCode, test.output) + val report = ProtocolJson.testReport.decode(test.stdout) + assertEquals("SUCCESS", report.outcome, test.output) + assertEquals(listOf("PASSED"), report.results.filter { it.kind == "TEST" }.map { it.status }, test.output) + } finally { stopDaemons(project, home) } + } +} diff --git a/daemon/src/main/kotlin/com/specificlanguages/mops/daemon/ModuleCreator.kt b/daemon/src/main/kotlin/com/specificlanguages/mops/daemon/ModuleCreator.kt index 1b343657..e4eb8e0a 100644 --- a/daemon/src/main/kotlin/com/specificlanguages/mops/daemon/ModuleCreator.kt +++ b/daemon/src/main/kotlin/com/specificlanguages/mops/daemon/ModuleCreator.kt @@ -140,7 +140,7 @@ class ModuleCreator(private val project: Project) { moduleFacetDescriptors.add(JavaModuleFacetImpl.forJavaCodeModule( JavaModuleFacet.Compile.MPS, JavaModuleFacet.LoadClasses.ManagedByMPS, JavaModuleFacet.LoadExtensions.Plugin, )) - outputRoot = "\${module}/source_gen" + outputRoot = DEFAULT_OUTPUT_ROOT } return (ModuleRepositoryFacade(mpsProject).instantiate(value, descriptorFile) as Language) .also { mpsProject.addModule(it); it.setChanged() } @@ -167,6 +167,7 @@ class ModuleCreator(private val project: Project) { JavaModuleFacet.Compile.MPS, JavaModuleFacet.LoadClasses.ManagedByMPS, JavaModuleFacet.LoadExtensions.Plugin, )) } + if (preset != SolutionUsagePreset.NOT_GENERATED) outputRoot = DEFAULT_OUTPUT_ROOT } return (instantiate(value, file(descriptor)) as Solution).also { mpsProject.addModule(it); it.setChanged() } } @@ -279,4 +280,9 @@ class ModuleCreator(private val project: Project) { private fun file(path: Path) = mpsProject.fileSystem.getFile(path.toString()) private fun fail(code: MpsErrorCode, message: String): Nothing = throw MpsRequestException(code, message) + + private companion object { + /** The generator output root that MPS uses when a module descriptor does not name one. */ + const val DEFAULT_OUTPUT_ROOT = "\${module}/source_gen" + } } diff --git a/daemon/src/test/kotlin/com/specificlanguages/mops/daemon/ModuleCreationSemanticsTest.kt b/daemon/src/test/kotlin/com/specificlanguages/mops/daemon/ModuleCreationSemanticsTest.kt index 6de91aae..6b21d565 100644 --- a/daemon/src/test/kotlin/com/specificlanguages/mops/daemon/ModuleCreationSemanticsTest.kt +++ b/daemon/src/test/kotlin/com/specificlanguages/mops/daemon/ModuleCreationSemanticsTest.kt @@ -8,6 +8,8 @@ import com.specificlanguages.mops.protocol.GeneratorPersistence import com.specificlanguages.mops.protocol.ModuleCreationResponse import com.specificlanguages.mops.protocol.ModuleKind import com.specificlanguages.mops.protocol.SolutionUsagePreset +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource import kotlin.io.path.exists import kotlin.io.path.readText import kotlin.test.assertIs @@ -35,6 +37,18 @@ class ModuleCreationSemanticsTest { } } + @ParameterizedTest + @EnumSource(SolutionUsagePreset::class, names = ["TEXT", "JAVA", "JAVA_TESTS", "JAVA_MPS_PLUGIN"]) + fun `solution of a generated preset keeps the default generator output path`(preset: SolutionUsagePreset) { + SharedMpsEnvironment.withOpenProjectCopy { project, projectPath -> + DomainRequestHandler(projectPath, SharedMpsEnvironment.mpsAccess(project)) + .handleDomainRequest(CreateSolutionRequest("", "example.generated", usagePreset = preset)) + + val descriptor = projectPath.resolve("solutions/example.generated/example.generated.msd").readText() + assertFalse("generatorOutputPath" in descriptor, descriptor) + } + } + @Test fun `solution report names the usage preset and the facets it produced`() { SharedMpsEnvironment.withOpenProjectCopy { project, _ ->