diff --git a/.idea/misc.xml b/.idea/misc.xml index d79c99176..a1c50656f 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -16,7 +16,10 @@ + + + - + \ No newline at end of file diff --git a/compiler/build.gradle b/compiler/build.gradle index bc08e979d..d2a4640f6 100644 --- a/compiler/build.gradle +++ b/compiler/build.gradle @@ -3,6 +3,7 @@ plugins { id 'application' id "org.jetbrains.kotlin.jvm" id 'com.github.johnrengelman.shadow' version '7.1.0' + id "io.kotest" version "0.3.8" } java { @@ -25,9 +26,7 @@ dependencies { testImplementation 'io.kotest:kotest-runner-junit5-jvm:4.6.3' testImplementation "org.jetbrains.kotlin:kotlin-test-junit5" - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.2' testImplementation 'org.hamcrest:hamcrest:2.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2' } configurations.all { diff --git a/compiler/compiler.iml b/compiler/compiler.iml index 2066e7a02..994fbe6bd 100644 --- a/compiler/compiler.iml +++ b/compiler/compiler.iml @@ -1,10 +1,5 @@ - - - - - @@ -17,7 +12,6 @@ - diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 31aa9172e..6c1f8e8ab 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -20,7 +20,7 @@ internal class AstChecker(private val program: Program, ) : IAstVisitor { override fun visit(program: Program) { - assert(program === this.program) + require(program === this.program) // there must be a single 'main' block with a 'start' subroutine for the program entry point. val mainBlocks = program.modules.flatMap { it.statements }.filter { b -> b is Block && b.name=="main" }.map { it as Block } if(mainBlocks.size>1) diff --git a/compiler/test/ModuleImporterTests.kt b/compiler/test/ModuleImporterTests.kt index e9e6098b3..4f4aca465 100644 --- a/compiler/test/ModuleImporterTests.kt +++ b/compiler/test/ModuleImporterTests.kt @@ -6,7 +6,6 @@ import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo import org.hamcrest.Matchers.nullValue import org.hamcrest.core.Is -import org.junit.jupiter.api.* import prog8.ast.Program import prog8.ast.internedStringsModuleName import prog8.compiler.ModuleImporter @@ -19,52 +18,50 @@ import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyMemsizer import prog8tests.helpers.DummyStringEncoder import kotlin.io.path.* -import kotlin.test.assertContains -import kotlin.test.assertFailsWith -import kotlin.test.assertFalse -import kotlin.test.fail +import io.kotest.assertions.fail +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.assertions.withClue +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.collections.shouldBeIn +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestModuleImporter { - private val count = listOf("1st", "2nd", "3rd", "4th", "5th") +class TestModuleImporter: FunSpec({ + val count = listOf("1st", "2nd", "3rd", "4th", "5th") - private lateinit var program: Program - @BeforeEach - fun beforeEach() { + lateinit var program: Program + + beforeTest { program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder) } - private fun makeImporter(errors: IErrorReporter?, vararg searchIn: String): ModuleImporter { + fun makeImporter(errors: IErrorReporter? = null, searchIn: Iterable) = + ModuleImporter(program, "blah", errors ?: ErrorReporterForTests(false), searchIn.toList()) + + fun makeImporter(errors: IErrorReporter?, vararg searchIn: String): ModuleImporter { return makeImporter(errors, searchIn.asList()) } - private fun makeImporter(errors: IErrorReporter? = null, searchIn: Iterable) = - ModuleImporter(program, "blah", errors ?: ErrorReporterForTests(false), searchIn.toList()) + context("Constructor") { - @Nested - inner class Constructor { + //Disabled("TODO: invalid entries in search list") + xtest("testInvalidEntriesInSearchList") { + } - @Test - @Disabled("TODO: invalid entries in search list") - fun testInvalidEntriesInSearchList() {} + //Disabled("TODO: literal duplicates in search list") + xtest("testLiteralDuplicatesInSearchList") { + } - @Test - @Disabled("TODO: literal duplicates in search list") - fun testLiteralDuplicatesInSearchList() {} - - @Test - @Disabled("TODO: factual duplicates in search list") - fun testFactualDuplicatesInSearchList() {} + //Disabled("TODO: factual duplicates in search list") + xtest("testFactualDuplicatesInSearchList") { + } } - @Nested - inner class ImportModule { + context("ImportModule") { - @Nested - inner class WithInvalidPath { - @Test - fun testNonexisting() { + context("WithInvalidPath") { + test("testNonexisting") { val dirRel = assumeDirectory(".", workingDir.relativize(fixturesDir)) val importer = makeImporter(null, dirRel.invariantSeparatorsPathString) val srcPathRel = assumeNotExists(dirRel, "i_do_not_exist") @@ -92,14 +89,13 @@ class TestModuleImporter { assertThat(program.modules.size, equalTo(1)) } - @Test - fun testDirectory() { + test("testDirectory") { val srcPathRel = assumeDirectory(workingDir.relativize(fixturesDir)) val srcPathAbs = srcPathRel.absolute() val searchIn = Path(".", "$srcPathRel").invariantSeparatorsPathString val importer = makeImporter(null, searchIn) - assertFailsWith { importer.importModule(srcPathRel) } + shouldThrow { importer.importModule(srcPathRel) } .let { assertThat( ".file should be normalized", @@ -112,7 +108,7 @@ class TestModuleImporter { } assertThat(program.modules.size, equalTo(1)) - assertFailsWith { importer.importModule(srcPathAbs) } + shouldThrow { importer.importModule(srcPathAbs) } .let { assertThat( ".file should be normalized", @@ -127,11 +123,9 @@ class TestModuleImporter { } } - @Nested - inner class WithValidPath { + context("WithValidPath") { - @Test - fun testAbsolute() { + test("testAbsolute") { val searchIn = listOf( Path(".").div(workingDir.relativize(fixturesDir)), // we do want a dot "." in front ).map { it.invariantSeparatorsPathString } @@ -141,12 +135,11 @@ class TestModuleImporter { val module = importer.importModule(path.absolute()).getOrElse { throw it } assertThat(program.modules.size, equalTo(2)) - assertContains(program.modules, module) + module shouldBeIn program.modules assertThat(module.program, equalTo(program)) } - @Test - fun testRelativeToWorkingDir() { + test("testRelativeToWorkingDir") { val searchIn = listOf( Path(".").div(workingDir.relativize(fixturesDir)), // we do want a dot "." in front ).map { it.invariantSeparatorsPathString } @@ -157,12 +150,11 @@ class TestModuleImporter { val module = importer.importModule(path).getOrElse { throw it } assertThat(program.modules.size, equalTo(2)) - assertContains(program.modules, module) + module shouldBeIn program.modules assertThat(module.program, equalTo(program)) } - @Test - fun testRelativeTo1stDirInSearchList() { + test("testRelativeTo1stDirInSearchList") { val searchIn = Path(".") .div(workingDir.relativize(fixturesDir)) .invariantSeparatorsPathString @@ -173,50 +165,37 @@ class TestModuleImporter { val module = importer.importModule(path).getOrElse { throw it } assertThat(program.modules.size, equalTo(2)) - assertContains(program.modules, module) + module shouldBeIn program.modules assertThat(module.program, equalTo(program)) } - @Test - @Disabled("TODO: relative to 2nd in search list") - fun testRelativeTo2ndDirInSearchList() {} + //Disabled("TODO: relative to 2nd in search list") + xtest("testRelativeTo2ndDirInSearchList") {} - @Test - @Disabled("TODO: ambiguous - 2 or more really different candidates") - fun testAmbiguousCandidates() {} + //Disabled("TODO: ambiguous - 2 or more really different candidates") + xtest("testAmbiguousCandidates") {} - @Nested - inner class WithBadFile { - @Test - fun testWithSyntaxError() { + context("WithBadFile") { + test("testWithSyntaxError") { val searchIn = assumeDirectory("./", workingDir.relativize(fixturesDir)) val importer = makeImporter(null, searchIn.invariantSeparatorsPathString) val srcPath = assumeReadableFile(fixturesDir, "file_with_syntax_error.p8") val act = { importer.importModule(srcPath) } - repeat(2) { n -> - assertFailsWith(count[n] + " call") { act() }.let { - assertThat(it.position.file, equalTo(SourceCode.relative(srcPath).toString())) - assertThat("line; should be 1-based", it.position.line, equalTo(2)) - assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6)) - assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6)) + repeat(2) { n -> withClue(count[n] + " call") { + shouldThrow() { act() }.let { + assertThat(it.position.file, equalTo(SourceCode.relative(srcPath).toString())) + assertThat("line; should be 1-based", it.position.line, equalTo(2)) + assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6)) + assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6)) + } } assertThat(program.modules.size, equalTo(1)) } } - @Test - fun testImportingFileWithSyntaxError_once() { - doTestImportingFileWithSyntaxError(1) - } - - @Test - fun testImportingFileWithSyntaxError_twice() { - doTestImportingFileWithSyntaxError(2) - } - - private fun doTestImportingFileWithSyntaxError(repetitions: Int) { + fun doTestImportingFileWithSyntaxError(repetitions: Int) { val searchIn = assumeDirectory("./", workingDir.relativize(fixturesDir)) val importer = makeImporter(null, searchIn.invariantSeparatorsPathString) val importing = assumeReadableFile(fixturesDir, "import_file_with_syntax_error.p8") @@ -224,28 +203,33 @@ class TestModuleImporter { val act = { importer.importModule(importing) } - repeat(repetitions) { n -> - assertFailsWith(count[n] + " call") { act() }.let { + repeat(repetitions) { n -> withClue(count[n] + " call") { + shouldThrow() { act() }.let { assertThat(it.position.file, equalTo(SourceCode.relative(imported).toString())) assertThat("line; should be 1-based", it.position.line, equalTo(2)) assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6)) assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6)) } + } assertThat("imported module with error in it should not be present", program.modules.size, equalTo(1)) assertThat(program.modules[0].name, equalTo(internedStringsModuleName)) } } + + test("testImportingFileWithSyntaxError_once") { + doTestImportingFileWithSyntaxError(1) + } + + test("testImportingFileWithSyntaxError_twice") { + doTestImportingFileWithSyntaxError(2) + } } } - } - @Nested - inner class ImportLibraryModule { - @Nested - inner class WithInvalidName { - @Test - fun testWithNonExistingName() { + context("ImportLibraryModule") { + context("WithInvalidName") { + test("testWithNonExistingName") { val searchIn = assumeDirectory("./", workingDir.relativize(fixturesDir)) val errors = ErrorReporterForTests(false) val importer = makeImporter(errors, searchIn.invariantSeparatorsPathString) @@ -255,45 +239,48 @@ class TestModuleImporter { repeat(2) { n -> val result = importer.importLibraryModule(filenameNoExt) assertThat(count[n] + " call / NO .p8 extension", result, Is(nullValue())) - assertFalse(errors.noErrors(), count[n] + " call / NO .p8 extension") - assertContains(errors.errors.single(), "0:0: no module found with name i_do_not_exist") + withClue(count[n] + " call / NO .p8 extension") { + errors.noErrors() shouldBe false + } + errors.errors.single() shouldContain "0:0: no module found with name i_do_not_exist" errors.report() assertThat(program.modules.size, equalTo(1)) val result2 = importer.importLibraryModule(filenameWithExt) assertThat(count[n] + " call / with .p8 extension", result2, Is(nullValue())) - assertFalse(importer.errors.noErrors(), count[n] + " call / with .p8 extension") - assertContains(errors.errors.single(), "0:0: no module found with name i_do_not_exist.p8") + withClue(count[n] + " call / with .p8 extension") { + importer.errors.noErrors() shouldBe false + } + errors.errors.single() shouldContain "0:0: no module found with name i_do_not_exist.p8" errors.report() assertThat(program.modules.size, equalTo(1)) } } } - @Nested - inner class WithValidName { - @Nested - inner class WithBadFile { - @Test - fun testWithSyntaxError() { + context("WithValidName") { + context("WithBadFile") { + test("testWithSyntaxError") { val searchIn = assumeDirectory("./", workingDir.relativize(fixturesDir)) val importer = makeImporter(null, searchIn.invariantSeparatorsPathString) val srcPath = assumeReadableFile(fixturesDir, "file_with_syntax_error.p8") - repeat(2) { n -> - assertFailsWith(count[n] + " call") - { importer.importLibraryModule(srcPath.nameWithoutExtension) }.let { + repeat(2) { n -> withClue(count[n] + " call") { + shouldThrow() + { + importer.importLibraryModule(srcPath.nameWithoutExtension) }.let { assertThat(it.position.file, equalTo(SourceCode.relative(srcPath).toString())) assertThat("line; should be 1-based", it.position.line, equalTo(2)) assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6)) assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6)) } + } assertThat(program.modules.size, equalTo(1)) } } - private fun doTestImportingFileWithSyntaxError(repetitions: Int) { + fun doTestImportingFileWithSyntaxError(repetitions: Int) { val searchIn = assumeDirectory("./", workingDir.relativize(fixturesDir)) val importer = makeImporter(null, searchIn.invariantSeparatorsPathString) val importing = assumeReadableFile(fixturesDir, "import_file_with_syntax_error.p8") @@ -301,12 +288,14 @@ class TestModuleImporter { val act = { importer.importLibraryModule(importing.nameWithoutExtension) } - repeat(repetitions) { n -> - assertFailsWith(count[n] + " call") { act() }.let { - assertThat(it.position.file, equalTo(SourceCode.relative(imported).toString())) - assertThat("line; should be 1-based", it.position.line, equalTo(2)) - assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6)) - assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6)) + repeat(repetitions) { n -> withClue(count[n] + " call") { + shouldThrow() { + act() }.let { + assertThat(it.position.file, equalTo(SourceCode.relative(imported).toString())) + assertThat("line; should be 1-based", it.position.line, equalTo(2)) + assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6)) + assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6)) + } } assertThat("imported module with error in it should not be present", program.modules.size, equalTo(1)) assertThat(program.modules[0].name, equalTo(internedStringsModuleName)) @@ -314,16 +303,14 @@ class TestModuleImporter { } } - @Test - fun testImportingFileWithSyntaxError_once() { + test("testImportingFileWithSyntaxError_once") { doTestImportingFileWithSyntaxError(1) } - @Test - fun testImportingFileWithSyntaxError_twice() { + test("testImportingFileWithSyntaxError_twice") { doTestImportingFileWithSyntaxError(2) } } } } -} +}) diff --git a/compiler/test/ProjectConfig.kt b/compiler/test/ProjectConfig.kt new file mode 100644 index 000000000..1ff8e9209 --- /dev/null +++ b/compiler/test/ProjectConfig.kt @@ -0,0 +1,58 @@ +package prog8tests + +import io.kotest.core.config.AbstractProjectConfig +import io.kotest.core.listeners.Listener +import io.kotest.core.listeners.TestListener +import io.kotest.core.spec.Spec +import io.kotest.extensions.system.NoSystemErrListener +import io.kotest.extensions.system.NoSystemOutListener +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import kotlin.math.max + +object ProjectConfig : AbstractProjectConfig() { + override val parallelism = 2 // max(2, Runtime.getRuntime().availableProcessors() / 2) + // override fun listeners() = listOf(SystemOutToNullListener) +} + +//object SystemOutToNullListener: TestListener { +// override suspend fun beforeSpec(spec: Spec) = setup() +// +// private fun setup() { +// System.setOut(object: PrintStream(object: ByteArrayOutputStream(){ +// override fun write(p0: Int) { +// // do nothing +// } +// +// override fun write(b: ByteArray, off: Int, len: Int) { +// // do nothing +// } +// +// override fun write(b: ByteArray) { +// // do nothing +// } +// }){} +// ) +// } +//} +// +//object SystemErrToNullListener: TestListener { +// override suspend fun beforeSpec(spec: Spec) = setup() +// +// private fun setup() { +// System.setErr(object: PrintStream(object: ByteArrayOutputStream(){ +// override fun write(p0: Int) { +// // do nothing +// } +// +// override fun write(b: ByteArray, off: Int, len: Int) { +// // do nothing +// } +// +// override fun write(b: ByteArray) { +// // do nothing +// } +// }){} +// ) +// } +//} diff --git a/compiler/test/TestCallgraph.kt b/compiler/test/TestCallgraph.kt index bbe140d75..ab5fc265d 100644 --- a/compiler/test/TestCallgraph.kt +++ b/compiler/test/TestCallgraph.kt @@ -1,21 +1,19 @@ package prog8tests -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance +import io.kotest.assertions.withClue +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.maps.shouldContainKey +import io.kotest.matchers.maps.shouldNotContainKey +import io.kotest.matchers.shouldBe import prog8.ast.statements.Block import prog8.ast.statements.Subroutine import prog8.compiler.target.C64Target import prog8.compilerinterface.CallGraph import prog8tests.helpers.assertSuccess import prog8tests.helpers.compileText -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestCallgraph { - @Test - fun testGraphForEmptySubs() { +class TestCallgraph: FunSpec({ + test("testGraphForEmptySubs") { val sourcecode = """ %import string main { @@ -28,32 +26,33 @@ class TestCallgraph { val result = compileText(C64Target, false, sourcecode).assertSuccess() val graph = CallGraph(result.program) - assertEquals(1, graph.imports.size) - assertEquals(1, graph.importedBy.size) + graph.imports.size shouldBe 1 + graph.importedBy.size shouldBe 1 val toplevelModule = result.program.toplevelModule val importedModule = graph.imports.getValue(toplevelModule).single() - assertEquals("string", importedModule.name) + importedModule.name shouldBe "string" val importedBy = graph.importedBy.getValue(importedModule).single() - assertTrue(importedBy.name.startsWith("on_the_fly_test")) + importedBy.name.startsWith("on_the_fly_test") shouldBe true - assertFalse(graph.unused(toplevelModule)) - assertFalse(graph.unused(importedModule)) + graph.unused(toplevelModule) shouldBe false + graph.unused(importedModule) shouldBe false val mainBlock = toplevelModule.statements.filterIsInstance().single() for(stmt in mainBlock.statements) { val sub = stmt as Subroutine - assertFalse(sub in graph.calls) - assertFalse(sub in graph.calledBy) + graph.calls shouldNotContainKey sub + graph.calledBy shouldNotContainKey sub if(sub === result.program.entrypoint) - assertFalse(graph.unused(sub), "start() should always be marked as used to avoid having it removed") + withClue("start() should always be marked as used to avoid having it removed") { + graph.unused(sub) shouldBe false + } else - assertTrue(graph.unused(sub)) + graph.unused(sub) shouldBe true } } - @Test - fun testGraphForEmptyButReferencedSub() { + test("testGraphForEmptyButReferencedSub") { val sourcecode = """ %import string main { @@ -68,24 +67,32 @@ class TestCallgraph { val result = compileText(C64Target, false, sourcecode).assertSuccess() val graph = CallGraph(result.program) - assertEquals(1, graph.imports.size) - assertEquals(1, graph.importedBy.size) + graph.imports.size shouldBe 1 + graph.importedBy.size shouldBe 1 val toplevelModule = result.program.toplevelModule val importedModule = graph.imports.getValue(toplevelModule).single() - assertEquals("string", importedModule.name) + importedModule.name shouldBe "string" val importedBy = graph.importedBy.getValue(importedModule).single() - assertTrue(importedBy.name.startsWith("on_the_fly_test")) + importedBy.name.startsWith("on_the_fly_test") shouldBe true - assertFalse(graph.unused(toplevelModule)) - assertFalse(graph.unused(importedModule)) + graph.unused(toplevelModule) shouldBe false + graph.unused(importedModule) shouldBe false val mainBlock = toplevelModule.statements.filterIsInstance().single() val startSub = mainBlock.statements.filterIsInstance().single{it.name=="start"} val emptySub = mainBlock.statements.filterIsInstance().single{it.name=="empty"} - assertTrue(startSub in graph.calls, "start 'calls' (references) empty") - assertFalse(emptySub in graph.calls, "empty doesn't call anything") - assertTrue(emptySub in graph.calledBy, "empty gets 'called'") - assertFalse(startSub in graph.calledBy, "start doesn't get called (except as entrypoint ofc.)") + withClue("start 'calls' (references) empty") { + graph.calls shouldContainKey startSub + } + withClue("empty doesn't call anything") { + graph.calls shouldNotContainKey emptySub + } + withClue("empty gets 'called'") { + graph.calledBy shouldContainKey emptySub + } + withClue( "start doesn't get called (except as entrypoint ofc.)") { + graph.calledBy shouldNotContainKey startSub + } } -} +}) diff --git a/compiler/test/TestCompilerOnCharLit.kt b/compiler/test/TestCompilerOnCharLit.kt index 87395cc54..8c81a3368 100644 --- a/compiler/test/TestCompilerOnCharLit.kt +++ b/compiler/test/TestCompilerOnCharLit.kt @@ -1,7 +1,10 @@ package prog8tests -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance +import io.kotest.assertions.withClue +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.instanceOf +import org.junit.jupiter.api.Assertions.fail import prog8.ast.IFunctionCall import prog8.ast.base.DataType import prog8.ast.base.VarDeclType @@ -11,9 +14,6 @@ import prog8.ast.statements.Assignment import prog8.compiler.target.Cx16Target import prog8tests.helpers.assertSuccess import prog8tests.helpers.compileText -import kotlin.test.assertEquals -import kotlin.test.assertIs -import kotlin.test.assertNull /** @@ -21,11 +21,9 @@ import kotlin.test.assertNull * They are not really unit tests, but rather tests of the whole process, * from source file loading all the way through to running 64tass. */ -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestCompilerOnCharLit { +class TestCompilerOnCharLit: FunSpec({ - @Test - fun testCharLitAsRomsubArg() { + test("testCharLitAsRomsubArg") { val platform = Cx16Target val result = compileText(platform, false, """ main { @@ -40,15 +38,15 @@ class TestCompilerOnCharLit { val startSub = program.entrypoint val funCall = startSub.statements.filterIsInstance()[0] - assertIs(funCall.args[0], - "char literal should have been replaced by ubyte literal") + withClue("char literal should have been replaced by ubyte literal") { + funCall.args[0] shouldBe instanceOf() + } val arg = funCall.args[0] as NumericLiteralValue - assertEquals(DataType.UBYTE, arg.type) - assertEquals(platform.encodeString("\n", false)[0], arg.number.toShort()) + arg.type shouldBe DataType.UBYTE + arg.number.toShort() shouldBe platform.encodeString("\n", false)[0] } - @Test - fun testCharVarAsRomsubArg() { + test("testCharVarAsRomsubArg") { val platform = Cx16Target val result = compileText(platform, false, """ main { @@ -64,28 +62,31 @@ class TestCompilerOnCharLit { val startSub = program.entrypoint val funCall = startSub.statements.filterIsInstance()[0] - assertIs(funCall.args[0]) + funCall.args[0] shouldBe instanceOf() val arg = funCall.args[0] as IdentifierReference val decl = arg.targetVarDecl(program)!! - assertEquals(VarDeclType.VAR, decl.type) - assertEquals(DataType.UBYTE, decl.datatype) + decl.type shouldBe VarDeclType.VAR + decl.datatype shouldBe DataType.UBYTE // TODO: assertIs(decl.value, // "char literals should be kept until code gen") // val initializerValue = decl.value as CharLiteral // assertEquals('\n', (initializerValue as CharLiteral).value) - assertNull(decl.value, "initializer value should have been moved to separate assignment") + withClue("initializer value should have been moved to separate assignment"){ + decl.value shouldBe null + } val assignInitialValue = decl.nextSibling() as Assignment - assertEquals(listOf("ch"), assignInitialValue.target.identifier!!.nameInSource) - assertIs(assignInitialValue.value, "char literal should have been replaced by ubyte literal") + assignInitialValue.target.identifier!!.nameInSource shouldBe listOf("ch") + withClue("char literal should have been replaced by ubyte literal") { + assignInitialValue.value shouldBe instanceOf() + } val initializerValue = assignInitialValue.value as NumericLiteralValue - assertEquals(DataType.UBYTE, initializerValue.type) - assertEquals(platform.encodeString("\n", false)[0], initializerValue.number.toShort()) + initializerValue.type shouldBe DataType.UBYTE + initializerValue.number.toShort() shouldBe platform.encodeString("\n", false)[0] } - @Test - fun testCharConstAsRomsubArg() { + test("testCharConstAsRomsubArg") { val platform = Cx16Target val result = compileText(platform, false, """ main { @@ -105,20 +106,15 @@ class TestCompilerOnCharLit { when (val arg = funCall.args[0]) { is IdentifierReference -> { val decl = arg.targetVarDecl(program)!! - assertEquals(VarDeclType.CONST, decl.type) - assertEquals(DataType.UBYTE, decl.datatype) - assertEquals( - platform.encodeString("\n", false)[0], - (decl.value as NumericLiteralValue).number.toShort()) + decl.type shouldBe VarDeclType.CONST + decl.datatype shouldBe DataType.UBYTE + (decl.value as NumericLiteralValue).number.toShort() shouldBe platform.encodeString("\n", false)[0] } is NumericLiteralValue -> { - assertEquals( - platform.encodeString("\n", false)[0], - arg.number.toShort()) + arg.number.toShort() shouldBe platform.encodeString("\n", false)[0] } - else -> assertIs(funCall.args[0]) // make test fail + else -> fail("invalid arg type") // funCall.args[0] shouldBe instanceOf() // make test fail } } -} - +}) diff --git a/compiler/test/TestCompilerOnExamples.kt b/compiler/test/TestCompilerOnExamples.kt index c8910cf7f..1d2e7c068 100644 --- a/compiler/test/TestCompilerOnExamples.kt +++ b/compiler/test/TestCompilerOnExamples.kt @@ -1,18 +1,13 @@ package prog8tests -import org.junit.jupiter.api.DynamicTest -import org.junit.jupiter.api.DynamicTest.dynamicTest -import org.junit.jupiter.api.TestFactory -import org.junit.jupiter.api.TestInstance +import io.kotest.core.spec.style.FunSpec import prog8.compiler.compileProgram import prog8.compiler.target.C64Target import prog8.compiler.target.Cx16Target import prog8.compilerinterface.ICompilationTarget -import prog8tests.ast.helpers.assumeDirectory -import prog8tests.ast.helpers.mapCombinations -import prog8tests.ast.helpers.outputDir -import prog8tests.ast.helpers.workingDir +import prog8tests.ast.helpers.* import prog8tests.helpers.assertSuccess +import java.nio.file.Path import kotlin.io.path.absolute import kotlin.io.path.exists @@ -22,41 +17,94 @@ import kotlin.io.path.exists * They are not really unit tests, but rather tests of the whole process, * from source file loading all the way through to running 64tass. */ -// @Disabled("disable to save some time") -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestCompilerOnExamples { - private val examplesDir = assumeDirectory(workingDir, "../examples") - private fun makeDynamicCompilerTest(name: String, platform: ICompilationTarget, optimize: Boolean) : DynamicTest { - val searchIn = mutableListOf(examplesDir) - if (platform == Cx16Target) { - searchIn.add(0, assumeDirectory(examplesDir, "cx16")) - } - val filepath = searchIn - .map { it.resolve("$name.p8") } - .map { it.normalize().absolute() } - .map { workingDir.relativize(it) } - .first { it.exists() } - val displayName = "${examplesDir.relativize(filepath.absolute())}: ${platform.name}, optimize=$optimize" - return dynamicTest(displayName) { - compileProgram( - filepath, - optimize, - optimizeFloatExpressions = false, - writeAssembly = true, - slowCodegenWarnings = false, - quietAssembler = true, - compilationTarget = platform.name, - sourceDirs = listOf(), - outputDir - ).assertSuccess("; $displayName") +private val examplesDir = assumeDirectory(workingDir, "../examples") + +private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilationTarget) = compileProgram( + filepath, + optimize, + optimizeFloatExpressions = false, + writeAssembly = true, + slowCodegenWarnings = false, + quietAssembler = true, + compilationTarget = target.name, + sourceDirs = listOf(), + outputDir +) + +private fun prepareTestFiles(source: String, optimize: Boolean, target: ICompilationTarget): Pair { + val searchIn = mutableListOf(examplesDir) + if (target == Cx16Target) { + searchIn.add(0, assumeDirectory(examplesDir, "cx16")) + } + val filepath = searchIn + .map { it.resolve("$source.p8") } + .map { it.normalize().absolute() } + .map { workingDir.relativize(it) } + .first { it.exists() } + val displayName = "${examplesDir.relativize(filepath.absolute())}: ${target.name}, optimize=$optimize" + return Pair(displayName, filepath) +} + + +class TestCompilerOnExamplesC64: FunSpec({ + + val onlyC64 = cartesianProduct( + listOf( + "balloonflight", + "bdmusic", + "bdmusic-irq", + "charset", + "cube3d-sprites", + "plasma", + "sprites", + "turtle-gfx", + "wizzine", + ), + listOf(false, true) + ) + + onlyC64.forEach { + val (source, optimize) = it + val (displayName, filepath) = prepareTestFiles(source, optimize, C64Target) + test(displayName) { + compileTheThing(filepath, optimize, C64Target).assertSuccess() } } +}) - @TestFactory -// @Disabled("disable to save some time") - fun bothCx16AndC64() = mapCombinations( - dim1 = listOf( +class TestCompilerOnExamplesCx16: FunSpec({ + + val onlyCx16 = cartesianProduct( + listOf( + "vtui/testvtui", + "amiga", + "bobs", + "cobramk3-gfx", + "colorbars", + "datetime", + "highresbitmap", + "kefrenbars", + "mandelbrot-gfx-colors", + "multipalette", + "testgfx2", + ), + listOf(false, true) + ) + + onlyCx16.forEach { + val (source, optimize) = it + val (displayName, filepath) = prepareTestFiles(source, optimize, Cx16Target) + test(displayName) { + compileTheThing(filepath, optimize, Cx16Target).assertSuccess() + } + } +}) + +class TestCompilerOnExamplesBothC64andCx16: FunSpec({ + + val bothCx16AndC64 = cartesianProduct( + listOf( "animals", "balls", "cube3d", @@ -79,48 +127,18 @@ class TestCompilerOnExamples { "tehtriz", "textelite", ), - dim2 = listOf(Cx16Target, C64Target), - dim3 = listOf(false, true), - combine3 = ::makeDynamicCompilerTest + listOf(false, true) ) - @TestFactory -// @Disabled("disable to save some time") - fun onlyC64() = mapCombinations( - dim1 = listOf( - "balloonflight", - "bdmusic", - "bdmusic-irq", - "charset", - "cube3d-sprites", - "plasma", - "sprites", - "turtle-gfx", - "wizzine", - ), - dim2 = listOf(C64Target), - dim3 = listOf(false, true), - combine3 = ::makeDynamicCompilerTest - ) - - @TestFactory -// @Disabled("disable to save some time") - fun onlyCx16() = mapCombinations( - dim1 = listOf( - "vtui/testvtui", - "amiga", - "bobs", - "cobramk3-gfx", - "colorbars", - "datetime", - "highresbitmap", - "kefrenbars", - "mandelbrot-gfx-colors", - "multipalette", - "testgfx2", - ), - dim2 = listOf(Cx16Target), - dim3 = listOf(false, true), - combine3 = ::makeDynamicCompilerTest - ) -} + bothCx16AndC64.forEach { + val (source, optimize) = it + val (displayNameC64, filepathC64) = prepareTestFiles(source, optimize, C64Target) + val (displayNameCx16, filepathCx16) = prepareTestFiles(source, optimize, Cx16Target) + test(displayNameC64) { + compileTheThing(filepathC64, optimize, C64Target).assertSuccess() + } + test(displayNameCx16) { + compileTheThing(filepathCx16, optimize, Cx16Target).assertSuccess() + } + } +}) diff --git a/compiler/test/TestCompilerOnImportsAndIncludes.kt b/compiler/test/TestCompilerOnImportsAndIncludes.kt index c2db07589..182b6a6dc 100644 --- a/compiler/test/TestCompilerOnImportsAndIncludes.kt +++ b/compiler/test/TestCompilerOnImportsAndIncludes.kt @@ -1,7 +1,6 @@ package prog8tests -import org.junit.jupiter.api.* -import org.junit.jupiter.api.DynamicTest.dynamicTest +import io.kotest.core.spec.style.FunSpec import prog8.ast.expressions.AddressOf import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.StringLiteralValue @@ -22,14 +21,11 @@ import kotlin.test.assertNotEquals * They are not really unit tests, but rather tests of the whole process, * from source file loading all the way through to running 64tass. */ -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestCompilerOnImportsAndIncludes { +class TestCompilerOnImportsAndIncludes: FunSpec({ - @Nested - inner class Import { + context("Import") { - @Test - fun testImportFromSameFolder() { + test("testImportFromSameFolder") { val filepath = assumeReadableFile(fixturesDir, "importFromSameFolder.p8") assumeReadableFile(fixturesDir, "foo_bar.p8") @@ -51,10 +47,8 @@ class TestCompilerOnImportsAndIncludes { } } - @Nested - inner class AsmInclude { - @Test - fun testAsmIncludeFromSameFolder() { + context("AsmInclude") { + test("testAsmIncludeFromSameFolder") { val filepath = assumeReadableFile(fixturesDir, "asmIncludeFromSameFolder.p8") assumeReadableFile(fixturesDir, "foo_bar.asm") @@ -79,10 +73,8 @@ class TestCompilerOnImportsAndIncludes { } } - @Nested - inner class Asmbinary { - @Test - fun testAsmbinaryDirectiveWithNonExistingFile() { + context("Asmbinary") { + test("testAsmbinaryDirectiveWithNonExistingFile") { val p8Path = assumeReadableFile(fixturesDir, "asmBinaryNonExisting.p8") assumeNotExists(fixturesDir, "i_do_not_exist.bin") @@ -90,8 +82,7 @@ class TestCompilerOnImportsAndIncludes { .assertFailure() } - @Test - fun testAsmbinaryDirectiveWithNonReadableFile() { + test("testAsmbinaryDirectiveWithNonReadableFile") { val p8Path = assumeReadableFile(fixturesDir, "asmBinaryNonReadable.p8") assumeDirectory(fixturesDir, "subFolder") @@ -99,31 +90,30 @@ class TestCompilerOnImportsAndIncludes { .assertFailure() } - @TestFactory - fun asmbinaryDirectiveWithExistingBinFile(): Iterable = - listOf( + val tests = listOf( Triple("same ", "asmBinaryFromSameFolder.p8", "do_nothing1.bin"), Triple("sub", "asmBinaryFromSubFolder.p8", "subFolder/do_nothing2.bin"), - ).map { - val (where, p8Str, binStr) = it - dynamicTest("%asmbinary from ${where}folder") { - val p8Path = assumeReadableFile(fixturesDir, p8Str) - // val binPath = assumeReadableFile(fixturesDir, binStr) - assertNotEquals( // the bug we're testing for (#54) was hidden if outputDir == workingDir - workingDir.normalize().toAbsolutePath(), - outputDir.normalize().toAbsolutePath(), - "sanity check: workingDir and outputDir should not be the same folder" + ) + + tests.forEach { + val (where, p8Str, binStr) = it + test("%asmbinary from ${where}folder") { + val p8Path = assumeReadableFile(fixturesDir, p8Str) + // val binPath = assumeReadableFile(fixturesDir, binStr) + assertNotEquals( // the bug we're testing for (#54) was hidden if outputDir == workingDir + workingDir.normalize().toAbsolutePath(), + outputDir.normalize().toAbsolutePath(), + "sanity check: workingDir and outputDir should not be the same folder" + ) + + compileFile(Cx16Target, false, p8Path.parent, p8Path.name, outputDir) + .assertSuccess( + "argument to assembler directive .binary " + + "should be relative to the generated .asm file (in output dir), " + + "NOT relative to .p8 neither current working dir" ) - - compileFile(Cx16Target, false, p8Path.parent, p8Path.name, outputDir) - .assertSuccess( - "argument to assembler directive .binary " + - "should be relative to the generated .asm file (in output dir), " + - "NOT relative to .p8 neither current working dir" - ) - } } - + } } -} +}) diff --git a/compiler/test/TestCompilerOnRanges.kt b/compiler/test/TestCompilerOnRanges.kt index fce4616d9..21f15a18c 100644 --- a/compiler/test/TestCompilerOnRanges.kt +++ b/compiler/test/TestCompilerOnRanges.kt @@ -1,20 +1,16 @@ package prog8tests -import org.junit.jupiter.api.DynamicTest.dynamicTest -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestFactory -import org.junit.jupiter.api.TestInstance +import io.kotest.core.spec.style.FunSpec import prog8.ast.base.DataType import prog8.ast.base.Position import prog8.ast.expressions.* import prog8.ast.statements.ForLoop -import prog8.ast.statements.Subroutine import prog8.ast.statements.VarDecl import prog8.compiler.target.C64Target import prog8.compiler.target.Cx16Target import prog8.compilerinterface.size import prog8.compilerinterface.toConstantIntegerRange -import prog8tests.ast.helpers.mapCombinations +import prog8tests.ast.helpers.cartesianProduct import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.assertFailure import prog8tests.helpers.assertSuccess @@ -28,11 +24,9 @@ import kotlin.test.assertEquals * They are not really unit tests, but rather tests of the whole process, * from source file loading all the way through to running 64tass. */ -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestCompilerOnRanges { +class TestCompilerOnRanges: FunSpec({ - @Test - fun testUByteArrayInitializerWithRange_char_to_char() { + test("testUByteArrayInitializerWithRange_char_to_char") { val platform = Cx16Target val result = compileText(platform, true, """ main { @@ -59,8 +53,7 @@ class TestCompilerOnRanges { assertEquals(expectedEnd - expectedStart + 1, rhsValues.last() - rhsValues.first() + 1, "rangeExpr.size()") } - @Test - fun testFloatArrayInitializerWithRange_char_to_char() { + test("testFloatArrayInitializerWithRange_char_to_char") { val platform = C64Target val result = compileText(platform, optimize = false, """ %option enable_floats @@ -88,46 +81,31 @@ class TestCompilerOnRanges { assertEquals(expectedEnd - expectedStart + 1, rhsValues.size, "rangeExpr.size()") } - fun Subroutine.decl(varName: String): VarDecl { - return statements.filterIsInstance() - .first { it.name == varName } - } - inline fun VarDecl.rhs() : T { - return value as T - } - inline fun ArrayLiteralValue.elements() : List { - return value.map { it as T } - } + context("floatArrayInitializerWithRange") { + val combos = cartesianProduct( + listOf("", "42", "41"), // sizeInDecl + listOf("%option enable_floats", ""), // optEnableFloats + listOf(Cx16Target, C64Target), // platform + listOf(false, true) // optimize + ) - fun assertEndpoints(expFirst: N, expLast: N, actual: Iterable, msg: String = ".first .. .last") { - val expectedStr = "$expFirst .. $expLast" - val actualStr = "${actual.first()} .. ${actual.last()}" - assertEquals(expectedStr, actualStr,".first .. .last") - } - - - @TestFactory - fun floatArrayInitializerWithRange() = mapCombinations( - dim1 = listOf("", "42", "41"), // sizeInDecl - dim2 = listOf("%option enable_floats", ""), // optEnableFloats - dim3 = listOf(Cx16Target, C64Target), // platform - dim4 = listOf(false, true), // optimize - combine4 = { sizeInDecl, optEnableFloats, platform, optimize -> + combos.forEach { + val (sizeInDecl, optEnableFloats, platform, optimize) = it val displayName = - "test failed for: " + when (sizeInDecl) { "" -> "no" "42" -> "correct" else -> "wrong" } + " array size given" + - ", " + (if (optEnableFloats == "") "without" else "with") + " %option enable_floats" + - ", ${platform.name}, optimize: $optimize" - dynamicTest(displayName) { + ", " + (if (optEnableFloats == "") "without" else "with") + " %option enable_floats" + + ", ${platform.name}, optimize: $optimize" + + test(displayName) { val result = compileText(platform, optimize, """ $optEnableFloats main { sub start() { - float[$sizeInDecl] cs = 1 to 42 ; values are computed at compile time + float[$sizeInDecl] cs = 1 to 42 ; values are computed at compile time cs[0] = 23 ; keep optimizer from removing it } } @@ -136,12 +114,12 @@ class TestCompilerOnRanges { result.assertSuccess() else result.assertFailure() + } } - ) + } - @Test - fun testForLoopWithRange_char_to_char() { + test("testForLoopWithRange_char_to_char") { val platform = Cx16Target val result = compileText(platform, optimize = true, """ main { @@ -171,8 +149,7 @@ class TestCompilerOnRanges { assertEquals(expectedEnd - expectedStart + 1, rangeExpr.size(), "rangeExpr.size()") } - @Test - fun testForLoopWithRange_bool_to_bool() { + test("testForLoopWithRange_bool_to_bool") { val platform = Cx16Target val result = compileText(platform, optimize = true, """ main { @@ -198,8 +175,7 @@ class TestCompilerOnRanges { assertEquals(1, intProgression?.last) } - @Test - fun testForLoopWithRange_ubyte_to_ubyte() { + test("testForLoopWithRange_ubyte_to_ubyte") { val platform = Cx16Target val result = compileText(platform, optimize = true, """ main { @@ -225,8 +201,7 @@ class TestCompilerOnRanges { assertEquals(9, intProgression?.last) } - @Test - fun testForLoopWithRange_str_downto_str() { + test("testForLoopWithRange_str_downto_str") { val errors = ErrorReporterForTests() compileText(Cx16Target, true, """ main { @@ -243,8 +218,7 @@ class TestCompilerOnRanges { assertContains(errors.errors[1], ".p8:5:44: range expression to value must be integer") } - @Test - fun testForLoopWithIterable_str() { + test("testForLoopWithIterable_str") { val result = compileText(Cx16Target, false, """ main { sub start() { @@ -266,8 +240,7 @@ class TestCompilerOnRanges { assertEquals(DataType.STR, iterable.inferType(program).getOr(DataType.UNDEFINED)) } - @Test - fun testRangeExprNumericSize() { + test("testRangeExprNumericSize") { val expr = RangeExpr( NumericLiteralValue.optimalInteger(10, Position.DUMMY), NumericLiteralValue.optimalInteger(20, Position.DUMMY), @@ -276,5 +249,4 @@ class TestCompilerOnRanges { assertEquals(6, expr.size()) expr.toConstantIntegerRange() } -} - +}) diff --git a/compiler/test/TestCompilerOptionLibdirs.kt b/compiler/test/TestCompilerOptionLibdirs.kt index ba6f552f2..141b956ef 100644 --- a/compiler/test/TestCompilerOptionLibdirs.kt +++ b/compiler/test/TestCompilerOptionLibdirs.kt @@ -1,9 +1,6 @@ package prog8tests -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance +import io.kotest.core.spec.style.FunSpec import prog8.compiler.compileProgram import prog8.compiler.target.Cx16Target import prog8tests.ast.helpers.assumeReadableFile @@ -22,13 +19,11 @@ import kotlin.io.path.writeText * They are not really unit tests, but rather tests of the whole process, * from source file loading all the way through to running 64tass. */ -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestCompilerOptionSourcedirs { +class TestCompilerOptionSourcedirs: FunSpec({ - private lateinit var tempFileInWorkingDir: Path + lateinit var tempFileInWorkingDir: Path - @BeforeAll - fun setUp() { + beforeSpec { tempFileInWorkingDir = createTempFile(directory = workingDir, prefix = "tmp_", suffix = ".p8") .also { it.writeText(""" main { @@ -38,12 +33,11 @@ class TestCompilerOptionSourcedirs { """)} } - @AfterAll - fun tearDown() { + afterSpec { tempFileInWorkingDir.deleteExisting() } - private fun compileFile(filePath: Path, sourceDirs: List) = + fun compileFile(filePath: Path, sourceDirs: List) = compileProgram( filepath = filePath, optimize = false, @@ -56,47 +50,41 @@ class TestCompilerOptionSourcedirs { outputDir ) - @Test - fun testAbsoluteFilePathInWorkingDir() { + test("testAbsoluteFilePathInWorkingDir") { val filepath = assumeReadableFile(tempFileInWorkingDir.absolute()) compileFile(filepath, listOf()) .assertSuccess() } - @Test - fun testFilePathInWorkingDirRelativeToWorkingDir() { + test("testFilePathInWorkingDirRelativeToWorkingDir") { val filepath = assumeReadableFile(workingDir.relativize(tempFileInWorkingDir.absolute())) compileFile(filepath, listOf()) .assertSuccess() } - @Test - fun testFilePathInWorkingDirRelativeTo1stInSourcedirs() { + test("testFilePathInWorkingDirRelativeTo1stInSourcedirs") { val filepath = assumeReadableFile(tempFileInWorkingDir) compileFile(filepath.fileName, listOf(workingDir.toString())) .assertSuccess() } - @Test - fun testAbsoluteFilePathOutsideWorkingDir() { + test("testAbsoluteFilePathOutsideWorkingDir") { val filepath = assumeReadableFile(fixturesDir, "simple_main.p8") compileFile(filepath.absolute(), listOf()) .assertSuccess() } - @Test - fun testFilePathOutsideWorkingDirRelativeToWorkingDir() { + test("testFilePathOutsideWorkingDirRelativeToWorkingDir") { val filepath = workingDir.relativize(assumeReadableFile(fixturesDir, "simple_main.p8").absolute()) compileFile(filepath, listOf()) .assertSuccess() } - @Test - fun testFilePathOutsideWorkingDirRelativeTo1stInSourcedirs() { + test("testFilePathOutsideWorkingDirRelativeTo1stInSourcedirs") { val filepath = assumeReadableFile(fixturesDir, "simple_main.p8") val sourcedirs = listOf("$fixturesDir") compileFile(filepath.fileName, sourcedirs) .assertSuccess() } -} +}) diff --git a/compiler/test/TestImportedModulesOrderAndOptions.kt b/compiler/test/TestImportedModulesOrderAndOptions.kt index 4b726157e..b6ebfc4e0 100644 --- a/compiler/test/TestImportedModulesOrderAndOptions.kt +++ b/compiler/test/TestImportedModulesOrderAndOptions.kt @@ -1,7 +1,6 @@ package prog8tests -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance +import io.kotest.core.spec.style.FunSpec import prog8.ast.internedStringsModuleName import prog8.compiler.determineCompilationOptions import prog8.compiler.parseImports @@ -15,11 +14,9 @@ import kotlin.test.assertEquals import kotlin.test.assertTrue -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestImportedModulesOrderAndOptions { +class TestImportedModulesOrderAndOptions: FunSpec({ - @Test - fun testImportedModuleOrderAndMainModuleCorrect() { + test("testImportedModuleOrderAndMainModuleCorrect") { val result = compileText(C64Target, false, """ %import textio %import floats @@ -47,8 +44,7 @@ main { assertTrue(result.program.toplevelModule.name.startsWith("on_the_fly_test")) } - @Test - fun testCompilationOptionsCorrectFromMain() { + test("testCompilationOptionsCorrectFromMain") { val result = compileText(C64Target, false, """ %import textio %import floats @@ -68,8 +64,7 @@ main { assertTrue(options.noSysInit) } - @Test - fun testModuleOrderAndCompilationOptionsCorrectWithJustImports() { + test("testModuleOrderAndCompilationOptionsCorrectWithJustImports") { val errors = ErrorReporterForTests() val sourceText = """ %import textio @@ -100,5 +95,4 @@ main { assertTrue(options.noSysInit) } - -} +}) diff --git a/compiler/test/TestMemory.kt b/compiler/test/TestMemory.kt index ac21d098f..dd26c2237 100644 --- a/compiler/test/TestMemory.kt +++ b/compiler/test/TestMemory.kt @@ -1,7 +1,7 @@ package prog8tests -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe import prog8.ast.Module import prog8.ast.Program import prog8.ast.base.DataType @@ -18,74 +18,53 @@ import prog8.parser.SourceCode import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyMemsizer import prog8tests.helpers.DummyStringEncoder -import kotlin.test.assertFalse -import kotlin.test.assertTrue -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestMemory { +class TestMemory: FunSpec({ - @Test - fun testInValidRamC64_memory_addresses() { + test("testInValidRamC64_memory_addresses") { var memexpr = NumericLiteralValue.optimalInteger(0x0000, Position.DUMMY) var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - assertTrue(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe true memexpr = NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - assertTrue(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe true memexpr = NumericLiteralValue.optimalInteger(0x9fff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - assertTrue(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe true memexpr = NumericLiteralValue.optimalInteger(0xc000, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - assertTrue(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe true memexpr = NumericLiteralValue.optimalInteger(0xcfff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - assertTrue(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe true } - @Test - fun testNotInValidRamC64_memory_addresses() { + test("testNotInValidRamC64_memory_addresses") { var memexpr = NumericLiteralValue.optimalInteger(0xa000, Position.DUMMY) var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - assertFalse(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe false memexpr = NumericLiteralValue.optimalInteger(0xafff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - assertFalse(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe false memexpr = NumericLiteralValue.optimalInteger(0xd000, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - assertFalse(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe false memexpr = NumericLiteralValue.optimalInteger(0xffff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - assertFalse(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe false } - @Test - fun testInValidRamC64_memory_identifiers() { - val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) - var target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.VAR) - - assertTrue(target.isInRegularRAMof(C64Target.machine)) - target = createTestProgramForMemoryRefViaVar(program, 0xd020, VarDeclType.VAR) - assertFalse(target.isInRegularRAMof(C64Target.machine)) - target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.CONST) - assertTrue(target.isInRegularRAMof(C64Target.machine)) - target = createTestProgramForMemoryRefViaVar(program, 0xd020, VarDeclType.CONST) - assertFalse(target.isInRegularRAMof(C64Target.machine)) - target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.MEMORY) - assertFalse(target.isInRegularRAMof(C64Target.machine)) - } - - private fun createTestProgramForMemoryRefViaVar(program: Program, address: Int, vartype: VarDeclType): AssignTarget { + fun createTestProgramForMemoryRefViaVar(program: Program, address: Int, vartype: VarDeclType): AssignTarget { val decl = VarDecl(vartype, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY) val memexpr = IdentifierReference(listOf("address"), Position.DUMMY) val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) @@ -95,16 +74,28 @@ class TestMemory { module.linkIntoProgram(program) return target } + test("testInValidRamC64_memory_identifiers") { + val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) + var target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.VAR) - @Test - fun testInValidRamC64_memory_expression() { - val memexpr = PrefixExpression("+", NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY), Position.DUMMY) - val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - assertFalse(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe true + target = createTestProgramForMemoryRefViaVar(program, 0xd020, VarDeclType.VAR) + target.isInRegularRAMof(C64Target.machine) shouldBe false + target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.CONST) + target.isInRegularRAMof(C64Target.machine) shouldBe true + target = createTestProgramForMemoryRefViaVar(program, 0xd020, VarDeclType.CONST) + target.isInRegularRAMof(C64Target.machine) shouldBe false + target = createTestProgramForMemoryRefViaVar(program, 0x1000, VarDeclType.MEMORY) + target.isInRegularRAMof(C64Target.machine) shouldBe false } - @Test - fun testInValidRamC64_variable() { + test("testInValidRamC64_memory_expression") { + val memexpr = PrefixExpression("+", NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY), Position.DUMMY) + val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) + target.isInRegularRAMof(C64Target.machine) shouldBe false + } + + test("testInValidRamC64_variable") { val decl = VarDecl(VarDeclType.VAR, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", null, false, false, false, Position.DUMMY) val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) @@ -113,11 +104,10 @@ class TestMemory { val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) module.linkIntoProgram(program) - assertTrue(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe true } - @Test - fun testInValidRamC64_memmap_variable() { + test("testInValidRamC64_memmap_variable") { val address = 0x1000 val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY) val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) @@ -127,11 +117,10 @@ class TestMemory { val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) module.linkIntoProgram(program) - assertTrue(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe true } - @Test - fun testNotInValidRamC64_memmap_variable() { + test("testNotInValidRamC64_memmap_variable") { val address = 0xd020 val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY) val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) @@ -141,11 +130,10 @@ class TestMemory { val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) module.linkIntoProgram(program) - assertFalse(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe false } - @Test - fun testInValidRamC64_array() { + test("testInValidRamC64_array") { val decl = VarDecl(VarDeclType.VAR, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", null, false, false, false, Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) @@ -155,11 +143,10 @@ class TestMemory { val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) module.linkIntoProgram(program) - assertTrue(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe true } - @Test - fun testInValidRamC64_array_memmapped() { + test("testInValidRamC64_array_memmapped") { val address = 0x1000 val decl = VarDecl(VarDeclType.MEMORY, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) @@ -170,11 +157,10 @@ class TestMemory { val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) module.linkIntoProgram(program) - assertTrue(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe true } - @Test - fun testNotValidRamC64_array_memmapped() { + test("testNotValidRamC64_array_memmapped") { val address = 0xe000 val decl = VarDecl(VarDeclType.MEMORY, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) @@ -185,6 +171,6 @@ class TestMemory { val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) module.linkIntoProgram(program) - assertFalse(target.isInRegularRAMof(C64Target.machine)) + target.isInRegularRAMof(C64Target.machine) shouldBe false } -} +}) diff --git a/compiler/test/TestNumbers.kt b/compiler/test/TestNumbers.kt index 71c44d29e..df125939b 100644 --- a/compiler/test/TestNumbers.kt +++ b/compiler/test/TestNumbers.kt @@ -1,116 +1,110 @@ package prog8tests -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.closeTo -import org.hamcrest.Matchers.equalTo -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.doubles.plusOrMinus +import io.kotest.matchers.shouldBe import prog8.ast.toHex import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_NEGATIVE import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_POSITIVE import prog8.compiler.target.c64.C64MachineDefinition.Mflpt5 import prog8.compilerinterface.InternalCompilerException -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestNumbers { - @Test - fun testToHex() { - assertEquals("0", 0.toHex()) - assertEquals("1", 1.toHex()) - assertEquals("1", 1.234.toHex()) - assertEquals("10", 10.toHex()) - assertEquals("10", 10.99.toHex()) - assertEquals("15", 15.toHex()) - assertEquals("\$10", 16.toHex()) - assertEquals("\$ff", 255.toHex()) - assertEquals("\$0100", 256.toHex()) - assertEquals("\$4e5c", 20060.toHex()) - assertEquals("\$c382", 50050.toHex()) - assertEquals("\$ffff", 65535.toHex()) - assertEquals("\$ffff", 65535L.toHex()) - assertEquals("0", 0.toHex()) - assertEquals("-1", (-1).toHex()) - assertEquals("-1", (-1.234).toHex()) - assertEquals("-10", (-10).toHex()) - assertEquals("-10", (-10.99).toHex()) - assertEquals("-15", (-15).toHex()) - assertEquals("-\$10", (-16).toHex()) - assertEquals("-\$ff", (-255).toHex()) - assertEquals("-\$0100", (-256).toHex()) - assertEquals("-\$4e5c", (-20060).toHex()) - assertEquals("-\$c382", (-50050).toHex()) - assertEquals("-\$ffff", (-65535).toHex()) - assertEquals("-\$ffff", (-65535L).toHex()) - assertFailsWith { 65536.toHex() } - assertFailsWith { 65536L.toHex() } + +class TestNumbers: FunSpec({ + test("testToHex") { + 0.toHex() shouldBe "0" + 1.toHex() shouldBe "1" + 1.234.toHex() shouldBe "1" + 10.toHex() shouldBe "10" + 10.99.toHex() shouldBe "10" + 15.toHex() shouldBe "15" + 16.toHex() shouldBe "\$10" + 255.toHex() shouldBe "\$ff" + 256.toHex() shouldBe "\$0100" + 20060.toHex() shouldBe "\$4e5c" + 50050.toHex() shouldBe "\$c382" + 65535.toHex() shouldBe "\$ffff" + 65535L.toHex() shouldBe "\$ffff" + 0.toHex() shouldBe "0" + (-1).toHex() shouldBe "-1" + (-1.234).toHex() shouldBe "-1" + (-10).toHex() shouldBe "-10" + (-10.99).toHex() shouldBe "-10" + (-15).toHex() shouldBe "-15" + (-16).toHex() shouldBe "-\$10" + (-255).toHex() shouldBe "-\$ff" + (-256).toHex() shouldBe "-\$0100" + (-20060).toHex() shouldBe "-\$4e5c" + (-50050).toHex() shouldBe "-\$c382" + (-65535).toHex() shouldBe "-\$ffff" + (-65535L).toHex() shouldBe "-\$ffff" + shouldThrow { 65536.toHex() } + shouldThrow { 65536L.toHex() } } - @Test - fun testFloatToMflpt5() { - assertThat(Mflpt5.fromNumber(0), equalTo(Mflpt5(0x00, 0x00, 0x00, 0x00, 0x00))) - assertThat(Mflpt5.fromNumber(3.141592653), equalTo(Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA1))) - assertThat(Mflpt5.fromNumber(3.141592653589793), equalTo(Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA2))) - assertThat(Mflpt5.fromNumber(32768), equalTo(Mflpt5(0x90, 0x00, 0x00, 0x00, 0x00))) - assertThat(Mflpt5.fromNumber(-32768), equalTo(Mflpt5(0x90, 0x80, 0x00, 0x00, 0x00))) - assertThat(Mflpt5.fromNumber(1), equalTo(Mflpt5(0x81, 0x00, 0x00, 0x00, 0x00))) - assertThat(Mflpt5.fromNumber(0.7071067812), equalTo(Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x34))) - assertThat(Mflpt5.fromNumber(0.7071067811865476), equalTo(Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x33))) - assertThat(Mflpt5.fromNumber(1.4142135624), equalTo(Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x34))) - assertThat(Mflpt5.fromNumber(1.4142135623730951), equalTo(Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x33))) - assertThat(Mflpt5.fromNumber(-.5), equalTo(Mflpt5(0x80, 0x80, 0x00, 0x00, 0x00))) - assertThat(Mflpt5.fromNumber(0.69314718061), equalTo(Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF8))) - assertThat(Mflpt5.fromNumber(0.6931471805599453), equalTo(Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF7))) - assertThat(Mflpt5.fromNumber(10), equalTo(Mflpt5(0x84, 0x20, 0x00, 0x00, 0x00))) - assertThat(Mflpt5.fromNumber(1000000000), equalTo(Mflpt5(0x9E, 0x6E, 0x6B, 0x28, 0x00))) - assertThat(Mflpt5.fromNumber(.5), equalTo(Mflpt5(0x80, 0x00, 0x00, 0x00, 0x00))) - assertThat(Mflpt5.fromNumber(1.4426950408889634), equalTo(Mflpt5(0x81, 0x38, 0xAA, 0x3B, 0x29))) - assertThat(Mflpt5.fromNumber(1.5707963267948966), equalTo(Mflpt5(0x81, 0x49, 0x0F, 0xDA, 0xA2))) - assertThat(Mflpt5.fromNumber(6.283185307179586), equalTo(Mflpt5(0x83, 0x49, 0x0F, 0xDA, 0xA2))) - assertThat(Mflpt5.fromNumber(.25), equalTo(Mflpt5(0x7F, 0x00, 0x00, 0x00, 0x00))) - assertThat(Mflpt5.fromNumber(123.45678e22), equalTo(Mflpt5(0xd1, 0x02, 0xb7, 0x06, 0xfb))) - assertThat(Mflpt5.fromNumber(-123.45678e-22), equalTo(Mflpt5(0x3e, 0xe9, 0x34, 0x09, 0x1b))) + test("testFloatToMflpt5") { + Mflpt5.fromNumber(0) shouldBe Mflpt5(0x00, 0x00, 0x00, 0x00, 0x00) + Mflpt5.fromNumber(3.141592653) shouldBe Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA1) + Mflpt5.fromNumber(3.141592653589793) shouldBe Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA2) + Mflpt5.fromNumber(32768) shouldBe Mflpt5(0x90, 0x00, 0x00, 0x00, 0x00) + Mflpt5.fromNumber(-32768) shouldBe Mflpt5(0x90, 0x80, 0x00, 0x00, 0x00) + Mflpt5.fromNumber(1) shouldBe Mflpt5(0x81, 0x00, 0x00, 0x00, 0x00) + Mflpt5.fromNumber(0.7071067812) shouldBe Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x34) + Mflpt5.fromNumber(0.7071067811865476) shouldBe Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x33) + Mflpt5.fromNumber(1.4142135624) shouldBe Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x34) + Mflpt5.fromNumber(1.4142135623730951) shouldBe Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x33) + Mflpt5.fromNumber(-.5) shouldBe Mflpt5(0x80, 0x80, 0x00, 0x00, 0x00) + Mflpt5.fromNumber(0.69314718061) shouldBe Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF8) + Mflpt5.fromNumber(0.6931471805599453) shouldBe Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF7) + Mflpt5.fromNumber(10) shouldBe Mflpt5(0x84, 0x20, 0x00, 0x00, 0x00) + Mflpt5.fromNumber(1000000000) shouldBe Mflpt5(0x9E, 0x6E, 0x6B, 0x28, 0x00) + Mflpt5.fromNumber(.5) shouldBe Mflpt5(0x80, 0x00, 0x00, 0x00, 0x00) + Mflpt5.fromNumber(1.4426950408889634) shouldBe Mflpt5(0x81, 0x38, 0xAA, 0x3B, 0x29) + Mflpt5.fromNumber(1.5707963267948966) shouldBe Mflpt5(0x81, 0x49, 0x0F, 0xDA, 0xA2) + Mflpt5.fromNumber(6.283185307179586) shouldBe Mflpt5(0x83, 0x49, 0x0F, 0xDA, 0xA2) + Mflpt5.fromNumber(.25) shouldBe Mflpt5(0x7F, 0x00, 0x00, 0x00, 0x00) + Mflpt5.fromNumber(123.45678e22) shouldBe Mflpt5(0xd1, 0x02, 0xb7, 0x06, 0xfb) + Mflpt5.fromNumber(-123.45678e-22) shouldBe Mflpt5(0x3e, 0xe9, 0x34, 0x09, 0x1b) } - @Test - fun testFloatRange() { - assertThat(Mflpt5.fromNumber(FLOAT_MAX_POSITIVE), equalTo(Mflpt5(0xff, 0x7f, 0xff, 0xff, 0xff))) - assertThat(Mflpt5.fromNumber(FLOAT_MAX_NEGATIVE), equalTo(Mflpt5(0xff, 0xff, 0xff, 0xff, 0xff))) - assertThat(Mflpt5.fromNumber(1.7e-38), equalTo(Mflpt5(0x03, 0x39, 0x1d, 0x15, 0x63))) - assertThat(Mflpt5.fromNumber(1.7e-39), equalTo(Mflpt5(0x00, 0x00, 0x00, 0x00, 0x00))) - assertThat(Mflpt5.fromNumber(-1.7e-38), equalTo(Mflpt5(0x03, 0xb9, 0x1d, 0x15, 0x63))) - assertThat(Mflpt5.fromNumber(-1.7e-39), equalTo(Mflpt5(0x00, 0x00, 0x00, 0x00, 0x00))) - assertFailsWith { Mflpt5.fromNumber(1.7014118346e+38) } - assertFailsWith { Mflpt5.fromNumber(-1.7014118346e+38) } - assertFailsWith { Mflpt5.fromNumber(1.7014118347e+38) } - assertFailsWith { Mflpt5.fromNumber(-1.7014118347e+38) } + test("testFloatRange") { + Mflpt5.fromNumber(FLOAT_MAX_POSITIVE) shouldBe Mflpt5(0xff, 0x7f, 0xff, 0xff, 0xff) + Mflpt5.fromNumber(FLOAT_MAX_NEGATIVE) shouldBe Mflpt5(0xff, 0xff, 0xff, 0xff, 0xff) + Mflpt5.fromNumber(1.7e-38) shouldBe Mflpt5(0x03, 0x39, 0x1d, 0x15, 0x63) + Mflpt5.fromNumber(1.7e-39) shouldBe Mflpt5(0x00, 0x00, 0x00, 0x00, 0x00) + Mflpt5.fromNumber(-1.7e-38) shouldBe Mflpt5(0x03, 0xb9, 0x1d, 0x15, 0x63) + Mflpt5.fromNumber(-1.7e-39) shouldBe Mflpt5(0x00, 0x00, 0x00, 0x00, 0x00) + shouldThrow { Mflpt5.fromNumber(1.7014118346e+38) } + shouldThrow { Mflpt5.fromNumber(-1.7014118346e+38) } + shouldThrow { Mflpt5.fromNumber(1.7014118347e+38) } + shouldThrow { Mflpt5.fromNumber(-1.7014118347e+38) } } - @Test - fun testMflpt5ToFloat() { + test("testMflpt5ToFloat") { val epsilon=0.000000001 - assertThat(Mflpt5(0x00, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(0.0)) - assertThat(Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA1).toDouble(), closeTo(3.141592653, epsilon)) - assertThat(Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(3.141592653589793, epsilon)) - assertThat(Mflpt5(0x90, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(32768.0)) - assertThat(Mflpt5(0x90, 0x80, 0x00, 0x00, 0x00).toDouble(), equalTo(-32768.0)) - assertThat(Mflpt5(0x81, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(1.0)) - assertThat(Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x34).toDouble(), closeTo(0.7071067812, epsilon)) - assertThat(Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x33).toDouble(), closeTo(0.7071067811865476, epsilon)) - assertThat(Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x34).toDouble(), closeTo(1.4142135624, epsilon)) - assertThat(Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x33).toDouble(), closeTo(1.4142135623730951, epsilon)) - assertThat(Mflpt5(0x80, 0x80, 0x00, 0x00, 0x00).toDouble(), equalTo(-.5)) - assertThat(Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF8).toDouble(), closeTo(0.69314718061, epsilon)) - assertThat(Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF7).toDouble(), closeTo(0.6931471805599453, epsilon)) - assertThat(Mflpt5(0x84, 0x20, 0x00, 0x00, 0x00).toDouble(), equalTo(10.0)) - assertThat(Mflpt5(0x9E, 0x6E, 0x6B, 0x28, 0x00).toDouble(), equalTo(1000000000.0)) - assertThat(Mflpt5(0x80, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(.5)) - assertThat(Mflpt5(0x81, 0x38, 0xAA, 0x3B, 0x29).toDouble(), closeTo(1.4426950408889634, epsilon)) - assertThat(Mflpt5(0x81, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(1.5707963267948966, epsilon)) - assertThat(Mflpt5(0x83, 0x49, 0x0F, 0xDA, 0xA2).toDouble(), closeTo(6.283185307179586, epsilon)) - assertThat(Mflpt5(0x7F, 0x00, 0x00, 0x00, 0x00).toDouble(), equalTo(.25)) - assertThat(Mflpt5(0xd1, 0x02, 0xb7, 0x06, 0xfb).toDouble(), closeTo(123.45678e22, 1.0e15)) - assertThat(Mflpt5(0x3e, 0xe9, 0x34, 0x09, 0x1b).toDouble(), closeTo(-123.45678e-22, epsilon)) + + Mflpt5(0x00, 0x00, 0x00, 0x00, 0x00).toDouble() shouldBe 0.0 + Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA1).toDouble() shouldBe(3.141592653 plusOrMinus epsilon) + Mflpt5(0x82, 0x49, 0x0F, 0xDA, 0xA2).toDouble() shouldBe(3.141592653589793 plusOrMinus epsilon) + Mflpt5(0x90, 0x00, 0x00, 0x00, 0x00).toDouble() shouldBe 32768.0 + Mflpt5(0x90, 0x80, 0x00, 0x00, 0x00).toDouble() shouldBe -32768.0 + Mflpt5(0x81, 0x00, 0x00, 0x00, 0x00).toDouble() shouldBe 1.0 + Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x34).toDouble() shouldBe(0.7071067812 plusOrMinus epsilon) + Mflpt5(0x80, 0x35, 0x04, 0xF3, 0x33).toDouble() shouldBe(0.7071067811865476 plusOrMinus epsilon) + Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x34).toDouble() shouldBe(1.4142135624 plusOrMinus epsilon) + Mflpt5(0x81, 0x35, 0x04, 0xF3, 0x33).toDouble() shouldBe(1.4142135623730951 plusOrMinus epsilon) + Mflpt5(0x80, 0x80, 0x00, 0x00, 0x00).toDouble() shouldBe -.5 + Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF8).toDouble() shouldBe(0.69314718061 plusOrMinus epsilon) + Mflpt5(0x80, 0x31, 0x72, 0x17, 0xF7).toDouble() shouldBe(0.6931471805599453 plusOrMinus epsilon) + Mflpt5(0x84, 0x20, 0x00, 0x00, 0x00).toDouble() shouldBe 10.0 + Mflpt5(0x9E, 0x6E, 0x6B, 0x28, 0x00).toDouble() shouldBe 1000000000.0 + Mflpt5(0x80, 0x00, 0x00, 0x00, 0x00).toDouble() shouldBe .5 + Mflpt5(0x81, 0x38, 0xAA, 0x3B, 0x29).toDouble() shouldBe(1.4426950408889634 plusOrMinus epsilon) + Mflpt5(0x81, 0x49, 0x0F, 0xDA, 0xA2).toDouble() shouldBe(1.5707963267948966 plusOrMinus epsilon) + Mflpt5(0x83, 0x49, 0x0F, 0xDA, 0xA2).toDouble() shouldBe(6.283185307179586 plusOrMinus epsilon) + Mflpt5(0x7F, 0x00, 0x00, 0x00, 0x00).toDouble() shouldBe .25 + Mflpt5(0xd1, 0x02, 0xb7, 0x06, 0xfb).toDouble() shouldBe(123.45678e22 plusOrMinus 1.0e15) + Mflpt5(0x3e, 0xe9, 0x34, 0x09, 0x1b).toDouble() shouldBe(-123.45678e-22 plusOrMinus epsilon) } -} +}) diff --git a/compiler/test/TestNumericLiteralValue.kt b/compiler/test/TestNumericLiteralValue.kt index e34cc608a..901e3ff9a 100644 --- a/compiler/test/TestNumericLiteralValue.kt +++ b/compiler/test/TestNumericLiteralValue.kt @@ -1,7 +1,6 @@ package prog8tests -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance +import io.kotest.core.spec.style.FunSpec import prog8.ast.base.DataType import prog8.ast.base.Position import prog8.ast.expressions.ArrayLiteralValue @@ -13,17 +12,15 @@ import kotlin.test.assertFalse import kotlin.test.assertNotEquals import kotlin.test.assertTrue -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestNumericLiteralValue { +class TestNumericLiteralValue: FunSpec({ - private fun sameValueAndType(lv1: NumericLiteralValue, lv2: NumericLiteralValue): Boolean { + fun sameValueAndType(lv1: NumericLiteralValue, lv2: NumericLiteralValue): Boolean { return lv1.type==lv2.type && lv1==lv2 } - private val dummyPos = Position("test", 0, 0, 0) + val dummyPos = Position("test", 0, 0, 0) - @Test - fun testIdentity() { + test("testIdentity") { val v = NumericLiteralValue(DataType.UWORD, 12345, dummyPos) assertEquals(v, v) assertFalse(v != v) @@ -35,8 +32,7 @@ class TestNumericLiteralValue { assertTrue(sameValueAndType(NumericLiteralValue(DataType.UWORD, 12345, dummyPos), NumericLiteralValue(DataType.UWORD, 12345, dummyPos))) } - @Test - fun testEqualsAndNotEquals() { + test("testEqualsAndNotEquals") { assertEquals(NumericLiteralValue(DataType.UBYTE, 100, dummyPos), NumericLiteralValue(DataType.UBYTE, 100, dummyPos)) assertEquals(NumericLiteralValue(DataType.UBYTE, 100, dummyPos), NumericLiteralValue(DataType.UWORD, 100, dummyPos)) assertEquals(NumericLiteralValue(DataType.UBYTE, 100, dummyPos), NumericLiteralValue(DataType.FLOAT, 100.0, dummyPos)) @@ -80,8 +76,7 @@ class TestNumericLiteralValue { } - @Test - fun testEqualsRef() { + test("testEqualsRef") { assertEquals(StringLiteralValue("hello", false, dummyPos), StringLiteralValue("hello", false, dummyPos)) assertNotEquals(StringLiteralValue("hello", false, dummyPos), StringLiteralValue("bye", false, dummyPos)) assertEquals(StringLiteralValue("hello", true, dummyPos), StringLiteralValue("hello", true, dummyPos)) @@ -102,8 +97,7 @@ class TestNumericLiteralValue { assertNotEquals(lv1, lv3) } - @Test - fun testGreaterThan(){ + test("testGreaterThan") { assertTrue(NumericLiteralValue(DataType.UBYTE, 100, dummyPos) > NumericLiteralValue(DataType.UBYTE, 99, dummyPos)) assertTrue(NumericLiteralValue(DataType.UWORD, 254, dummyPos) > NumericLiteralValue(DataType.UWORD, 253, dummyPos)) assertTrue(NumericLiteralValue(DataType.FLOAT, 100.0, dummyPos) > NumericLiteralValue(DataType.FLOAT, 99.9, dummyPos)) @@ -121,8 +115,7 @@ class TestNumericLiteralValue { assertFalse(NumericLiteralValue(DataType.FLOAT, 100.0, dummyPos) >= NumericLiteralValue(DataType.FLOAT, 100.1, dummyPos)) } - @Test - fun testLessThan() { + test("testLessThan") { assertTrue(NumericLiteralValue(DataType.UBYTE, 100, dummyPos) < NumericLiteralValue(DataType.UBYTE, 101, dummyPos)) assertTrue(NumericLiteralValue(DataType.UWORD, 254, dummyPos) < NumericLiteralValue(DataType.UWORD, 255, dummyPos)) assertTrue(NumericLiteralValue(DataType.FLOAT, 100.0, dummyPos) < NumericLiteralValue(DataType.FLOAT, 100.1, dummyPos)) @@ -140,5 +133,4 @@ class TestNumericLiteralValue { assertFalse(NumericLiteralValue(DataType.FLOAT, 100.0, dummyPos) <= NumericLiteralValue(DataType.FLOAT, 99.9, dummyPos)) } -} - +}) diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index e190d6da2..ca6571461 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -1,7 +1,6 @@ package prog8tests -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance +import io.kotest.core.spec.style.FunSpec import prog8.ast.Program import prog8.ast.base.DataType import prog8.ast.base.ParentSentinel @@ -17,10 +16,8 @@ import prog8tests.helpers.assertSuccess import prog8tests.helpers.compileText import kotlin.test.* -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestOptimization { - @Test - fun testRemoveEmptySubroutineExceptStart() { +class TestOptimization: FunSpec({ + test("testRemoveEmptySubroutineExceptStart") { val sourcecode = """ main { sub start() { @@ -39,8 +36,7 @@ class TestOptimization { assertTrue(startSub.statements.single() is Return, "compiler has inserted return in empty subroutines") } - @Test - fun testDontRemoveEmptySubroutineIfItsReferenced() { + test("testDontRemoveEmptySubroutineIfItsReferenced") { val sourcecode = """ main { sub start() { @@ -63,9 +59,7 @@ class TestOptimization { assertTrue(emptySub.statements.single() is Return, "compiler has inserted return in empty subroutines") } - @Test - fun testGeneratedConstvalueInheritsProperParentLinkage() - { + test("testGeneratedConstvalueInheritsProperParentLinkage") { val number = NumericLiteralValue(DataType.UBYTE, 11, Position.DUMMY) val tc = TypecastExpression(number, DataType.BYTE, false, Position.DUMMY) val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) @@ -80,8 +74,7 @@ class TestOptimization { assertSame(tc, constvalue.parent) } - @Test - fun testConstantFoldedAndSilentlyTypecastedForInitializerValues() { + test("testConstantFoldedAndSilentlyTypecastedForInitializerValues") { val sourcecode = """ main { sub start() { @@ -120,4 +113,4 @@ class TestOptimization { assertEquals(DataType.UBYTE, (initY2.value as NumericLiteralValue).type) assertEquals(11.0, (initY2.value as NumericLiteralValue).number.toDouble()) } -} +}) diff --git a/compiler/test/TestPetscii.kt b/compiler/test/TestPetscii.kt index d9bc7f58c..de0ac6e75 100644 --- a/compiler/test/TestPetscii.kt +++ b/compiler/test/TestPetscii.kt @@ -1,32 +1,27 @@ package prog8tests import com.github.michaelbull.result.Ok -import com.github.michaelbull.result.expect import com.github.michaelbull.result.expectError import com.github.michaelbull.result.getOrElse +import io.kotest.core.spec.style.FunSpec import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance import prog8.compiler.target.cbm.Petscii import java.io.CharConversionException import kotlin.test.assertEquals import kotlin.test.assertFailsWith -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestPetscii { +class TestPetscii: FunSpec({ - @Test - fun testZero() { + test("testZero") { assertThat(Petscii.encodePetscii("\u0000", true), equalTo(Ok(listOf(0)))) assertThat(Petscii.encodePetscii("\u0000", false), equalTo(Ok(listOf(0)))) assertThat(Petscii.decodePetscii(listOf(0), true), equalTo("\u0000")) assertThat(Petscii.decodePetscii(listOf(0), false), equalTo("\u0000")) } - @Test - fun testLowercase() { + test("testLowercase") { assertThat(Petscii.encodePetscii("hello WORLD 123 @!£", true), equalTo( Ok(listOf(72, 69, 76, 76, 79, 32, 0xd7, 0xcf, 0xd2, 0xcc, 0xc4, 32, 49, 50, 51, 32, 64, 33, 0x5c)))) assertThat(Petscii.encodePetscii("\uf11a", true), equalTo(Ok(listOf(0x12)))) // reverse vid @@ -37,8 +32,7 @@ class TestPetscii { assertThat(Petscii.decodePetscii(listOf(72, 0xd7, 0x5c, 0xfa, 0x12), true), equalTo("hW£✓\uF11A")) } - @Test - fun testUppercase() { + test("testUppercase") { assertThat(Petscii.encodePetscii("HELLO 123 @!£"), equalTo( Ok(listOf(72, 69, 76, 76, 79, 32, 49, 50, 51, 32, 64, 33, 0x5c)))) assertThat(Petscii.encodePetscii("\uf11a"), equalTo(Ok(listOf(0x12)))) // reverse vid @@ -49,8 +43,7 @@ class TestPetscii { assertThat(Petscii.decodePetscii(listOf(72, 0x5c, 0xd3, 0xff)), equalTo("H£♥π")) } - @Test - fun testScreencodeLowercase() { + test("testScreencodeLowercase") { assertThat(Petscii.encodeScreencode("hello WORLD 123 @!£", true), equalTo( Ok(listOf(0x08, 0x05, 0x0c, 0x0c, 0x0f, 0x20, 0x57, 0x4f, 0x52, 0x4c, 0x44, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c)) )) @@ -61,8 +54,7 @@ class TestPetscii { assertThat(Petscii.decodeScreencode(listOf(0x08, 0x57, 0x1c, 0x7a), true), equalTo("hW£✓")) } - @Test - fun testScreencodeUppercase() { + test("testScreencodeUppercase") { assertThat(Petscii.encodeScreencode("WORLD 123 @!£"), equalTo( Ok(listOf(0x17, 0x0f, 0x12, 0x0c, 0x04, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c)))) assertThat(Petscii.encodeScreencode("♥"), equalTo(Ok(listOf(0x53)))) @@ -74,8 +66,7 @@ class TestPetscii { assertThat(Petscii.decodeScreencode(listOf(0x17, 0x1c, 0x53, 0x5e)), equalTo("W£♥π")) } - @Test - fun testErrorCases() { + test("testErrorCases") { Petscii.encodePetscii("~", true).expectError { "shouldn't be able to encode tilde" } Petscii.encodePetscii("~", false).expectError { "shouldn't be able to encode tilde" } Petscii.encodeScreencode("~", true).expectError { "shouldn't be able to encode tilde" } @@ -98,9 +89,7 @@ class TestPetscii { Petscii.petscii2scr(256, false).expectError { "256 should error" } } - @Test - fun testSpecialReplacements() - { + test("testSpecialReplacements") { fun encodeP(c: Char, lower: Boolean) = Petscii.encodePetscii(c.toString(), lower).getOrElse { throw it }.single() fun encodeS(c: Char, lower: Boolean) = Petscii.encodeScreencode(c.toString(), lower).getOrElse { throw it }.single() @@ -135,8 +124,7 @@ class TestPetscii { assertEquals(77, encodeS('\\', true)) } - @Test - fun testBoxDrawingCharsEncoding() { + test("testBoxDrawingCharsEncoding") { fun encodeP(c: Char, lower: Boolean) = Petscii.encodePetscii(c.toString(), lower).getOrElse { throw it }.single() fun encodeS(c: Char, lower: Boolean) = Petscii.encodeScreencode(c.toString(), lower).getOrElse { throw it }.single() @@ -174,8 +162,7 @@ class TestPetscii { assertEquals(93, encodeS('│', true)) } - @Test - fun testBoxDrawingCharsDecoding() { + test("testBoxDrawingCharsDecoding") { // ─ 0xC0 -> BOX DRAWINGS LIGHT HORIZONTAL assertEquals('\uf13b', Petscii.decodePetscii(listOf(195), false).single(), "BOX DRAWINGS LIGHT HORIZONTAL ONE EIGHTH UP (CUS)") assertEquals('C', Petscii.decodePetscii(listOf(195), true).single()) @@ -197,4 +184,4 @@ class TestPetscii { assertEquals('B', Petscii.decodeScreencode(listOf(66), true).single()) } -} +}) diff --git a/compiler/test/TestScoping.kt b/compiler/test/TestScoping.kt index 05bf26906..6950fef29 100644 --- a/compiler/test/TestScoping.kt +++ b/compiler/test/TestScoping.kt @@ -1,7 +1,6 @@ package prog8tests -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance +import io.kotest.core.spec.style.FunSpec import prog8.ast.GlobalNamespace import prog8.ast.base.ParentSentinel import prog8.ast.expressions.NumericLiteralValue @@ -12,11 +11,9 @@ import prog8tests.helpers.compileText import kotlin.test.* -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestScoping { +class TestScoping: FunSpec({ - @Test - fun testModulesParentIsGlobalNamespace() { + test("testModulesParentIsGlobalNamespace") { val src = """ main { sub start() { @@ -31,8 +28,7 @@ class TestScoping { assertIs(module.parent.parent) } - @Test - fun testAnonScopeVarsMovedIntoSubroutineScope() { + test("testAnonScopeVarsMovedIntoSubroutineScope") { val src = """ main { sub start() { @@ -60,8 +56,7 @@ class TestScoping { assertTrue(repeatbody.statements[1] is PostIncrDecr) } - @Test - fun testLabelsWithAnonScopes() { + test("testLabelsWithAnonScopes") { val src = """ main { sub start() { @@ -123,4 +118,4 @@ class TestScoping { assertEquals(1, labels.size, "only one label in subroutine scope") } -} +}) diff --git a/compiler/test/TestSubroutines.kt b/compiler/test/TestSubroutines.kt index 33f38d737..76c3fc3c3 100644 --- a/compiler/test/TestSubroutines.kt +++ b/compiler/test/TestSubroutines.kt @@ -1,8 +1,6 @@ package prog8tests -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance +import io.kotest.core.spec.style.FunSpec import prog8.ast.base.DataType import prog8.ast.expressions.* import prog8.ast.statements.* @@ -14,11 +12,9 @@ import prog8tests.helpers.compileText import kotlin.test.* -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestSubroutines { +class TestSubroutines: FunSpec({ - @Test - fun stringParameter() { + test("stringParameter") { val text = """ main { sub start() { @@ -65,8 +61,7 @@ class TestSubroutines { assertEquals("thing", (call.args.single() as IdentifierReference).nameInSource.single()) } - @Test - fun stringParameterAsmGen() { + test("stringParameterAsmGen") { val text = """ main { sub start() { @@ -116,8 +111,7 @@ class TestSubroutines { assertEquals("thing", (call.args.single() as IdentifierReference).nameInSource.single()) } - @Test - fun arrayParameterNotYetAllowed_ButShouldPerhapsBe() { + test("arrayParameterNotYetAllowed_ButShouldPerhapsBe") { // note: the *parser* accepts this as it is valid *syntax*, // however, it's not (yet) valid for the compiler val text = """ @@ -139,9 +133,8 @@ class TestSubroutines { assertContains(errors.errors.single(), ".p8:9:16: Non-string pass-by-reference types cannot occur as a parameter type directly") } - @Test - @Disabled("TODO: allow array parameter in signature") // TODO allow this? - fun arrayParameter() { + // TODO allow this? + xtest("arrayParameter") { val text = """ main { sub start() { @@ -178,8 +171,7 @@ class TestSubroutines { assertTrue(func.statements.isEmpty()) } - @Test - fun testUwordParameterAndNormalVarIndexedAsArrayWorkAsDirectMemoryRead() { + test("testUwordParameterAndNormalVarIndexedAsArrayWorkAsDirectMemoryRead") { val text=""" main { sub thing(uword rr) { @@ -222,8 +214,7 @@ class TestSubroutines { assertEquals(3, (valueZZexpr.right as NumericLiteralValue).number.toInt()) } - @Test - fun testUwordParameterAndNormalVarIndexedAsArrayWorkAsMemoryWrite() { + test("testUwordParameterAndNormalVarIndexedAsArrayWorkAsMemoryWrite") { val text=""" main { sub thing(uword rr) { @@ -252,4 +243,4 @@ class TestSubroutines { assertEquals("+", addressExpr.operator) assertEquals(10, (addressExpr.right as NumericLiteralValue).number.toInt()) } -} +}) diff --git a/compiler/test/ZeropageTests.kt b/compiler/test/ZeropageTests.kt index b8b41dae3..7c5bb1bfb 100644 --- a/compiler/test/ZeropageTests.kt +++ b/compiler/test/ZeropageTests.kt @@ -1,7 +1,12 @@ package prog8tests -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.assertions.withClue +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.collections.shouldBeIn +import io.kotest.matchers.collections.shouldNotBeIn +import io.kotest.matchers.ints.shouldBeGreaterThan +import io.kotest.matchers.shouldBe import prog8.ast.base.DataType import prog8.compiler.target.C64Target import prog8.compiler.target.Cx16Target @@ -9,31 +14,9 @@ import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage import prog8.compiler.target.cx16.CX16MachineDefinition.CX16Zeropage import prog8.compilerinterface.* import prog8tests.helpers.ErrorReporterForTests -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith -import kotlin.test.assertFalse -import kotlin.test.assertTrue -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestAbstractZeropage { - - @Test - fun testAbstractZeropage() { - val compTarget = DummyCompilationTarget() - val zp = DummyZeropage( - CompilationOptions( - OutputType.RAW, - LauncherType.NONE, - ZeropageType.FULL, - listOf((0x50..0x5f)), - false, - false, - compTarget - ) - ) - assertEquals(256-6-16, zp.free.size) - } +class TestAbstractZeropage: FunSpec({ class DummyCompilationTarget: ICompilationTarget { override val name: String = "dummy" @@ -67,165 +50,172 @@ class TestAbstractZeropage { } } -} + + test("testAbstractZeropage") { + val compTarget = DummyCompilationTarget() + val zp = DummyZeropage( + CompilationOptions( + OutputType.RAW, + LauncherType.NONE, + ZeropageType.FULL, + listOf((0x50..0x5f)), + false, + false, + compTarget + ) + ) + zp.free.size shouldBe 256-6-16 + } + +}) -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestC64Zeropage { +class TestC64Zeropage: FunSpec({ - private val errors = ErrorReporterForTests() + val errors = ErrorReporterForTests() - @Test - fun testNames() { + test("testNames") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, C64Target)) zp.allocate("", DataType.UBYTE, null, errors) zp.allocate("", DataType.UBYTE, null, errors) zp.allocate("varname", DataType.UBYTE, null, errors) - assertFailsWith { + shouldThrow { zp.allocate("varname", DataType.UBYTE, null, errors) } zp.allocate("varname2", DataType.UBYTE, null, errors) } - @Test - fun testZpFloatEnable() { + test("testZpFloatEnable") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target)) - assertFailsWith { + shouldThrow { zp.allocate("", DataType.FLOAT, null, errors) } val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, false, C64Target)) - assertFailsWith { + shouldThrow { zp2.allocate("", DataType.FLOAT, null, errors) } val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, false, C64Target)) zp3.allocate("", DataType.FLOAT, null, errors) } - @Test - fun testZpModesWithFloats() { + test("testZpModesWithFloats") { C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, C64Target)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, C64Target)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false, C64Target)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, false, C64Target)) - assertFailsWith { + shouldThrow { C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true, false, C64Target)) } - assertFailsWith { + shouldThrow { C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true, false, C64Target)) } } - @Test - fun testZpDontuse() { + test("testZpDontuse") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, false, C64Target)) println(zp.free) - assertEquals(0, zp.availableBytes()) - assertFailsWith { + zp.availableBytes() shouldBe 0 + shouldThrow { zp.allocate("", DataType.BYTE, null, errors) } } - @Test - fun testFreeSpacesBytes() { + test("testFreeSpacesBytes") { val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target)) - assertEquals(18, zp1.availableBytes()) + zp1.availableBytes() shouldBe 18 val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false, C64Target)) - assertEquals(85, zp2.availableBytes()) + zp2.availableBytes() shouldBe 85 val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, C64Target)) - assertEquals(125, zp3.availableBytes()) + zp3.availableBytes() shouldBe 125 val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target)) - assertEquals(238, zp4.availableBytes()) + zp4.availableBytes() shouldBe 238 zp4.allocate("test", DataType.UBYTE, null, errors) - assertEquals(237, zp4.availableBytes()) + zp4.availableBytes() shouldBe 237 zp4.allocate("test2", DataType.UBYTE, null, errors) - assertEquals(236, zp4.availableBytes()) + zp4.availableBytes() shouldBe 236 } - @Test - fun testFreeSpacesWords() { + test("testFreeSpacesWords") { val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target)) - assertEquals(6, zp1.availableWords()) + zp1.availableWords() shouldBe 6 val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false, C64Target)) - assertEquals(38, zp2.availableWords()) + zp2.availableWords() shouldBe 38 val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, C64Target)) - assertEquals(57, zp3.availableWords()) + zp3.availableWords() shouldBe 57 val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target)) - assertEquals(116, zp4.availableWords()) + zp4.availableWords() shouldBe 116 zp4.allocate("test", DataType.UWORD, null, errors) - assertEquals(115, zp4.availableWords()) + zp4.availableWords() shouldBe 115 zp4.allocate("test2", DataType.UWORD, null, errors) - assertEquals(114, zp4.availableWords()) + zp4.availableWords() shouldBe 114 } - @Test - fun testReservedSpace() { + test("testReservedSpace") { val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target)) - assertEquals(238, zp1.availableBytes()) - assertTrue(50 in zp1.free) - assertTrue(100 in zp1.free) - assertTrue(49 in zp1.free) - assertTrue(101 in zp1.free) - assertTrue(200 in zp1.free) - assertTrue(255 in zp1.free) - assertTrue(199 in zp1.free) + zp1.availableBytes() shouldBe 238 + 50 shouldBeIn zp1.free + 100 shouldBeIn zp1.free + 49 shouldBeIn zp1.free + 101 shouldBeIn zp1.free + 200 shouldBeIn zp1.free + 255 shouldBeIn zp1.free + 199 shouldBeIn zp1.free val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, listOf(50 .. 100, 200..255), false, false, C64Target)) - assertEquals(139, zp2.availableBytes()) - assertFalse(50 in zp2.free) - assertFalse(100 in zp2.free) - assertTrue(49 in zp2.free) - assertTrue(101 in zp2.free) - assertFalse(200 in zp2.free) - assertFalse(255 in zp2.free) - assertTrue(199 in zp2.free) + zp2.availableBytes() shouldBe 139 + 50 shouldNotBeIn zp2.free + 100 shouldNotBeIn zp2.free + 49 shouldBeIn zp2.free + 101 shouldBeIn zp2.free + 200 shouldNotBeIn zp2.free + 255 shouldNotBeIn zp2.free + 199 shouldBeIn zp2.free } - @Test - fun testBasicsafeAllocation() { + test("testBasicsafeAllocation") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target)) - assertEquals(18, zp.availableBytes()) - assertTrue(zp.hasByteAvailable()) - assertTrue(zp.hasWordAvailable()) + zp.availableBytes() shouldBe 18 + zp.hasByteAvailable() shouldBe true + zp.hasWordAvailable() shouldBe true - assertFailsWith { + shouldThrow { // in regular zp there aren't 5 sequential bytes free zp.allocate("", DataType.FLOAT, null, errors) } for (i in 0 until zp.availableBytes()) { val loc = zp.allocate("", DataType.UBYTE, null, errors) - assertTrue(loc > 0) + loc shouldBeGreaterThan 0 } - assertEquals(0, zp.availableBytes()) - assertFalse(zp.hasByteAvailable()) - assertFalse(zp.hasWordAvailable()) - assertFailsWith { + zp.availableBytes() shouldBe 0 + zp.hasByteAvailable() shouldBe false + zp.hasWordAvailable() shouldBe false + shouldThrow { zp.allocate("", DataType.UBYTE, null, errors) } - assertFailsWith { + shouldThrow { zp.allocate("", DataType.UWORD, null, errors) } } - @Test - fun testFullAllocation() { + test("testFullAllocation") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target)) - assertEquals(238, zp.availableBytes()) - assertTrue(zp.hasByteAvailable()) - assertTrue(zp.hasWordAvailable()) + zp.availableBytes() shouldBe 238 + zp.hasByteAvailable() shouldBe true + zp.hasWordAvailable() shouldBe true val loc = zp.allocate("", DataType.UWORD, null, errors) - assertTrue(loc > 3) - assertFalse(loc in zp.free) + loc shouldBeGreaterThan 3 + loc shouldNotBeIn zp.free val num = zp.availableBytes() / 2 for(i in 0..num-4) { zp.allocate("", DataType.UWORD, null, errors) } - assertEquals(6,zp.availableBytes()) + zp.availableBytes() shouldBe 6 - assertFailsWith { + shouldThrow { // can't allocate because no more sequential bytes, only fragmented zp.allocate("", DataType.UWORD, null, errors) } @@ -234,88 +224,85 @@ class TestC64Zeropage { zp.allocate("", DataType.UBYTE, null, errors) } - assertEquals(0, zp.availableBytes()) - assertFalse(zp.hasByteAvailable()) - assertFalse(zp.hasWordAvailable()) - assertFailsWith { + zp.availableBytes() shouldBe 0 + zp.hasByteAvailable() shouldBe false + zp.hasWordAvailable() shouldBe false + shouldThrow { // no more space zp.allocate("", DataType.UBYTE, null, errors) } } - @Test - fun testEfficientAllocation() { + test("testEfficientAllocation") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target)) - assertEquals(18, zp.availableBytes()) - assertEquals(0x04, zp.allocate("", DataType.WORD, null, errors)) - assertEquals(0x06, zp.allocate("", DataType.UBYTE, null, errors)) - assertEquals(0x0a, zp.allocate("", DataType.UBYTE, null, errors)) - assertEquals(0x9b, zp.allocate("", DataType.UWORD, null, errors)) - assertEquals(0x9e, zp.allocate("", DataType.UWORD, null, errors)) - assertEquals(0xa5, zp.allocate("", DataType.UWORD, null, errors)) - assertEquals(0xb0, zp.allocate("", DataType.UWORD, null, errors)) - assertEquals(0xbe, zp.allocate("", DataType.UWORD, null, errors)) - assertEquals(0x0e, zp.allocate("", DataType.UBYTE, null, errors)) - assertEquals(0x92, zp.allocate("", DataType.UBYTE, null, errors)) - assertEquals(0x96, zp.allocate("", DataType.UBYTE, null, errors)) - assertEquals(0xf9, zp.allocate("", DataType.UBYTE, null, errors)) - assertEquals(0, zp.availableBytes()) + zp.availableBytes() shouldBe 18 + zp.allocate("", DataType.WORD, null, errors) shouldBe 0x04 + zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0x06 + zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0x0a + zp.allocate("", DataType.UWORD, null, errors) shouldBe 0x9b + zp.allocate("", DataType.UWORD, null, errors) shouldBe 0x9e + zp.allocate("", DataType.UWORD, null, errors) shouldBe 0xa5 + zp.allocate("", DataType.UWORD, null, errors) shouldBe 0xb0 + zp.allocate("", DataType.UWORD, null, errors) shouldBe 0xbe + zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0x0e + zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0x92 + zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0x96 + zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0xf9 + zp.availableBytes() shouldBe 0 } - @Test - fun testReservedLocations() { + test("testReservedLocations") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, C64Target)) - assertEquals(zp.SCRATCH_REG, zp.SCRATCH_B1+1, "zp _B1 and _REG must be next to each other to create a word") + withClue("zp _B1 and _REG must be next to each other to create a word") { + zp.SCRATCH_B1 + 1 shouldBe zp.SCRATCH_REG + } } -} +}) -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestCx16Zeropage { - private val errors = ErrorReporterForTests() +class TestCx16Zeropage: FunSpec({ + val errors = ErrorReporterForTests() - @Test - fun testReservedLocations() { + test("testReservedLocations") { val zp = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, Cx16Target)) - assertEquals(zp.SCRATCH_REG, zp.SCRATCH_B1+1, "zp _B1 and _REG must be next to each other to create a word") + withClue("zp _B1 and _REG must be next to each other to create a word") { + zp.SCRATCH_B1 + 1 shouldBe zp.SCRATCH_REG + } } - @Test - fun testFreeSpacesBytes() { + test("testFreeSpacesBytes") { val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, Cx16Target)) - assertEquals(88, zp1.availableBytes()) + zp1.availableBytes() shouldBe 88 val zp2 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, Cx16Target)) - assertEquals(175, zp2.availableBytes()) + zp2.availableBytes() shouldBe 175 val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, Cx16Target)) - assertEquals(216, zp3.availableBytes()) + zp3.availableBytes() shouldBe 216 zp3.allocate("test", DataType.UBYTE, null, errors) - assertEquals(215, zp3.availableBytes()) + zp3.availableBytes() shouldBe 215 zp3.allocate("test2", DataType.UBYTE, null, errors) - assertEquals(214, zp3.availableBytes()) + zp3.availableBytes() shouldBe 214 } - @Test - fun testFreeSpacesWords() { + test("testFreeSpacesWords") { val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, Cx16Target)) - assertEquals(108, zp1.availableWords()) + zp1.availableWords() shouldBe 108 val zp2 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, Cx16Target)) - assertEquals(87, zp2.availableWords()) + zp2.availableWords() shouldBe 87 val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, Cx16Target)) - assertEquals(44, zp3.availableWords()) + zp3.availableWords() shouldBe 44 zp3.allocate("test", DataType.UWORD, null, errors) - assertEquals(43, zp3.availableWords()) + zp3.availableWords() shouldBe 43 zp3.allocate("test2", DataType.UWORD, null, errors) - assertEquals(42, zp3.availableWords()) + zp3.availableWords() shouldBe 42 } - @Test - fun testReservedSpace() { + test("testReservedSpace") { val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, Cx16Target)) - assertEquals(216, zp1.availableBytes()) - assertTrue(0x22 in zp1.free) - assertTrue(0x80 in zp1.free) - assertTrue(0xff in zp1.free) - assertFalse(0x02 in zp1.free) - assertFalse(0x21 in zp1.free) + zp1.availableBytes() shouldBe 216 + 0x22 shouldBeIn zp1.free + 0x80 shouldBeIn zp1.free + 0xff shouldBeIn zp1.free + 0x02 shouldNotBeIn zp1.free + 0x21 shouldNotBeIn zp1.free } -} +}) diff --git a/compiler/test/helpers/ErrorReporterForTests.kt b/compiler/test/helpers/ErrorReporterForTests.kt index eddbb248a..32304e41e 100644 --- a/compiler/test/helpers/ErrorReporterForTests.kt +++ b/compiler/test/helpers/ErrorReporterForTests.kt @@ -5,7 +5,6 @@ import prog8.compilerinterface.IErrorReporter internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: Boolean=true): IErrorReporter { - val errors = mutableListOf() val warnings = mutableListOf() diff --git a/compiler/test/helpers/compileXyz.kt b/compiler/test/helpers/compileXyz.kt index e95039b3c..79d208929 100644 --- a/compiler/test/helpers/compileXyz.kt +++ b/compiler/test/helpers/compileXyz.kt @@ -1,5 +1,7 @@ package prog8tests.helpers +import io.kotest.assertions.withClue +import io.kotest.matchers.shouldBe import prog8.compiler.CompilationResult import prog8.compiler.compileProgram import prog8.compilerinterface.ICompilationTarget @@ -8,17 +10,19 @@ import prog8tests.ast.helpers.assumeReadableFile import prog8tests.ast.helpers.outputDir import java.nio.file.Path import kotlin.io.path.name -import kotlin.test.assertFalse -import kotlin.test.assertTrue internal fun CompilationResult.assertSuccess(description: String = ""): CompilationResult { - assertTrue(success, "expected successful compilation but failed $description") + withClue("expected successful compilation but failed $description") { + success shouldBe true + } return this } internal fun CompilationResult.assertFailure(description: String = ""): CompilationResult { - assertFalse(success, "expected failure to compile but succeeded $description") + withClue("expected failure to compile but succeeded $description") { + success shouldBe false + } return this } diff --git a/compilerAst/test/TestAstToSourceText.kt b/compilerAst/test/TestAstToSourceText.kt index ce2f0517c..2d78ce6ed 100644 --- a/compilerAst/test/TestAstToSourceText.kt +++ b/compilerAst/test/TestAstToSourceText.kt @@ -1,5 +1,6 @@ package prog8tests.ast +import io.kotest.assertions.fail import io.kotest.core.spec.style.AnnotationSpec import io.kotest.matchers.string.shouldContain import prog8.ast.AstToSourceTextConverter @@ -33,8 +34,7 @@ class TestAstToSourceText: AnnotationSpec() { val parsedAgain = parseModule(SourceCode.Text(generatedText)) return Pair(generatedText, parsedAgain) } catch (e: ParseError) { - assert(false) { "should produce valid Prog8 but threw $e" } - throw e + fail("should produce valid Prog8 but threw $e") } } diff --git a/compilerAst/test/helpers/mapCombinations.kt b/compilerAst/test/helpers/mapCombinations.kt index 52c601464..23d86411b 100644 --- a/compilerAst/test/helpers/mapCombinations.kt +++ b/compilerAst/test/helpers/mapCombinations.kt @@ -1,5 +1,30 @@ package prog8tests.ast.helpers +fun cartesianProduct(c1: Collection, c2: Collection): Sequence> { + return c1.flatMap { lhsElem -> c2.map { rhsElem -> lhsElem to rhsElem } }.asSequence() +} + +fun cartesianProduct(c1: Collection, c2: Collection, c3: Collection): Sequence> { + return sequence { + for (a in c1) + for (b in c2) + for (c in c3) + yield(Triple(a,b,c)) + } +} + +data class Product(val first: T, val second: U, val third: V, val fourth: W) + +fun cartesianProduct(c1: Collection, c2: Collection, c3: Collection, c4: Collection): Sequence> { + return sequence { + for (a in c1) + for (b in c2) + for (c in c3) + for (d in c4) + yield(Product(a,b,c,d)) + } +} + fun mapCombinations(dim1: Iterable, dim2: Iterable, combine2: (A, B) -> R) = sequence { for (a in dim1) diff --git a/compilerInterfaces/src/prog8/compilerinterface/Zeropage.kt b/compilerInterfaces/src/prog8/compilerinterface/Zeropage.kt index 0c6c71e60..06183ed38 100644 --- a/compilerInterfaces/src/prog8/compilerinterface/Zeropage.kt +++ b/compilerInterfaces/src/prog8/compilerinterface/Zeropage.kt @@ -51,7 +51,7 @@ abstract class Zeropage(protected val options: CompilationOptions) { } fun allocate(scopedname: String, datatype: DataType, position: Position?, errors: IErrorReporter): Int { - assert(scopedname.isEmpty() || !allocations.values.any { it.first==scopedname } ) {"scopedname can't be allocated twice"} + require(scopedname.isEmpty() || !allocations.values.any { it.first==scopedname } ) {"scopedname can't be allocated twice"} if(options.zeropage== ZeropageType.DONTUSE) throw InternalCompilerException("zero page usage has been disabled")