From 2334e0a91548c63208fe1be2e0734fec55254639 Mon Sep 17 00:00:00 2001 From: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> Date: Wed, 8 Mar 2023 01:47:16 -0700 Subject: [PATCH] Adds back the JUnit testing system (#4979) --- .github/workflows/junit-17-builds.yml | 27 ++ .github/workflows/junit-8-builds.yml | 27 ++ .gitignore | 3 +- build.gradle | 80 ++++-- src/main/java/ch/njol/skript/Skript.java | 230 +++++++++++------- src/main/java/ch/njol/skript/SkriptAddon.java | 115 +++------ .../java/ch/njol/skript/SkriptCommand.java | 6 +- .../skript/SkriptCommandTabCompleter.java | 2 +- .../{tests => test}/platform/Environment.java | 75 +++++- .../platform/PlatformMain.java | 41 ++-- .../platform}/package-info.java | 2 +- .../runner/CondMethodExists.java | 3 +- .../runner/CondMinecraftVersion.java | 2 +- .../{tests => test}/runner/EffAssert.java | 41 ++-- .../skript/test/runner/EffObjectives.java | 122 ++++++++++ .../{tests => test}/runner/EvtTestCase.java | 2 +- .../skript/test/runner/ExprJUnitTest.java | 71 ++++++ .../skript/test/runner/SkriptJUnitTest.java | 154 ++++++++++++ .../runner/SkriptTestEvent.java | 2 +- .../{tests => test}/runner/TestFunctions.java | 2 +- .../{tests => test}/runner/TestMode.java | 9 +- .../{tests => test}/runner/TestTracker.java | 26 +- .../{tests => test/runner}/package-info.java | 2 +- .../{tests => test/utils}/TestResults.java | 2 +- .../platform => test/utils}/package-info.java | 4 +- src/main/java/ch/njol/skript/util/Utils.java | 90 ++++++- .../skript/variables/FlatFileStorageTest.java | 65 +++++ .../test/tests/aliases/AliasesTest.java | 59 +++++ .../test/tests/aliases/package-info.java | 24 ++ .../test/tests/classes/ClassesTest.java | 74 ++++++ .../test/tests/classes/package-info.java | 24 ++ .../skript/test/tests/config/NodeTest.java | 58 +++++ .../test/tests/config/package-info.java | 24 ++ .../test/tests/localization/NounTest.java | 65 +++++ .../test/tests/localization/UtilsPlurals.java | 64 +++++ .../test/tests/localization/package-info.java | 24 ++ .../tests/regression/SimpleJUnitTest.java | 68 ++++++ .../test/tests/regression/package-info.java | 24 ++ .../test/tests/syntaxes/package-info.java | 24 ++ .../skript/test/tests/utils/UtilsTest.java | 69 ++++++ .../skript/test/tests/utils/package-info.java | 24 ++ src/test/skript/README.md | 5 + src/test/skript/tests/junit/README.md | 8 + .../skript/tests/junit/SimpleJUnitTest.sk | 16 ++ 44 files changed, 1582 insertions(+), 277 deletions(-) create mode 100644 .github/workflows/junit-17-builds.yml create mode 100644 .github/workflows/junit-8-builds.yml rename src/main/java/ch/njol/skript/{tests => test}/platform/Environment.java (78%) rename src/main/java/ch/njol/skript/{tests => test}/platform/PlatformMain.java (81%) rename src/main/java/ch/njol/skript/{tests/runner => test/platform}/package-info.java (96%) rename src/main/java/ch/njol/skript/{tests => test}/runner/CondMethodExists.java (97%) rename src/main/java/ch/njol/skript/{tests => test}/runner/CondMinecraftVersion.java (98%) rename src/main/java/ch/njol/skript/{tests => test}/runner/EffAssert.java (77%) create mode 100644 src/main/java/ch/njol/skript/test/runner/EffObjectives.java rename src/main/java/ch/njol/skript/{tests => test}/runner/EvtTestCase.java (98%) create mode 100644 src/main/java/ch/njol/skript/test/runner/ExprJUnitTest.java create mode 100644 src/main/java/ch/njol/skript/test/runner/SkriptJUnitTest.java rename src/main/java/ch/njol/skript/{tests => test}/runner/SkriptTestEvent.java (96%) rename src/main/java/ch/njol/skript/{tests => test}/runner/TestFunctions.java (98%) rename src/main/java/ch/njol/skript/{tests => test}/runner/TestMode.java (91%) rename src/main/java/ch/njol/skript/{tests => test}/runner/TestTracker.java (90%) rename src/main/java/ch/njol/skript/{tests => test/runner}/package-info.java (96%) rename src/main/java/ch/njol/skript/{tests => test/utils}/TestResults.java (98%) rename src/main/java/ch/njol/skript/{tests/platform => test/utils}/package-info.java (92%) create mode 100644 src/test/java/ch/njol/skript/variables/FlatFileStorageTest.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/aliases/AliasesTest.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/aliases/package-info.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/classes/ClassesTest.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/classes/package-info.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/config/NodeTest.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/config/package-info.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/localization/NounTest.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/localization/UtilsPlurals.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/localization/package-info.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/regression/SimpleJUnitTest.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/regression/package-info.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/syntaxes/package-info.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/utils/UtilsTest.java create mode 100644 src/test/java/org/skriptlang/skript/test/tests/utils/package-info.java create mode 100644 src/test/skript/tests/junit/README.md create mode 100644 src/test/skript/tests/junit/SimpleJUnitTest.sk diff --git a/.github/workflows/junit-17-builds.yml b/.github/workflows/junit-17-builds.yml new file mode 100644 index 00000000000..eca1ebb9706 --- /dev/null +++ b/.github/workflows/junit-17-builds.yml @@ -0,0 +1,27 @@ +name: JUnit (MC 1.17+) + +on: + push: + branches: + - master + - 'dev/**' + pull_request: + +jobs: + build: + if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'adopt' + cache: gradle + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build Skript and run JUnit + run: ./gradlew clean JUnitJava17 diff --git a/.github/workflows/junit-8-builds.yml b/.github/workflows/junit-8-builds.yml new file mode 100644 index 00000000000..93971c79624 --- /dev/null +++ b/.github/workflows/junit-8-builds.yml @@ -0,0 +1,27 @@ +name: JUnit (MC 1.13-1.16) + +on: + push: + branches: + - master + - 'dev/**' + pull_request: + +jobs: + build: + if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'adopt' + cache: gradle + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build Skript and run JUnit + run: ./gradlew clean JUnitJava8 diff --git a/.gitignore b/.gitignore index 477d2c72451..fbddca8fd46 100755 --- a/.gitignore +++ b/.gitignore @@ -220,5 +220,6 @@ gradle-app.setting # End of https://www.toptal.com/developers/gitignore/api/intellij+all,gradle,java,eclipse,git -# Skript test runners +# TODO remove this in the future after some time since https://github.com/SkriptLang/Skript/pull/4979 +# This ensures developers don't upload their old existing test_runners/ folder. test_runners/ diff --git a/build.gradle b/build.gradle index 84bd6feba8d..fff7d4c2e69 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,10 @@ plugins { id 'java' } +configurations { + testImplementation.extendsFrom testShadow +} + allprojects { repositories { mavenCentral() @@ -31,7 +35,11 @@ dependencies { implementation group: 'net.milkbowl.vault', name: 'Vault', version: '1.7.1', { exclude group: 'org.bstats', module: 'bstats-bukkit' } + implementation fileTree(dir: 'lib', include: '*.jar') + + testShadow group: 'junit', name: 'junit', version: '4.12' + testShadow group: 'org.easymock', name: 'easymock', version: '4.2' } compileJava.options.encoding = 'UTF-8' @@ -47,6 +55,12 @@ task checkAliases { } } +task testJar(type: ShadowJar) { + dependsOn(compileTestJava, licenseTest) + archiveName 'Skript-JUnit.jar' + from sourceSets.test.output, sourceSets.main.output, project.configurations.testShadow +} + task jar(overwrite: true, type: ShadowJar) { dependsOn checkAliases archiveName jarName ? 'Skript.jar' : jarName @@ -64,7 +78,7 @@ task relocateShadowJar(type: ConfigureShadowRelocation) { task sourceJar(type: Jar) { from sourceSets.main.allJava - archiveClassifier = "sources" + archiveClassifier = 'sources' } tasks.withType(ShadowJar) { @@ -106,8 +120,8 @@ processResources { publishing { publications { maven(MavenPublication) { - groupId "com.github.SkriptLang" - artifactId "Skript" + groupId 'com.github.SkriptLang' + artifactId 'Skript' version project.version artifact sourceJar artifact tasks.jar @@ -116,11 +130,11 @@ publishing { repositories { maven { - name = "repo" - url = "https://repo.skriptlang.org/releases" + name = 'repo' + url = 'https://repo.skriptlang.org/releases' credentials { - username = System.getenv("MAVEN_USERNAME") - password = System.getenv("MAVEN_PASSWORD") + username = System.getenv('MAVEN_USERNAME') + password = System.getenv('MAVEN_PASSWORD') } } } @@ -167,9 +181,15 @@ tasks.register('testNaming') { } // Create a test task with given name, environments dir/file, dev mode and java version. -void createTestTask(String name, String environments, boolean devMode, int javaVersion, boolean genDocs) { +void createTestTask(String name, String desc, String environment, boolean devMode, int javaVersion, boolean genDocs, boolean junit) { tasks.register(name, JavaExec) { - dependsOn nightlyRelease, testNaming + description = desc; + dependsOn licenseTest + if (junit) { + dependsOn testJar + } else { + dependsOn nightlyRelease, testNaming + } javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(javaVersion) } @@ -178,18 +198,19 @@ void createTestTask(String name, String environments, boolean devMode, int javaV } group = 'execution' classpath = files([ - 'build' + File.separator + 'libs' + File.separator + 'Skript-nightly.jar', + 'build' + File.separator + 'libs' + File.separator + (junit ? 'Skript-JUnit.jar' : 'Skript-nightly.jar'), project.configurations.runtimeClasspath.find { it.name.startsWith('gson') }, sourceSets.main.runtimeClasspath ]) - main = 'ch.njol.skript.tests.platform.PlatformMain' + main = 'ch.njol.skript.test.platform.PlatformMain' args = [ - 'test_runners', - 'src/test/skript/tests', + 'build/test_runners', + junit ? 'src/test/skript/tests/junit' : 'src/test/skript/tests', 'src/test/resources/runner_data', - environments, + environment, devMode, - genDocs + genDocs, + junit ] } } @@ -199,20 +220,31 @@ def latestJava = 17 def oldestJava = 8 tasks.withType(JavaCompile).configureEach { - options.compilerArgs += ["-source", "" + oldestJava, "-target", "" + oldestJava] + options.compilerArgs += ['-source', '' + oldestJava, '-target', '' + oldestJava] +} + +createTestTask('JUnitQuick', 'Runs JUnit tests on one environment being the latest supported Java and Minecraft.', 'src/test/skript/environments/' + latestEnv, false, latestJava, false, true) +createTestTask('JUnitJava17', 'Runs JUnit tests on all Java 17 environments.', 'src/test/skript/environments/java17', false, latestJava, false, true) +createTestTask('JUnitJava8', 'Runs JUnit tests on all Java 8 environments.', 'src/test/skript/environments/java8', false, oldestJava, false, true) +tasks.register('JUnit') { + description = 'Runs JUnit tests on all environments.' + dependsOn JUnitJava8, JUnitJava17 } // Register different Skript testing tasks -createTestTask('quickTest', 'src/test/skript/environments/' + latestEnv, false, latestJava, false) -createTestTask('skriptTestJava17', 'src/test/skript/environments/java17', false, latestJava, false) -createTestTask('skriptTestJava8', 'src/test/skript/environments/java8', false, oldestJava, false) -createTestTask('skriptTestDev', 'src/test/skript/environments/' + (project.property('testEnv') == null +createTestTask('quickTest', 'Runs tests on one environment being the latest supported Java and Minecraft.', 'src/test/skript/environments/' + latestEnv, false, latestJava, false, false) +createTestTask('skriptTestJava17', 'Runs tests on all Java 17 environments.', 'src/test/skript/environments/java17', false, latestJava, false, false) +createTestTask('skriptTestJava8', 'Runs tests on all Java 8 environments.', 'src/test/skript/environments/java8', false, oldestJava, false, false) +createTestTask('skriptTestDev', 'Runs testing server and uses \'system.in\' for command input, stop server to finish.', 'src/test/skript/environments/' + (project.property('testEnv') == null ? latestEnv : project.property('testEnv') + '.json'), true, Integer.parseInt(project.property('testEnvJavaVersion') == null - ? latestJava : project.property('testEnvJavaVersion')), false) -tasks.register('skriptTest') {dependsOn skriptTestJava8, skriptTestJava17} -createTestTask('genDocs', 'src/test/skript/environments/' + (project.property('testEnv') == null + ? latestJava : project.property('testEnvJavaVersion')), false, false) +tasks.register('skriptTest') { + description = 'Runs tests on all environments.' + dependsOn skriptTestJava8, skriptTestJava17 +} +createTestTask('genDocs', 'Generates the Skript documentation website html files.', 'src/test/skript/environments/' + (project.property('testEnv') == null ? latestEnv : project.property('testEnv') + '.json'), false, Integer.parseInt(project.property('testEnvJavaVersion') == null - ? latestJava : project.property('testEnvJavaVersion')), true) + ? latestJava : project.property('testEnvJavaVersion')), true, false) // Build flavor configurations task githubResources(type: ProcessResources) { diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index 1b86ff51497..251c4d9afe3 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -18,6 +18,71 @@ */ package ch.njol.skript; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.Thread.UncaughtExceptionHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Filter; +import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import org.bstats.bukkit.Metrics; +import org.bstats.charts.SimplePie; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.event.server.ServerCommandEvent; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.java.JavaPlugin; +import org.eclipse.jdt.annotation.Nullable; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.skriptlang.skript.lang.entry.EntryValidator; +import org.skriptlang.skript.lang.script.Script; +import org.skriptlang.skript.lang.structure.Structure; +import org.skriptlang.skript.lang.structure.StructureInfo; + +import com.google.common.collect.Lists; +import com.google.gson.Gson; + import ch.njol.skript.aliases.Aliases; import ch.njol.skript.bukkitutil.BurgerHelper; import ch.njol.skript.classes.ClassInfo; @@ -62,9 +127,11 @@ import org.skriptlang.skript.lang.comparator.Comparators; import org.skriptlang.skript.lang.converter.Converters; import ch.njol.skript.registrations.EventValues; -import ch.njol.skript.tests.runner.SkriptTestEvent; -import ch.njol.skript.tests.runner.TestMode; -import ch.njol.skript.tests.runner.TestTracker; +import ch.njol.skript.test.runner.EffObjectives; +import ch.njol.skript.test.runner.SkriptJUnitTest; +import ch.njol.skript.test.runner.SkriptTestEvent; +import ch.njol.skript.test.runner.TestMode; +import ch.njol.skript.test.runner.TestTracker; import ch.njol.skript.timings.SkriptTimings; import ch.njol.skript.update.ReleaseManifest; import ch.njol.skript.update.ReleaseStatus; @@ -87,66 +154,6 @@ import ch.njol.util.StringUtils; import ch.njol.util.coll.iterator.CheckedIterator; import ch.njol.util.coll.iterator.EnumerationIterable; -import com.google.gson.Gson; -import org.bstats.bukkit.Metrics; -import org.bstats.charts.SimplePie; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.Server; -import org.bukkit.command.CommandSender; -import org.bukkit.command.PluginCommand; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.event.server.ServerCommandEvent; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginDescriptionFile; -import org.bukkit.plugin.java.JavaPlugin; -import org.eclipse.jdt.annotation.Nullable; -import org.skriptlang.skript.lang.entry.EntryValidator; -import org.skriptlang.skript.lang.script.Script; -import org.skriptlang.skript.lang.structure.Structure; -import org.skriptlang.skript.lang.structure.StructureInfo; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.lang.Thread.UncaughtExceptionHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.logging.Filter; -import java.util.logging.Level; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; // TODO meaningful error if someone uses an %expression with percent signs% outside of text or a variable @@ -354,7 +361,6 @@ public static void disableHookRegistration(Class>... hooks) { * The folder containing all Scripts. * Never reference this field directly. Use {@link #getScriptsFolder()}. */ - @SuppressWarnings("NotNullFieldNotInitialized") private File scriptsFolder; /** @@ -583,7 +589,7 @@ public void run() { info("Preparing Skript for testing..."); tainted = true; try { - getAddonInstance().loadClasses("ch.njol.skript", "tests"); + getAddonInstance().loadClasses("ch.njol.skript.test.runner"); } catch (IOException e) { Skript.exception("Failed to load testing environment."); Bukkit.getServer().shutdown(); @@ -637,26 +643,19 @@ protected void afterErrors() { // Skript initialization done debug("Early init done"); - Bukkit.getScheduler().runTaskLater(Skript.this, () -> { - if (TestMode.ENABLED) { // Ignore late init (scripts, etc.) in test mode + if (TestMode.ENABLED) { + Bukkit.getScheduler().runTaskLater(Skript.this, () -> info("Skript testing environment enabled, starting soon..."), 1); + // Ignore late init (scripts, etc.) in test mode + Bukkit.getScheduler().runTaskLater(Skript.this, () -> { + // Delay is in Minecraft ticks. + long shutdownDelay = 0; if (TestMode.GEN_DOCS) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "skript gen-docs"); - String results = new Gson().toJson(TestTracker.collectResults()); - try { - Files.write(TestMode.RESULTS_FILE, results.getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - Skript.exception(e, "Failed to write test results."); - } - // Delay server shutdown to stop the server from crashing because the current tick takes a long time due to all the tests - Bukkit.getScheduler().runTaskLater(Skript.this, () -> { - Bukkit.getServer().shutdown(); - }, 5); - return; - } - if (TestMode.DEV_MODE) { // Run tests NOW! + } else if (TestMode.DEV_MODE) { // Developer controlled environment. info("Test development mode enabled. Test scripts are at " + TestMode.TEST_DIR); + return; } else { - info("Running all tests from " + TestMode.TEST_DIR); + info("Loading all tests from " + TestMode.TEST_DIR); // Treat parse errors as fatal testing failure CountingLogHandler errorCounter = new CountingLogHandler(Level.SEVERE); @@ -670,8 +669,6 @@ protected void afterErrors() { } Bukkit.getPluginManager().callEvent(new SkriptTestEvent()); - - info("Collecting results to " + TestMode.RESULTS_FILE); if (errorCounter.getCount() > 0) { TestTracker.testStarted("parse scripts"); TestTracker.testFailed(errorCounter.getCount() + " error(s) found"); @@ -680,22 +677,71 @@ protected void afterErrors() { TestTracker.testStarted("run scripts"); TestTracker.testFailed("exception was thrown during execution"); } + if (TestMode.JUNIT) { + SkriptLogger.setVerbosity(Verbosity.DEBUG); + info("Running all JUnit tests..."); + long milliseconds = 0, tests = 0, fails = 0, ignored = 0, size = 0; + try { + List> classes = Lists.newArrayList(Utils.getClasses(Skript.getInstance(), "org.skriptlang.skript.test", "tests")); + // Test that requires package access. This is only present when compiling with src/test. + classes.add(Class.forName("ch.njol.skript.variables.FlatFileStorageTest")); + size = classes.size(); + for (Class clazz : classes) { + // Reset class SkriptJUnitTest which stores test requirements. + String test = clazz.getName(); + SkriptJUnitTest.setCurrentJUnitTest(test); + SkriptJUnitTest.setShutdownDelay(0); + + info("Running JUnit test '" + test + "'"); + Result junit = JUnitCore.runClasses(clazz); + TestTracker.testStarted("JUnit: '" + test + "'"); + + // Collect all data from the current JUnit test. + shutdownDelay = Math.max(shutdownDelay, SkriptJUnitTest.getShutdownDelay()); + tests += junit.getRunCount(); + milliseconds += junit.getRunTime(); + ignored += junit.getIgnoreCount(); + fails += junit.getFailureCount(); + + // If JUnit failures are present, add them to the TestTracker. + junit.getFailures().forEach(failure -> { + String message = failure.getMessage() == null ? "" : " " + failure.getMessage(); + TestTracker.testFailed("'" + test + "': " + message); + Skript.exception(failure.getException(), "JUnit test '" + failure.getTestHeader() + " failed."); + }); + SkriptJUnitTest.clearJUnitTest(); + } + } catch (IOException e) { + Skript.exception(e, "Failed to execute JUnit runtime tests."); + } catch (ClassNotFoundException e) { + // Should be the Skript test jar gradle task. + assert false : "Class 'ch.njol.skript.variables.FlatFileStorageTest' was not found."; + } + if (ignored > 0) + Skript.warning("There were " + ignored + " ignored test cases! This can mean they are not properly setup in order in that class!"); + + info("Completed " + tests + " JUnit tests in " + size + " classes with " + fails + " failures in " + milliseconds + " milliseconds."); + } + } + double display = shutdownDelay / 20; + info("Testing done, shutting down the server in " + display + " second" + (display <= 1D ? "" : "s") + "..."); + // Delay server shutdown to stop the server from crashing because the current tick takes a long time due to all the tests + Bukkit.getScheduler().runTaskLater(Skript.this, () -> { + if (TestMode.JUNIT && !EffObjectives.isJUnitComplete()) + TestTracker.testFailed(EffObjectives.getFailedObjectivesString()); + + info("Collecting results to " + TestMode.RESULTS_FILE); String results = new Gson().toJson(TestTracker.collectResults()); try { Files.write(TestMode.RESULTS_FILE, results.getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { Skript.exception(e, "Failed to write test results."); } - info("Testing done, shutting down the server."); - // Delay server shutdown to stop the server from crashing because the current tick takes a long time due to all the tests - Bukkit.getScheduler().runTaskLater(Skript.this, () -> { - Bukkit.getServer().shutdown(); - }, 5); - } - return; - } - }, 100); + Bukkit.getServer().shutdown(); + }, shutdownDelay); + }, 100); + } final long vld = System.currentTimeMillis() - vls; if (logNormal()) diff --git a/src/main/java/ch/njol/skript/SkriptAddon.java b/src/main/java/ch/njol/skript/SkriptAddon.java index d32f90d1a5c..c117f51cb9a 100644 --- a/src/main/java/ch/njol/skript/SkriptAddon.java +++ b/src/main/java/ch/njol/skript/SkriptAddon.java @@ -18,35 +18,27 @@ */ package ch.njol.skript; -import ch.njol.skript.localization.Language; -import ch.njol.skript.util.Utils; -import ch.njol.skript.util.Version; -import ch.njol.util.coll.iterator.EnumerationIterable; -import org.bukkit.plugin.java.JavaPlugin; -import org.eclipse.jdt.annotation.Nullable; - import java.io.File; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.bukkit.plugin.java.JavaPlugin; +import org.eclipse.jdt.annotation.Nullable; + +import ch.njol.skript.localization.Language; +import ch.njol.skript.util.Utils; +import ch.njol.skript.util.Version; + /** * Utility class for Skript addons. Use {@link Skript#registerAddon(JavaPlugin)} to create a SkriptAddon instance for your plugin. - * - * @author Peter Güttinger */ public final class SkriptAddon { - + public final JavaPlugin plugin; public final Version version; private final String name; - + /** * Package-private constructor. Use {@link Skript#registerAddon(JavaPlugin)} to get a SkriptAddon for your plugin. * @@ -67,16 +59,16 @@ public final class SkriptAddon { } version = v; } - + @Override public final String toString() { return name; } - + public String getName() { return name; } - + /** * Loads classes of the plugin by package. Useful for registering many syntax elements like Skript does it. * @@ -87,51 +79,13 @@ public String getName() { * @return This SkriptAddon */ public SkriptAddon loadClasses(String basePackage, String... subPackages) throws IOException { - assert subPackages != null; - JarFile jar = new JarFile(getFile()); - for (int i = 0; i < subPackages.length; i++) - subPackages[i] = subPackages[i].replace('.', '/') + "/"; - basePackage = basePackage.replace('.', '/') + "/"; - try { - List classNames = new ArrayList<>(); - - for (JarEntry e : new EnumerationIterable<>(jar.entries())) { - if (e.getName().startsWith(basePackage) && e.getName().endsWith(".class")) { - boolean load = subPackages.length == 0; - for (String sub : subPackages) { - if (e.getName().startsWith(sub, basePackage.length())) { - load = true; - break; - } - } - - if (load) - classNames.add(e.getName().replace('/', '.').substring(0, e.getName().length() - ".class".length())); - } - } - - classNames.sort(String::compareToIgnoreCase); - - for (String c : classNames) { - try { - Class.forName(c, true, plugin.getClass().getClassLoader()); - } catch (ClassNotFoundException ex) { - Skript.exception(ex, "Cannot load class " + c + " from " + this); - } catch (ExceptionInInitializerError err) { - Skript.exception(err.getCause(), this + "'s class " + c + " generated an exception while loading"); - } - } - } finally { - try { - jar.close(); - } catch (IOException e) {} - } + Utils.getClasses(plugin, basePackage, subPackages); return this; } - + @Nullable private String languageFileDirectory = null; - + /** * Makes Skript load language files from the specified directory, e.g. "lang" or "skript lang" if you have a lang folder yourself. Localised files will be read from the * plugin's jar and the plugin's data folder, but the default English file is only taken from the jar and must exist! @@ -149,40 +103,27 @@ public SkriptAddon setLanguageFileDirectory(String directory) { Language.loadDefault(this); return this; } - + @Nullable public String getLanguageFileDirectory() { return languageFileDirectory; } - + @Nullable - private File file = null; - + private File file; + /** - * @return The jar file of the plugin. The first invocation of this method uses reflection to invoke the protected method {@link JavaPlugin#getFile()} to get the plugin's jar - * file. The file is then cached and returned upon subsequent calls to this method to reduce usage of reflection. + * The first invocation of this method uses reflection to invoke the protected method {@link JavaPlugin#getFile()} to get the plugin's jar file. + * The file is then cached and returned upon subsequent calls to this method to reduce usage of reflection. + * Only nullable if there was an exception thrown. + * + * @return The jar file of the plugin. */ @Nullable public File getFile() { - if (file != null) - return file; - try { - final Method getFile = JavaPlugin.class.getDeclaredMethod("getFile"); - getFile.setAccessible(true); - file = (File) getFile.invoke(plugin); - return file; - } catch (final NoSuchMethodException e) { - Skript.outdatedError(e); - } catch (final IllegalArgumentException e) { - Skript.outdatedError(e); - } catch (final IllegalAccessException e) { - assert false; - } catch (final SecurityException e) { - throw new RuntimeException(e); - } catch (final InvocationTargetException e) { - throw new RuntimeException(e.getCause()); - } - return null; + if (file == null) + file = Utils.getFile(plugin); + return file; } - + } diff --git a/src/main/java/ch/njol/skript/SkriptCommand.java b/src/main/java/ch/njol/skript/SkriptCommand.java index ac926d14262..7f01e3ff331 100644 --- a/src/main/java/ch/njol/skript/SkriptCommand.java +++ b/src/main/java/ch/njol/skript/SkriptCommand.java @@ -27,9 +27,9 @@ import ch.njol.skript.localization.PluralizingArgsMessage; import ch.njol.skript.log.RedirectingLogHandler; import ch.njol.skript.log.TimingLogHandler; -import ch.njol.skript.tests.runner.SkriptTestEvent; -import ch.njol.skript.tests.runner.TestMode; -import ch.njol.skript.tests.runner.TestTracker; +import ch.njol.skript.test.runner.SkriptTestEvent; +import ch.njol.skript.test.runner.TestMode; +import ch.njol.skript.test.runner.TestTracker; import ch.njol.skript.util.ExceptionUtils; import ch.njol.skript.util.FileUtils; import ch.njol.skript.util.SkriptColor; diff --git a/src/main/java/ch/njol/skript/SkriptCommandTabCompleter.java b/src/main/java/ch/njol/skript/SkriptCommandTabCompleter.java index 177a8e319ea..7f01510e6db 100644 --- a/src/main/java/ch/njol/skript/SkriptCommandTabCompleter.java +++ b/src/main/java/ch/njol/skript/SkriptCommandTabCompleter.java @@ -18,7 +18,7 @@ */ package ch.njol.skript; -import ch.njol.skript.tests.runner.TestMode; +import ch.njol.skript.test.runner.TestMode; import ch.njol.util.StringUtils; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; diff --git a/src/main/java/ch/njol/skript/tests/platform/Environment.java b/src/main/java/ch/njol/skript/test/platform/Environment.java similarity index 78% rename from src/main/java/ch/njol/skript/tests/platform/Environment.java rename to src/main/java/ch/njol/skript/test/platform/Environment.java index 763a9d94f90..cd7fb24d3f3 100644 --- a/src/main/java/ch/njol/skript/tests/platform/Environment.java +++ b/src/main/java/ch/njol/skript/test/platform/Environment.java @@ -16,13 +16,15 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.tests.platform; +package ch.njol.skript.test.platform; -import ch.njol.skript.tests.TestResults; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; + +import ch.njol.skript.test.utils.TestResults; + import org.eclipse.jdt.annotation.Nullable; import java.io.File; @@ -43,6 +45,11 @@ */ public class Environment { + /** + * Time before the process is killed if there was a stack stace etc. + */ + private static final int TIMEOUT = 5 * 60_000; // 5 minutes. + private static final Gson gson = new Gson(); /** @@ -239,11 +246,11 @@ public TestResults runTests(Path runnerRoot, Path testsRoot, boolean devMode, bo args.addAll(Arrays.asList(commandLine)); Process process = new ProcessBuilder(args) - .directory(env.toFile()) - .redirectOutput(Redirect.INHERIT) - .redirectError(Redirect.INHERIT) - .redirectInput(Redirect.INHERIT) - .start(); + .directory(env.toFile()) + .redirectOutput(Redirect.INHERIT) + .redirectError(Redirect.INHERIT) + .redirectInput(Redirect.INHERIT) + .start(); // When we exit, try to make them exit too Runtime.getRuntime().addShutdownHook(new Thread(() -> { @@ -263,7 +270,7 @@ public void run() { System.exit(1); } } - }, 8 * 60_000); // 8 minutes. + }, TIMEOUT); } int code = process.waitFor(); @@ -278,4 +285,56 @@ public void run() { return results; } + @Nullable + public TestResults runJUnit(Path runnerRoot, Path testsRoot, String... jvmArgs) throws IOException, InterruptedException { + Path env = runnerRoot.resolve(name); + Path resultsPath = env.resolve("test_results.json"); + Files.deleteIfExists(resultsPath); + List args = new ArrayList<>(); + args.add(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"); + args.add("-ea"); + args.add("-Dskript.testing.enabled=true"); + args.add("-Dskript.testing.dir=" + testsRoot); + args.add("-Dskript.testing.junit=true"); + args.add("-Dskript.testing.results=test_results.json"); + args.add("-Ddisable.watchdog=true"); + args.addAll(Arrays.asList(jvmArgs)); + args.addAll(Arrays.asList(commandLine)); + + Process process = new ProcessBuilder(args) + .directory(env.toFile()) + .redirectOutput(Redirect.INHERIT) + .redirectError(Redirect.INHERIT) + .redirectInput(Redirect.INHERIT) + .start(); + + // When we exit, try to make them exit too + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + if (process.isAlive()) { + process.destroy(); + } + })); + + new Timer("runner watchdog", true).schedule(new TimerTask() { + + @Override + public void run() { + if (process.isAlive()) { + System.err.println("Test environment is taking too long, failing..."); + System.exit(1); + } + } + }, TIMEOUT); + int code = process.waitFor(); + if (code != 0) + throw new IOException("environment returned with code " + code); + + // Read test results + if (!Files.exists(resultsPath)) + return null; + TestResults results = new Gson().fromJson(new String(Files.readAllBytes(resultsPath)), TestResults.class); + assert results != null; + return results; + } + } diff --git a/src/main/java/ch/njol/skript/tests/platform/PlatformMain.java b/src/main/java/ch/njol/skript/test/platform/PlatformMain.java similarity index 81% rename from src/main/java/ch/njol/skript/tests/platform/PlatformMain.java rename to src/main/java/ch/njol/skript/test/platform/PlatformMain.java index 0098f97200e..29f09c30a15 100644 --- a/src/main/java/ch/njol/skript/tests/platform/PlatformMain.java +++ b/src/main/java/ch/njol/skript/test/platform/PlatformMain.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.tests.platform; +package ch.njol.skript.test.platform; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -39,7 +39,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; -import ch.njol.skript.tests.TestResults; +import ch.njol.skript.test.utils.TestResults; import ch.njol.util.NonNullPair; /** @@ -62,6 +62,7 @@ public static void main(String... args) throws IOException, InterruptedException assert envsRoot != null; boolean devMode = "true".equals(args[4]); boolean genDocs = "true".equals(args[5]); + boolean junit = "true".equals(args[6]); // Load environments List envs; @@ -80,17 +81,22 @@ public static void main(String... args) throws IOException, InterruptedException } System.out.println("Test environments: " + String.join(", ", envs.stream().map(Environment::getName).collect(Collectors.toList()))); - - Set allTests = new HashSet<>(); + Map>> failures = new HashMap<>(); - + Set allTests = new HashSet<>(); + boolean docsFailed = false; // Run tests and collect the results envs.sort(Comparator.comparing(Environment::getName)); for (Environment env : envs) { System.out.println("Starting testing on " + env.getName()); env.initialize(dataRoot, runnerRoot, false); - TestResults results = env.runTests(runnerRoot, testsRoot, devMode, genDocs, "-Xmx5G"); + TestResults results = null; + if (junit) { + results = env.runJUnit(runnerRoot, testsRoot, "-Xmx5G"); + } else { + results = env.runTests(runnerRoot, testsRoot, devMode, genDocs, "-Xmx5G"); + } if (results == null) { if (devMode) { // Nothing to report, it's the dev mode environment. @@ -131,24 +137,29 @@ public static void main(String... args) throws IOException, InterruptedException Collections.sort(succeeded); List failNames = new ArrayList<>(failures.keySet()); Collections.sort(failNames); - + // All succeeded tests in a single line - System.out.printf("%s Results %s%n", StringUtils.repeat("-", 25), StringUtils.repeat("-", 25)); - System.out.println("Tested environments: " + String.join(", ", + StringBuilder output = new StringBuilder(String.format("%s Results %s%n", StringUtils.repeat("-", 25), StringUtils.repeat("-", 25))); + output.append("\nTested environments: " + String.join(", ", envs.stream().map(Environment::getName).collect(Collectors.toList()))); - System.out.println("\nSucceeded: " + String.join(", ", succeeded)); + output.append("\nSucceeded:\n " + String.join((junit ? "\n " : ", "), succeeded)); + if (!failNames.isEmpty()) { // More space for failed tests, they're important - System.err.println("Failed:"); + output.append("\nFailed:"); for (String failed : failNames) { List> errors = failures.get(failed); - System.err.println(" " + failed + " (on " + errors.size() + " environments)"); + output.append(" " + failed + " (on " + errors.size() + " environment" + (errors.size() == 1 ? "" : "s") + ")"); for (NonNullPair error : errors) { - System.err.println(" " + error.getSecond() + " (on " + error.getFirst().getName() + ")"); + output.append(" " + error.getSecond() + " (on " + error.getFirst().getName() + ")"); } } - System.exit(failNames.size()); // Error code to indicate how many tests failed + output.append(String.format("%n%n%s", StringUtils.repeat("-", 60))); + System.err.print(output.toString()); + System.exit(failNames.size()); // Error code to indicate how many tests failed. + return; } - System.out.printf("%n%s", StringUtils.repeat("-", 60)); + output.append(String.format("%n%n%s", StringUtils.repeat("-", 60))); + System.out.print(output.toString()); } } diff --git a/src/main/java/ch/njol/skript/tests/runner/package-info.java b/src/main/java/ch/njol/skript/test/platform/package-info.java similarity index 96% rename from src/main/java/ch/njol/skript/tests/runner/package-info.java rename to src/main/java/ch/njol/skript/test/platform/package-info.java index 8d276f66853..6ea91784b5f 100644 --- a/src/main/java/ch/njol/skript/tests/runner/package-info.java +++ b/src/main/java/ch/njol/skript/test/platform/package-info.java @@ -20,7 +20,7 @@ * Support for script-based testing. */ @NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) -package ch.njol.skript.tests.runner; +package ch.njol.skript.test.platform; import org.eclipse.jdt.annotation.DefaultLocation; import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/src/main/java/ch/njol/skript/tests/runner/CondMethodExists.java b/src/main/java/ch/njol/skript/test/runner/CondMethodExists.java similarity index 97% rename from src/main/java/ch/njol/skript/tests/runner/CondMethodExists.java rename to src/main/java/ch/njol/skript/test/runner/CondMethodExists.java index 8a3b5e04061..17d821ad6aa 100644 --- a/src/main/java/ch/njol/skript/tests/runner/CondMethodExists.java +++ b/src/main/java/ch/njol/skript/test/runner/CondMethodExists.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.tests.runner; +package ch.njol.skript.test.runner; import ch.njol.skript.conditions.base.PropertyCondition; import org.apache.commons.lang.StringUtils; @@ -50,7 +50,6 @@ public class CondMethodExists extends PropertyCondition { Skript.registerCondition(CondMethodExists.class, "method[s] %strings% [dont:do(esn't|n't)] exist[s]"); } - @SuppressWarnings("NotNullFieldNotInitialized") private Expression signatures; @Override diff --git a/src/main/java/ch/njol/skript/tests/runner/CondMinecraftVersion.java b/src/main/java/ch/njol/skript/test/runner/CondMinecraftVersion.java similarity index 98% rename from src/main/java/ch/njol/skript/tests/runner/CondMinecraftVersion.java rename to src/main/java/ch/njol/skript/test/runner/CondMinecraftVersion.java index 4aaafa405f7..bc5f1436349 100644 --- a/src/main/java/ch/njol/skript/tests/runner/CondMinecraftVersion.java +++ b/src/main/java/ch/njol/skript/test/runner/CondMinecraftVersion.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.tests.runner; +package ch.njol.skript.test.runner; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; diff --git a/src/main/java/ch/njol/skript/tests/runner/EffAssert.java b/src/main/java/ch/njol/skript/test/runner/EffAssert.java similarity index 77% rename from src/main/java/ch/njol/skript/tests/runner/EffAssert.java rename to src/main/java/ch/njol/skript/test/runner/EffAssert.java index 04e4e9ce786..4f78665295d 100644 --- a/src/main/java/ch/njol/skript/tests/runner/EffAssert.java +++ b/src/main/java/ch/njol/skript/test/runner/EffAssert.java @@ -16,20 +16,19 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.tests.runner; +package ch.njol.skript.test.runner; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; +import ch.njol.skript.doc.NoDoc; import ch.njol.skript.lang.Condition; import ch.njol.skript.lang.Effect; import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.TriggerItem; import ch.njol.skript.log.ParseLogHandler; import ch.njol.skript.log.SkriptLogger; @@ -37,8 +36,7 @@ @Name("Assert") @Description("Assert that condition is true. Test fails when it is not.") -@Examples("") -@Since("2.5") +@NoDoc public class EffAssert extends Effect { static { @@ -49,14 +47,12 @@ public class EffAssert extends Effect { @Nullable private Condition condition; - @SuppressWarnings("null") private Expression errorMsg; - private boolean shouldFail; - @SuppressWarnings({"null", "unchecked"}) @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { String conditionString = parseResult.regexes.get(0).group(); errorMsg = (Expression) exprs[0]; shouldFail = parseResult.mark != 0; @@ -65,9 +61,8 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye try { condition = Condition.parse(conditionString, "Can't understand this condition: " + conditionString); - if (shouldFail) { + if (shouldFail) return true; - } if (condition == null) { logHandler.printError(); @@ -82,18 +77,22 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye } @Override - protected void execute(Event e) {} - + protected void execute(Event event) {} + @Nullable @Override - public TriggerItem walk(Event e) { - if (shouldFail && condition == null) { + public TriggerItem walk(Event event) { + if (shouldFail && condition == null) return getNext(); - } - - if (condition.check(e) == shouldFail) { - String msg = errorMsg.getSingle(e); - TestTracker.testFailed(msg != null ? msg : "assertation failed"); + + if (condition.check(event) == shouldFail) { + String message = errorMsg.getSingle(event); + assert message != null; // Should not happen, developer needs to fix test. + if (SkriptJUnitTest.getCurrentJUnitTest() != null) { + TestTracker.junitTestFailed(SkriptJUnitTest.getCurrentJUnitTest(), message); + } else { + TestTracker.testFailed(message); + } return null; } return getNext(); diff --git a/src/main/java/ch/njol/skript/test/runner/EffObjectives.java b/src/main/java/ch/njol/skript/test/runner/EffObjectives.java new file mode 100644 index 00000000000..9a2d9a0e4ae --- /dev/null +++ b/src/main/java/ch/njol/skript/test/runner/EffObjectives.java @@ -0,0 +1,122 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package ch.njol.skript.test.runner; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.NoDoc; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; + +@Name("Objectives") +@Description("An effect to setup required objectives for JUnit tests to complete.") +@NoDoc +public class EffObjectives extends Effect { + + static { + if (TestMode.ENABLED) + Skript.registerEffect(EffObjectives.class, + "ensure [[junit] test] %string% completes [(objective|trigger)[s]] %strings%", + "complete [(objective|trigger)[s]] %strings% (for|on) [[junit] test] %string%" + ); + } + + private static final Multimap requirements = HashMultimap.create(); + private static final Multimap completeness = HashMultimap.create(); + + private Expression junit, objectives; + private boolean setup; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + objectives = (Expression) exprs[matchedPattern ^ 1]; + junit = (Expression) exprs[matchedPattern]; + setup = matchedPattern == 0; + return true; + } + + @Override + protected void execute(Event event) { + String junit = this.junit.getSingle(event); + assert junit != null; + String[] objectives = this.objectives.getArray(event); + assert objectives.length > 0; + if (setup) { + requirements.putAll(junit, Lists.newArrayList(objectives)); + } else { + completeness.putAll(junit, Lists.newArrayList(objectives)); + } + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + if (setup) + return "ensure junit test " + junit.toString(event, debug) + " completes objectives " + objectives.toString(event, debug); + return "complete objectives " + objectives.toString(event, debug) + " on junit test " + junit.toString(event, debug); + } + + /** + * Check if the currently running JUnit test has passed all + * it's required objectives that the script test setup. + * + * @return boolean true if the test passed. + */ + public static boolean isJUnitComplete() { + if (requirements.isEmpty()) + return true; + if (completeness.isEmpty() && !requirements.isEmpty()) + return false; + return completeness.equals(requirements); + } + + /** + * Returns an array string containing all the objectives that the current + * JUnit test failed to accomplish in the given time. + * + * @return + */ + public static String getFailedObjectivesString() { + StringBuilder builder = new StringBuilder(); + for (String test : requirements.keySet()) { + if (!completeness.containsKey(test)) { + builder.append("JUnit test '" + test + "' didn't complete any objectives."); + continue; + } + List failures = Lists.newArrayList(requirements.get(test)); + failures.removeAll(completeness.get(test)); + builder.append("JUnit test '" + test + "' failed objectives: " + Arrays.toString(failures.toArray(new String[0]))); + } + return builder.toString(); + } + +} diff --git a/src/main/java/ch/njol/skript/tests/runner/EvtTestCase.java b/src/main/java/ch/njol/skript/test/runner/EvtTestCase.java similarity index 98% rename from src/main/java/ch/njol/skript/tests/runner/EvtTestCase.java rename to src/main/java/ch/njol/skript/test/runner/EvtTestCase.java index 82809604a19..eb6bbd93b4f 100644 --- a/src/main/java/ch/njol/skript/tests/runner/EvtTestCase.java +++ b/src/main/java/ch/njol/skript/test/runner/EvtTestCase.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.tests.runner; +package ch.njol.skript.test.runner; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; diff --git a/src/main/java/ch/njol/skript/test/runner/ExprJUnitTest.java b/src/main/java/ch/njol/skript/test/runner/ExprJUnitTest.java new file mode 100644 index 00000000000..0f85a98e8aa --- /dev/null +++ b/src/main/java/ch/njol/skript/test/runner/ExprJUnitTest.java @@ -0,0 +1,71 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package ch.njol.skript.test.runner; + +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.NoDoc; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; + +@Name("JUnit Test Name") +@Description("Returns the currently running JUnit test name otherwise nothing.") +@NoDoc +public class ExprJUnitTest extends SimpleExpression { + + static { + if (TestMode.ENABLED) + Skript.registerExpression(ExprJUnitTest.class, String.class, ExpressionType.SIMPLE, "[the] [current[[ly] running]] junit test [name]"); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + return true; + } + + @Override + @Nullable + protected String[] get(Event event) { + return CollectionUtils.array(SkriptJUnitTest.getCurrentJUnitTest()); + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "current junit test"; + } + +} diff --git a/src/main/java/ch/njol/skript/test/runner/SkriptJUnitTest.java b/src/main/java/ch/njol/skript/test/runner/SkriptJUnitTest.java new file mode 100644 index 00000000000..ed9fb6d026e --- /dev/null +++ b/src/main/java/ch/njol/skript/test/runner/SkriptJUnitTest.java @@ -0,0 +1,154 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package ch.njol.skript.test.runner; + +import org.bukkit.Bukkit; +import org.bukkit.GameRule; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Pig; +import org.junit.After; +import org.junit.Before; + +import ch.njol.skript.Skript; + +/** + * Class that helps the JUnit test communicate with Skript. + */ +public abstract class SkriptJUnitTest { + + static { + World world = Bukkit.getWorlds().get(0); + world.setGameRule(GameRule.MAX_ENTITY_CRAMMING, 1000); + world.setGameRule(GameRule.DO_WEATHER_CYCLE, false); + // Natural entity spawning + world.setGameRule(GameRule.DO_MOB_SPAWNING, false); + world.setGameRule(GameRule.MOB_GRIEFING, false); + + if (Skript.isRunningMinecraft(1, 15)) { + world.setGameRule(GameRule.DO_PATROL_SPAWNING, false); + world.setGameRule(GameRule.DO_TRADER_SPAWNING, false); + world.setGameRule(GameRule.DISABLE_RAIDS, false); + } + } + + /** + * Used for getting the currently running JUnit test name. + */ + private static String currentJUnitTest; + + private static long delay = 0; + + /** + * The delay this JUnit test is requiring to run. + * Do note this is global to all other tests. The most delay is the final waiting time. + * + * @return the delay in Minecraft ticks this junit test is requiring to run for. + */ + public static long getShutdownDelay() { + return delay; + } + + /** + * @param delay Set the delay in Minecraft ticks for this test to run. + */ + public static void setShutdownDelay(long delay) { + SkriptJUnitTest.delay = delay; + } + + @Before + @After + public final void cleanup() { + getTestWorld().getEntities().forEach(Entity::remove); + setBlock(Material.AIR); + } + + /** + * @return the test world. + */ + protected World getTestWorld() { + return Bukkit.getWorlds().get(0); + } + + /** + * @return the testing location at the spawn of the testing world. + */ + protected Location getTestLocation() { + return getTestWorld().getSpawnLocation().add(0, 1, 0); + } + + /** + * Spawns a testing pig at the spawn location of the testing world. + * + * @return Pig that has been spawned. + */ + protected Pig spawnTestPig() { + if (delay <= 0D) + delay = 1; // A single tick allows the piggy to spawn before server shutdown. + return (Pig) getTestWorld().spawnEntity(getTestLocation(), EntityType.PIG); + } + + /** + * Set the type of the block at the testing location. + * + * @param material The material to set the block to. + * @return the Block after it has been updated. + */ + protected Block setBlock(Material material) { + Block block = getBlock(); + block.setType(material); + return block; + } + + /** + * Return the main block for testing in the getTestLocation(); + * + * @return the Block after it has been updated. + */ + protected Block getBlock() { + return getTestWorld().getSpawnLocation().add(10, 1, 0).getBlock(); + } + + /** + * Get the currently running JUnit test name. + */ + public static String getCurrentJUnitTest() { + return currentJUnitTest; + } + + /** + * Used internally. + */ + public static void setCurrentJUnitTest(String currentJUnitTest) { + SkriptJUnitTest.currentJUnitTest = currentJUnitTest; + } + + /** + * Used internally. + */ + public static void clearJUnitTest() { + SkriptJUnitTest.currentJUnitTest = null; + setShutdownDelay(0); + } + +} diff --git a/src/main/java/ch/njol/skript/tests/runner/SkriptTestEvent.java b/src/main/java/ch/njol/skript/test/runner/SkriptTestEvent.java similarity index 96% rename from src/main/java/ch/njol/skript/tests/runner/SkriptTestEvent.java rename to src/main/java/ch/njol/skript/test/runner/SkriptTestEvent.java index be7bf978857..558a7ae458e 100644 --- a/src/main/java/ch/njol/skript/tests/runner/SkriptTestEvent.java +++ b/src/main/java/ch/njol/skript/test/runner/SkriptTestEvent.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.tests.runner; +package ch.njol.skript.test.runner; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; diff --git a/src/main/java/ch/njol/skript/tests/runner/TestFunctions.java b/src/main/java/ch/njol/skript/test/runner/TestFunctions.java similarity index 98% rename from src/main/java/ch/njol/skript/tests/runner/TestFunctions.java rename to src/main/java/ch/njol/skript/test/runner/TestFunctions.java index 21f31a52b80..fe9a434cebe 100644 --- a/src/main/java/ch/njol/skript/tests/runner/TestFunctions.java +++ b/src/main/java/ch/njol/skript/test/runner/TestFunctions.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.tests.runner; +package ch.njol.skript.test.runner; import ch.njol.skript.classes.ClassInfo; import ch.njol.skript.lang.function.Functions; diff --git a/src/main/java/ch/njol/skript/tests/runner/TestMode.java b/src/main/java/ch/njol/skript/test/runner/TestMode.java similarity index 91% rename from src/main/java/ch/njol/skript/tests/runner/TestMode.java rename to src/main/java/ch/njol/skript/test/runner/TestMode.java index d4612da0b4a..9374269f710 100644 --- a/src/main/java/ch/njol/skript/tests/runner/TestMode.java +++ b/src/main/java/ch/njol/skript/test/runner/TestMode.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.tests.runner; +package ch.njol.skript.test.runner; import java.io.File; import java.nio.file.Path; @@ -24,7 +24,7 @@ import org.eclipse.jdt.annotation.Nullable; -import ch.njol.skript.tests.TestResults; +import ch.njol.skript.test.utils.TestResults; /** * Static utilities for Skript's 'test mode'. @@ -63,6 +63,11 @@ public class TestMode { */ public static final Path RESULTS_FILE = ENABLED ? Paths.get(System.getProperty(ROOT + "results")) : null; + /** + * If this test is for JUnits on the server. + */ + public static final boolean JUNIT = "true".equals(System.getProperty(ROOT + "junit")); + /** * In development mode, file that was last run. */ diff --git a/src/main/java/ch/njol/skript/tests/runner/TestTracker.java b/src/main/java/ch/njol/skript/test/runner/TestTracker.java similarity index 90% rename from src/main/java/ch/njol/skript/tests/runner/TestTracker.java rename to src/main/java/ch/njol/skript/test/runner/TestTracker.java index a80ca913814..fb6b2a0df40 100644 --- a/src/main/java/ch/njol/skript/tests/runner/TestTracker.java +++ b/src/main/java/ch/njol/skript/test/runner/TestTracker.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.tests.runner; +package ch.njol.skript.test.runner; import java.util.HashMap; import java.util.HashSet; @@ -25,50 +25,54 @@ import org.eclipse.jdt.annotation.Nullable; -import ch.njol.skript.tests.TestResults; +import ch.njol.skript.test.utils.TestResults; /** * Tracks failed and succeeded tests. */ public class TestTracker { - + /** * Started tests. */ private static final Set startedTests = new HashSet<>(); - + /** * Failed tests to failure assert messages. */ private static final Map failedTests = new HashMap<>(); - + @Nullable private static String currentTest; - + public static void testStarted(String name) { startedTests.add(name); currentTest = name; } - + public static void testFailed(String msg) { failedTests.put(currentTest, msg); } - + + public static void junitTestFailed(String junit, String msg) { + failedTests.put(junit, msg); + } + public static Map getFailedTests() { return new HashMap<>(failedTests); } - + public static Set getSucceededTests() { Set tests = new HashSet<>(startedTests); tests.removeAll(failedTests.keySet()); return tests; } - + public static TestResults collectResults() { TestResults results = new TestResults(getSucceededTests(), getFailedTests(), TestMode.docsFailed); startedTests.clear(); failedTests.clear(); return results; } - + } diff --git a/src/main/java/ch/njol/skript/tests/package-info.java b/src/main/java/ch/njol/skript/test/runner/package-info.java similarity index 96% rename from src/main/java/ch/njol/skript/tests/package-info.java rename to src/main/java/ch/njol/skript/test/runner/package-info.java index bee5911b214..0111f884a88 100644 --- a/src/main/java/ch/njol/skript/tests/package-info.java +++ b/src/main/java/ch/njol/skript/test/runner/package-info.java @@ -20,7 +20,7 @@ * Support for script-based testing. */ @NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) -package ch.njol.skript.tests; +package ch.njol.skript.test.runner; import org.eclipse.jdt.annotation.DefaultLocation; import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/src/main/java/ch/njol/skript/tests/TestResults.java b/src/main/java/ch/njol/skript/test/utils/TestResults.java similarity index 98% rename from src/main/java/ch/njol/skript/tests/TestResults.java rename to src/main/java/ch/njol/skript/test/utils/TestResults.java index ecc9045f0b2..53586491992 100644 --- a/src/main/java/ch/njol/skript/tests/TestResults.java +++ b/src/main/java/ch/njol/skript/test/utils/TestResults.java @@ -16,7 +16,7 @@ * * Copyright Peter Güttinger, SkriptLang team and contributors */ -package ch.njol.skript.tests; +package ch.njol.skript.test.utils; import java.util.Map; import java.util.Set; diff --git a/src/main/java/ch/njol/skript/tests/platform/package-info.java b/src/main/java/ch/njol/skript/test/utils/package-info.java similarity index 92% rename from src/main/java/ch/njol/skript/tests/platform/package-info.java rename to src/main/java/ch/njol/skript/test/utils/package-info.java index eef7a9713b0..846a1258239 100644 --- a/src/main/java/ch/njol/skript/tests/platform/package-info.java +++ b/src/main/java/ch/njol/skript/test/utils/package-info.java @@ -17,10 +17,10 @@ * Copyright Peter Güttinger, SkriptLang team and contributors */ /** - * Support for script-based testing. + * Utils for script-based testing. */ @NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) -package ch.njol.skript.tests.platform; +package ch.njol.skript.test.utils; import org.eclipse.jdt.annotation.DefaultLocation; import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/src/main/java/ch/njol/skript/util/Utils.java b/src/main/java/ch/njol/skript/util/Utils.java index 18adcfdaf4c..12255d4d8d6 100644 --- a/src/main/java/ch/njol/skript/util/Utils.java +++ b/src/main/java/ch/njol/skript/util/Utils.java @@ -18,6 +18,11 @@ */ package ch.njol.skript.util; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -25,12 +30,16 @@ import java.util.Random; import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.messaging.Messenger; import org.bukkit.plugin.messaging.PluginMessageListener; import org.eclipse.jdt.annotation.Nullable; @@ -51,6 +60,7 @@ import ch.njol.util.Pair; import ch.njol.util.StringUtils; import ch.njol.util.coll.CollectionUtils; +import ch.njol.util.coll.iterator.EnumerationIterable; import net.md_5.bungee.api.ChatColor; /** @@ -149,7 +159,85 @@ public static Pair getAmount(String s) { // } // return new AmountResponse(s); // } - + + /** + * Loads classes of the plugin by package. Useful for registering many syntax elements like Skript does it. + * + * @param basePackage The base package to add to all sub packages, e.g. "ch.njol.skript". + * @param subPackages Which subpackages of the base package should be loaded, e.g. "expressions", "conditions", "effects". Subpackages of these packages will be loaded + * as well. Use an empty array to load all subpackages of the base package. + * @throws IOException If some error occurred attempting to read the plugin's jar file. + * @return This SkriptAddon + */ + public static Class[] getClasses(Plugin plugin, String basePackage, String... subPackages) throws IOException { + assert subPackages != null; + JarFile jar = new JarFile(getFile(plugin)); + for (int i = 0; i < subPackages.length; i++) + subPackages[i] = subPackages[i].replace('.', '/') + "/"; + basePackage = basePackage.replace('.', '/') + "/"; + List> classes = new ArrayList<>(); + try { + List classNames = new ArrayList<>(); + + for (JarEntry e : new EnumerationIterable<>(jar.entries())) { + if (e.getName().startsWith(basePackage) && e.getName().endsWith(".class") && !e.getName().endsWith("package-info.class")) { + boolean load = subPackages.length == 0; + for (String sub : subPackages) { + if (e.getName().startsWith(sub, basePackage.length())) { + load = true; + break; + } + } + + if (load) + classNames.add(e.getName().replace('/', '.').substring(0, e.getName().length() - ".class".length())); + } + } + + classNames.sort(String::compareToIgnoreCase); + + for (String c : classNames) { + try { + classes.add(Class.forName(c, true, plugin.getClass().getClassLoader())); + } catch (ClassNotFoundException ex) { + Skript.exception(ex, "Cannot load class " + c); + } catch (ExceptionInInitializerError err) { + Skript.exception(err.getCause(), "class " + c + " generated an exception while loading"); + } + } + } finally { + try { + jar.close(); + } catch (IOException e) {} + } + return classes.toArray(new Class[classes.size()]); + } + + /** + * The first invocation of this method uses reflection to invoke the protected method {@link JavaPlugin#getFile()} to get the plugin's jar file. + * + * @return The jar file of the plugin. + */ + @Nullable + public static File getFile(Plugin plugin) { + try { + Method getFile = JavaPlugin.class.getDeclaredMethod("getFile"); + getFile.setAccessible(true); + return (File) getFile.invoke(plugin); + } catch (NoSuchMethodException e) { + Skript.outdatedError(e); + } catch (IllegalArgumentException e) { + Skript.outdatedError(e); + } catch (IllegalAccessException e) { + assert false; + } catch (SecurityException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e.getCause()); + } + return null; + } + private final static String[][] plurals = { {"fe", "ves"},// most -f words' plurals can end in -fs as well as -ves diff --git a/src/test/java/ch/njol/skript/variables/FlatFileStorageTest.java b/src/test/java/ch/njol/skript/variables/FlatFileStorageTest.java new file mode 100644 index 00000000000..3868358459c --- /dev/null +++ b/src/test/java/ch/njol/skript/variables/FlatFileStorageTest.java @@ -0,0 +1,65 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package ch.njol.skript.variables; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; + +public class FlatFileStorageTest { + + @Test + public void testHexCoding() { + byte[] bytes = {-0x80, -0x50, -0x01, 0x00, 0x01, 0x44, 0x7F}; + String string = "80B0FF0001447F"; + assertEquals(string, FlatFileStorage.encode(bytes)); + assert Arrays.equals(bytes, FlatFileStorage.decode(string)) : Arrays.toString(bytes) + " != " + Arrays.toString(FlatFileStorage.decode(string)); + } + + @Test + public void testSplitCSV() { + String[][] vs = { + {"", ""}, + {",", "", ""}, + {",,", "", "", ""}, + {"a", "a"}, + {"a,", "a", ""}, + {",a", "", "a"}, + {",a,", "", "a", ""}, + {" , a , ", "", "a", ""}, + {"a,b,c", "a", "b", "c"}, + {" a , b , c ", "a", "b", "c"}, + + {"\"\"", ""}, + {"\",\"", ","}, + {"\"\"\"\"", "\""}, + {"\" \"", " "}, + {"a, \"\"\"\", b, \", c\", d", "a", "\"", "b", ", c", "d"}, + {"a, \"\"\", b, \", c", "a", "\", b, ", "c"}, + + {"\"\t\0\"", "\t\0"}, + }; + for (String[] v : vs) { + assert Arrays.equals(Arrays.copyOfRange(v, 1, v.length), FlatFileStorage.splitCSV(v[0])) : v[0] + ": " + Arrays.toString(Arrays.copyOfRange(v, 1, v.length)) + " != " + Arrays.toString(FlatFileStorage.splitCSV(v[0])); + } + } + +} diff --git a/src/test/java/org/skriptlang/skript/test/tests/aliases/AliasesTest.java b/src/test/java/org/skriptlang/skript/test/tests/aliases/AliasesTest.java new file mode 100644 index 00000000000..c2ad1a61918 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/aliases/AliasesTest.java @@ -0,0 +1,59 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package org.skriptlang.skript.test.tests.aliases; + +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.junit.Test; + +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.registrations.Classes; + +public class AliasesTest { + + @Test + public void test() { + ItemStack itemstack = new ItemStack(Material.LEATHER_CHESTPLATE, 6); + ItemMeta meta = itemstack.getItemMeta(); + assert meta instanceof LeatherArmorMeta; + LeatherArmorMeta leather = (LeatherArmorMeta) meta; + leather.setColor(Color.LIME); + itemstack.setItemMeta(leather); + ItemType itemType = new ItemType(itemstack); + assert itemType.equals(new ItemType(itemstack)); + + itemstack = new ItemStack(Material.LEATHER_CHESTPLATE, 2); + meta = itemstack.getItemMeta(); + assert meta instanceof LeatherArmorMeta; + leather = (LeatherArmorMeta) meta; + leather.setColor(Color.RED); + itemstack.setItemMeta(leather); + assert !itemType.equals(new ItemType(itemstack)); + + // Contains assert inside serialize method too, Njol mentioned this. + assert Classes.serialize(itemType) != null; + // This doesn't work anymore since Njol added this. + //assert Classes.serialize(itemType).equals(Classes.serialize(itemType)); + assert !Classes.serialize(itemType).equals(Classes.serialize(new ItemType(itemstack))); + } + +} diff --git a/src/test/java/org/skriptlang/skript/test/tests/aliases/package-info.java b/src/test/java/org/skriptlang/skript/test/tests/aliases/package-info.java new file mode 100644 index 00000000000..9abed714d99 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/aliases/package-info.java @@ -0,0 +1,24 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) +package org.skriptlang.skript.test.tests.aliases; + +import org.eclipse.jdt.annotation.DefaultLocation; +import org.eclipse.jdt.annotation.NonNullByDefault; + diff --git a/src/test/java/org/skriptlang/skript/test/tests/classes/ClassesTest.java b/src/test/java/org/skriptlang/skript/test/tests/classes/ClassesTest.java new file mode 100644 index 00000000000..385078a5701 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/classes/ClassesTest.java @@ -0,0 +1,74 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package org.skriptlang.skript.test.tests.classes; + +import org.bukkit.GameMode; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Snowball; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.inventory.InventoryType; +import org.junit.Test; + +import ch.njol.skript.entity.CreeperData; +import ch.njol.skript.entity.EntityType; +import ch.njol.skript.entity.SimpleEntityData; +import ch.njol.skript.entity.ThrownPotionData; +import ch.njol.skript.entity.WolfData; +import ch.njol.skript.entity.XpOrbData; +import ch.njol.skript.registrations.Classes; +import ch.njol.skript.util.Date; +import ch.njol.skript.util.Direction; +import ch.njol.skript.util.Experience; +import ch.njol.skript.util.SkriptColor; +import ch.njol.skript.util.StructureType; +import ch.njol.skript.util.Time; +import ch.njol.skript.util.Timeperiod; +import ch.njol.skript.util.Timespan; +import ch.njol.skript.util.WeatherType; + +public class ClassesTest { + + @Test + public void serializationTest() { + Object[] random = { + // Java + (byte) 127, (short) 2000, -1600000, 1L << 40, -1.5f, 13.37, + "String", + + // Skript + SkriptColor.BLACK, StructureType.RED_MUSHROOM, WeatherType.THUNDER, + new Date(System.currentTimeMillis()), new Timespan(1337), new Time(12000), new Timeperiod(1000, 23000), + new Experience(15), new Direction(0, Math.PI, 10), new Direction(new double[] {0, 1, 0}), + new EntityType(new SimpleEntityData(HumanEntity.class), 300), + new CreeperData(), + new SimpleEntityData(Snowball.class), + new ThrownPotionData(), + new WolfData(), + new XpOrbData(50), + + // Bukkit - simple classes only + GameMode.ADVENTURE, InventoryType.CHEST, DamageCause.FALL, + + // there is also at least one variable for each class on my test server which are tested whenever the server shuts down. + }; + for (Object o : random) + Classes.serialize(o); // includes a deserialisation test + } + +} diff --git a/src/test/java/org/skriptlang/skript/test/tests/classes/package-info.java b/src/test/java/org/skriptlang/skript/test/tests/classes/package-info.java new file mode 100644 index 00000000000..27c021a95b0 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/classes/package-info.java @@ -0,0 +1,24 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) +package org.skriptlang.skript.test.tests.classes; + +import org.eclipse.jdt.annotation.DefaultLocation; +import org.eclipse.jdt.annotation.NonNullByDefault; + diff --git a/src/test/java/org/skriptlang/skript/test/tests/config/NodeTest.java b/src/test/java/org/skriptlang/skript/test/tests/config/NodeTest.java new file mode 100644 index 00000000000..e24d28405f2 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/config/NodeTest.java @@ -0,0 +1,58 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package org.skriptlang.skript.test.tests.config; + +import static org.junit.Assert.assertArrayEquals; + +import org.junit.Test; + +import ch.njol.skript.config.Node; +import ch.njol.util.NonNullPair; + +public class NodeTest { + + @Test + public void splitLineTest() { + String[][] data = { + {"", "", ""}, + {"ab", "ab", ""}, + {"ab#", "ab", "#"}, + {"ab##", "ab#", ""}, + {"ab###", "ab#", "#"}, + {"#ab", "", "#ab"}, + {"ab#cd", "ab", "#cd"}, + {"ab##cd", "ab#cd", ""}, + {"ab###cd", "ab#", "#cd"}, + {"######", "###", ""}, + {"#######", "###", "#"}, + {"#### # ####", "## ", "# ####"}, + {"##### ####", "##", "# ####"}, + {"#### #####", "## ##", "#"}, + {"#########", "####", "#"}, + {"a##b#c##d#e", "a#b", "#c##d#e"}, + {" a ## b # c ## d # e ", " a # b ", "# c ## d # e "}, + }; + for (String[] d : data) { + NonNullPair p = Node.splitLine(d[0]); + assertArrayEquals(d[0], new String[] {d[1], d[2]}, new String[] {p.getFirst(), p.getSecond()}); + } + + } + +} diff --git a/src/test/java/org/skriptlang/skript/test/tests/config/package-info.java b/src/test/java/org/skriptlang/skript/test/tests/config/package-info.java new file mode 100644 index 00000000000..f32c2844ba2 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/config/package-info.java @@ -0,0 +1,24 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) +package org.skriptlang.skript.test.tests.config; + +import org.eclipse.jdt.annotation.DefaultLocation; +import org.eclipse.jdt.annotation.NonNullByDefault; + diff --git a/src/test/java/org/skriptlang/skript/test/tests/localization/NounTest.java b/src/test/java/org/skriptlang/skript/test/tests/localization/NounTest.java new file mode 100644 index 00000000000..0c9cd31de11 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/localization/NounTest.java @@ -0,0 +1,65 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package org.skriptlang.skript.test.tests.localization; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import ch.njol.skript.localization.Noun; +import ch.njol.util.NonNullPair; + +public class NounTest { + + @Test + public void testGetPlural() { + String[][] tests = { + {"a", "a", "a"}, + {"a¦b", "a", "ab"}, + {"a¦b¦c", "ab", "ac"}, + {"a¦b¦c¦d", "abd", "acd"}, + {"a¦b¦c¦d¦e", "abd", "acde"}, + {"a¦b¦c¦d¦e¦f", "abde", "acdf"}, + {"a¦b¦c¦d¦e¦f¦g", "abdeg", "acdfg"}, + }; + for (String[] test : tests) { + NonNullPair p = Noun.getPlural(test[0]); + assertEquals(test[1], p.getFirst()); + assertEquals(test[2], p.getSecond()); + } + } + + @Test + public void testNormalizePluralMarkers() { + String[][] tests = { + {"a", "a"}, + {"a¦b", "a¦¦b¦"}, + {"a¦b¦c", "a¦b¦c¦"}, + {"a¦b¦c¦d", "a¦b¦c¦d"}, + {"a¦b¦c¦d¦e", "a¦b¦c¦d¦¦e¦"}, + {"a¦b¦c¦d¦e¦f", "a¦b¦c¦d¦e¦f¦"}, + {"a¦b¦c¦d¦e¦f¦g", "a¦b¦c¦d¦e¦f¦g"}, + }; + for (String[] test : tests) { + assertEquals(test[1], Noun.normalizePluralMarkers(test[0])); + assertEquals(test[1] + "@x", Noun.normalizePluralMarkers(test[0] + "@x")); + } + } + +} diff --git a/src/test/java/org/skriptlang/skript/test/tests/localization/UtilsPlurals.java b/src/test/java/org/skriptlang/skript/test/tests/localization/UtilsPlurals.java new file mode 100644 index 00000000000..716f11e2d26 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/localization/UtilsPlurals.java @@ -0,0 +1,64 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package org.skriptlang.skript.test.tests.localization; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import ch.njol.skript.util.Utils; + +public class UtilsPlurals { + + /** + * Testing method {@link Utils#getEnglishPlural(String)} + */ + @Test + public void testPlural() { + String[][] strings = { + {"house", "houses"}, + {"cookie", "cookies"}, + {"creeper", "creepers"}, + {"cactus", "cacti"}, + {"rose", "roses"}, + {"dye", "dyes"}, + {"name", "names"}, + {"ingot", "ingots"}, + {"derp", "derps"}, + {"sheep", "sheep"}, + {"choir", "choirs"}, + {"man", "men"}, + {"child", "children"}, + {"hoe", "hoes"}, + {"toe", "toes"}, + {"hero", "heroes"}, + {"kidney", "kidneys"}, + {"anatomy", "anatomies"}, + {"axe", "axes"}, + {"elf", "elfs"}, + {"knife", "knives"}, + {"shelf", "shelfs"}, + }; + for (String[] s : strings) { + assertEquals(s[1], Utils.toEnglishPlural(s[0])); + assertEquals(s[0], Utils.getEnglishPlural(s[1]).getFirst()); + } + } + +} diff --git a/src/test/java/org/skriptlang/skript/test/tests/localization/package-info.java b/src/test/java/org/skriptlang/skript/test/tests/localization/package-info.java new file mode 100644 index 00000000000..bfc35002b56 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/localization/package-info.java @@ -0,0 +1,24 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) +package org.skriptlang.skript.test.tests.localization; + +import org.eclipse.jdt.annotation.DefaultLocation; +import org.eclipse.jdt.annotation.NonNullByDefault; + diff --git a/src/test/java/org/skriptlang/skript/test/tests/regression/SimpleJUnitTest.java b/src/test/java/org/skriptlang/skript/test/tests/regression/SimpleJUnitTest.java new file mode 100644 index 00000000000..0f8f78b33b7 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/regression/SimpleJUnitTest.java @@ -0,0 +1,68 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package org.skriptlang.skript.test.tests.regression; + +import org.bukkit.entity.Pig; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import ch.njol.skript.test.runner.SkriptJUnitTest; + +/** + * This class is a simple example JUnit. + * A piggy will spawn and get damaged by 100. + * The script under skript/tests/SimpleJUnitTest.sk will do all the assertion using the damage event. + * + * Methods exist in {@link ch.njol.skript.test.runner.SkriptJUnitTest} to simplify repetitive tasks. + */ +public class SimpleJUnitTest extends SkriptJUnitTest { + + private Pig piggy; + + /** + * In the static method of the class, you can utilize methods in SkriptJUnitTest that allow you + * to control how this JUnit test will interact with the server. + */ + static { + // Set the delay to 1 tick. This allows the piggy to be spawned into the world. + setShutdownDelay(1); + } + + @Before + @SuppressWarnings("deprecation") + public void spawnPig() { + piggy = spawnTestPig(); + piggy.setCustomName("Simple JUnit Test"); + } + + @Test + public void testDamage() { // Try to have more descriptive method names other than 'test()' + piggy.damage(100); + } + + @After + public void clearPiggy() { + // Remember to cleanup your test. This is an example method. + // Skript does clean up your JUnit test if it extends SkriptJUnitTest for; + // - Entities + // - Block (using getTestBlock) + } + +} diff --git a/src/test/java/org/skriptlang/skript/test/tests/regression/package-info.java b/src/test/java/org/skriptlang/skript/test/tests/regression/package-info.java new file mode 100644 index 00000000000..8225d91b19e --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/regression/package-info.java @@ -0,0 +1,24 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) +package org.skriptlang.skript.test.tests.regression; + +import org.eclipse.jdt.annotation.DefaultLocation; +import org.eclipse.jdt.annotation.NonNullByDefault; + diff --git a/src/test/java/org/skriptlang/skript/test/tests/syntaxes/package-info.java b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/package-info.java new file mode 100644 index 00000000000..1a7edcf6847 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/package-info.java @@ -0,0 +1,24 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) +package org.skriptlang.skript.test.tests.syntaxes; + +import org.eclipse.jdt.annotation.DefaultLocation; +import org.eclipse.jdt.annotation.NonNullByDefault; + diff --git a/src/test/java/org/skriptlang/skript/test/tests/utils/UtilsTest.java b/src/test/java/org/skriptlang/skript/test/tests/utils/UtilsTest.java new file mode 100644 index 00000000000..592ea5c9fa8 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/utils/UtilsTest.java @@ -0,0 +1,69 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package org.skriptlang.skript.test.tests.utils; + +import static org.junit.Assert.assertEquals; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.UnknownHostException; +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.junit.Test; + +import ch.njol.skript.util.Utils; + +/** + * Test methods from the Utils class. + */ +public class UtilsTest { + + /** + * Testing method {@link Utils#getSuperType(Class...)} + */ + @Test + public void testSuperClass() { + Class[][] classes = { + {Object.class, Object.class}, + {String.class, String.class}, + {String.class, Object.class, Object.class}, + {Object.class, String.class, Object.class}, + {String.class, String.class, String.class}, + {Object.class, String.class, Object.class, String.class, Object.class}, + {Double.class, Integer.class, Number.class}, + {UnknownHostException.class, FileNotFoundException.class, IOException.class}, + {SortedMap.class, TreeMap.class, SortedMap.class}, + {LinkedList.class, ArrayList.class, AbstractList.class}, + {List.class, Set.class, Collection.class}, + {ArrayList.class, Set.class, Collection.class}, + }; + for (Class[] cs : classes) { + assertEquals(cs[cs.length - 1], Utils.getSuperType(Arrays.copyOf(cs, cs.length - 1))); + } + } + +} diff --git a/src/test/java/org/skriptlang/skript/test/tests/utils/package-info.java b/src/test/java/org/skriptlang/skript/test/tests/utils/package-info.java new file mode 100644 index 00000000000..a02dc136ec8 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/utils/package-info.java @@ -0,0 +1,24 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD}) +package org.skriptlang.skript.test.tests.utils; + +import org.eclipse.jdt.annotation.DefaultLocation; +import org.eclipse.jdt.annotation.NonNullByDefault; + diff --git a/src/test/skript/README.md b/src/test/skript/README.md index 3955abe012a..77f80457f3e 100644 --- a/src/test/skript/README.md +++ b/src/test/skript/README.md @@ -78,9 +78,14 @@ Use Gradle to launch a test development server: gradlew clean skriptTestDev --console=plain ``` +Note: adding the tag `clean` will clear the build directory, making Skript generate a new server each time. +Don't include the `clean` tag if you want to keep the same server folder around each test. + The server launched will be running at localhost:25565. You can use console as normal, though there is some lag due to Gradle. If you're having trouble, try without --console=plain. +Server files are located at build/test_runners. + To run individual test files, use /sk test \. To run last used file again, just use /sk test. diff --git a/src/test/skript/tests/junit/README.md b/src/test/skript/tests/junit/README.md new file mode 100644 index 00000000000..029b1a5c184 --- /dev/null +++ b/src/test/skript/tests/junit/README.md @@ -0,0 +1,8 @@ +# JUnit testing system +This folder is for scripts that will load and be present for the Skript JUnit tests. +This allows a test to listen for events or persist during JUnit tests. + +An example would be checking the damage of an entity. You would write a test script +and have the on damage event inside that script with assertion checking. +Then in the JUnit Java class, you would perform some action that would damage the entity. +That test script then catches that event and any errors will be included in the final results. diff --git a/src/test/skript/tests/junit/SimpleJUnitTest.sk b/src/test/skript/tests/junit/SimpleJUnitTest.sk new file mode 100644 index 00000000000..25a048ae372 --- /dev/null +++ b/src/test/skript/tests/junit/SimpleJUnitTest.sk @@ -0,0 +1,16 @@ +on script load: + # Setup our objective for this script test to complete with the JUnit test. + ensure junit test "org.skriptlang.skript.test.tests.regression.SimpleJUnitTest" completes "piggy died" + +on damage of pig: + # Check that this is indeed our correct test to match with the JUnit test we want. + junit test is "org.skriptlang.skript.test.tests.regression.SimpleJUnitTest" + + # Using the JUnit name is not required, just another example. + assert custom name of victim is "Simple JUnit Test" with "piggy was not the same" + + # Remember the damage was 100 but Skript represents it by hearts so it's 50. + assert damage is 50 with "damage was not 50" + + # Tell our objective that our runtime objective has been completed which was an entity damage event. + complete objective "piggy died" for junit test "org.skriptlang.skript.test.tests.regression.SimpleJUnitTest"