Skip to content

Commit afde0d8

Browse files
committed
initial test work --- trying it out, this will fail im sure
1 parent e0bbefd commit afde0d8

13 files changed

Lines changed: 493 additions & 13 deletions

File tree

.github/workflows/gradle.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
66
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
77

8-
name: Java CI with Gradle
8+
name: Build, Test, and Upload Artifact
99

1010
on:
1111
push:
@@ -38,3 +38,5 @@ jobs:
3838
name: HySkript-Artifact
3939
# A file, directory or wildcard pattern that describes what to upload
4040
path: build/libs/HySkript-*.jar
41+
- name: Run Tests
42+
run: ./gradlew testRunner

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,6 @@ bin/
4343
### Mac OS ###
4444
.DS_Store
4545
**/.DS_Store
46+
47+
### Run Folder ###
48+
run/

build.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ tasks {
4242
destinationDir = file("/Users/ShaneBee/Desktop/Server/Hytale/Creative/mods/")
4343
}
4444
}
45+
register<JavaExec>("testRunner") {
46+
dependsOn("jar")
47+
group = "application"
48+
description = "Runs the test runner"
49+
mainClass.set("com.github.skriptdev.skript.api.skript.testing.TestRunner")
50+
classpath = sourceSets["main"].runtimeClasspath
51+
}
4552
processResources {
4653
filesNotMatching("assets/**") {
4754
expand("pluginVersion" to projectVersion, "hytaleVersion" to hytaleVersion)
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.github.skriptdev.skript.api.skript.testing;
2+
3+
import com.github.skriptdev.skript.plugin.HySk;
4+
5+
import java.io.IOException;
6+
import java.io.OutputStreamWriter;
7+
import java.nio.charset.StandardCharsets;
8+
import java.nio.file.Files;
9+
import java.nio.file.Path;
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
import java.util.Properties;
13+
14+
public class TestResults {
15+
16+
private boolean success = true;
17+
private final Map<String, String> successMap = new HashMap<>();
18+
private final Map<String, String> failureMap = new HashMap<>();
19+
20+
public boolean isSuccess() {
21+
return success;
22+
}
23+
24+
public Map<String, String> getSuccessMap() {
25+
return successMap;
26+
}
27+
28+
public Map<String, String> getFailureMap() {
29+
return failureMap;
30+
}
31+
32+
public void addSuccess(String test, String value) {
33+
this.successMap.put(test, value);
34+
}
35+
36+
public void addFailure(String test, String value) {
37+
this.success = false;
38+
this.failureMap.put(test, value);
39+
}
40+
41+
@SuppressWarnings({"ResultOfMethodCallIgnored", "CallToPrintStackTrace"})
42+
public void printToJsonFile() {
43+
Path resolve = HySk.getInstance().getDataDirectory().resolve("test-results.properties");
44+
try {
45+
Files.createDirectories(resolve.getParent());
46+
} catch (IOException e) {
47+
throw new RuntimeException("Failed to create directories for " + resolve.toAbsolutePath(), e);
48+
}
49+
50+
Properties props = new Properties();
51+
props.setProperty("success", Boolean.toString(this.success));
52+
props.setProperty("success.count", Integer.toString(this.successMap.size()));
53+
props.setProperty("failure.count", Integer.toString(this.failureMap.size()));
54+
55+
// Store individual entries (handy for debugging in CI logs)
56+
for (var e : successMap.entrySet()) {
57+
props.setProperty("success." + e.getKey(), e.getValue());
58+
}
59+
for (var e : failureMap.entrySet()) {
60+
props.setProperty("failure." + e.getKey(), e.getValue());
61+
}
62+
63+
try (var out = new OutputStreamWriter(Files.newOutputStream(resolve), StandardCharsets.UTF_8)) {
64+
props.store(out, "HySkript test results");
65+
System.out.println("Test-Results successfully written to " + resolve.toAbsolutePath());
66+
} catch (Exception e) {
67+
e.printStackTrace();
68+
}
69+
}
70+
71+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package com.github.skriptdev.skript.api.skript.testing;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.net.URI;
6+
import java.net.http.HttpClient;
7+
import java.net.http.HttpRequest;
8+
import java.net.http.HttpResponse;
9+
import java.nio.charset.StandardCharsets;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
12+
import java.nio.file.Paths;
13+
import java.nio.file.StandardCopyOption;
14+
import java.util.Properties;
15+
16+
public class TestRunner {
17+
18+
static void main(String[] args) {
19+
System.out.println("Downloading Hytale Server...");
20+
downloadHytaleServer();
21+
System.out.println("Download complete!");
22+
23+
// move plugin to mods file
24+
System.out.println("Moving plugin to mods folder...");
25+
movePlugin();
26+
System.out.println("Plugin moved!");
27+
28+
// set system property for testing
29+
System.out.println("Starting server...");
30+
runServer();
31+
System.out.println("Server started!");
32+
}
33+
34+
private static void downloadHytaleServer() {
35+
String url = "https://maven.hytale.com/release/com/hypixel/hytale/Server" +
36+
"/2026.02.06-aa1b071c2/Server-2026.02.06-aa1b071c2.jar"; // TODO replace with gradle replace
37+
String targetDir = "run/testServer/";
38+
String newName = "HytaleServer.jar";
39+
40+
try {
41+
// 1. Create the directory if it doesn't exist
42+
Path directoryPath = Paths.get(targetDir);
43+
if (!Files.exists(directoryPath)) {
44+
Files.createDirectories(directoryPath);
45+
}
46+
47+
// 2. Download the file to a temporary location
48+
HttpClient client = HttpClient.newHttpClient();
49+
HttpRequest request = HttpRequest.newBuilder()
50+
.uri(URI.create(url))
51+
.build();
52+
53+
// We download directly to a path to save memory
54+
Path tempFile = Files.createTempFile("tempDownload", ".tmp");
55+
client.send(request, HttpResponse.BodyHandlers.ofFile(tempFile));
56+
57+
// 3. Move and Rename the file
58+
Path finalPath = directoryPath.resolve(newName);
59+
Files.move(tempFile, finalPath, StandardCopyOption.REPLACE_EXISTING);
60+
61+
System.out.println("File saved to: " + finalPath.toAbsolutePath());
62+
63+
} catch (IOException | InterruptedException e) {
64+
e.printStackTrace();
65+
}
66+
}
67+
68+
private static void movePlugin() {
69+
File file = new File("run/testServer/mods");
70+
file.mkdirs();
71+
try {
72+
Files.copy(Path.of("build/libs/HySkript-1.0.0-pre-release-3.jar"),
73+
Path.of("run/testServer/mods/HySkript-1.0.0-pre-release-3.jar"),
74+
StandardCopyOption.REPLACE_EXISTING);
75+
} catch (IOException e) {
76+
throw new RuntimeException(e);
77+
}
78+
}
79+
80+
private static void runServer() {
81+
try {
82+
File serverFolder = new File("run/testServer/");
83+
ProcessBuilder processBuilder = new ProcessBuilder(
84+
"java",
85+
"-Xms2G",
86+
"-Xmx2G",
87+
"-jar", "HytaleServer.jar",
88+
"--assets", "/Users/ShaneBee/Desktop/Server/Hytale/Assets/Assets.zip"
89+
);
90+
processBuilder.inheritIO();
91+
processBuilder.directory(serverFolder);
92+
Process process = processBuilder.start();
93+
int exitCode = process.waitFor();
94+
95+
// Read results written by the plugin (no Gson required).
96+
Path resultsPath = Path.of("run/testServer/mods/skript_HySkript/test-results.properties");
97+
if (!Files.exists(resultsPath)) {
98+
throw new IllegalStateException(
99+
"Test results file not found at " + resultsPath.toAbsolutePath() +
100+
" (server exit code was " + exitCode + ")"
101+
);
102+
}
103+
104+
Properties props = new Properties();
105+
try (var reader = Files.newBufferedReader(resultsPath, StandardCharsets.UTF_8)) {
106+
props.load(reader);
107+
}
108+
109+
int failureCount = Integer.parseInt(props.getProperty("failure.count", "0"));
110+
111+
System.out.println("Exited with code " + failureCount);
112+
System.exit(failureCount);
113+
} catch (IOException | InterruptedException e) {
114+
e.printStackTrace();
115+
}
116+
}
117+
118+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package com.github.skriptdev.skript.api.skript.testing;
2+
3+
import com.github.skriptdev.skript.api.skript.testing.elements.EvtTest.TestContext;
4+
import com.github.skriptdev.skript.api.utils.Utils;
5+
import com.github.skriptdev.skript.plugin.Skript;
6+
import com.hypixel.hytale.server.core.HytaleServer;
7+
import com.hypixel.hytale.server.core.Message;
8+
import com.hypixel.hytale.server.core.universe.Universe;
9+
import com.hypixel.hytale.server.core.universe.world.World;
10+
import com.hypixel.hytale.server.core.util.MessageUtil;
11+
import fi.sulku.hytale.TinyMsg;
12+
import io.github.syst3ms.skriptparser.lang.TriggerMap;
13+
import io.github.syst3ms.skriptparser.log.LogEntry;
14+
import io.github.syst3ms.skriptparser.parsing.ScriptLoader;
15+
16+
import java.io.File;
17+
import java.nio.file.Path;
18+
import java.util.ArrayList;
19+
import java.util.Arrays;
20+
import java.util.Comparator;
21+
import java.util.List;
22+
import java.util.concurrent.TimeUnit;
23+
24+
public class TestingThingy {
25+
26+
private static Skript skript;
27+
28+
@SuppressWarnings("DataFlowIssue")
29+
public static void start(Skript skript) {
30+
TestingThingy.skript = skript;
31+
32+
Runnable runTestsInWorld = () -> {
33+
Utils.log("Running tests in world 'default'...");
34+
runTests();
35+
Utils.log("Finished running tests!");
36+
};
37+
Runnable loadTestsRunnable = () -> {
38+
Utils.log("Loading test scripts...");
39+
loadTests();
40+
Utils.log("Finished loading test scripts!");
41+
World world = Universe.get().getWorld("default");
42+
if (world.isPaused()) world.setPaused(false);
43+
44+
world.execute(runTestsInWorld);
45+
};
46+
HytaleServer.SCHEDULED_EXECUTOR.schedule(loadTestsRunnable, 2, TimeUnit.SECONDS);
47+
}
48+
49+
private static void loadTests() {
50+
Path path = Path.of("/Users/ShaneBee/IdeaProjects/HySkript/HySkript/src/test/skript/tests");
51+
loadScripts(path);
52+
}
53+
54+
private static void runTests() {
55+
56+
TestResults testResults = new TestResults();
57+
58+
TestContext testContext = new TestContext(testResults);
59+
TriggerMap.callTriggersByContext(testContext);
60+
61+
if (testResults.isSuccess()) {
62+
Message message = TinyMsg.parse("<green>All tests passed!");
63+
Utils.log(MessageUtil.toAnsiString(message).toAnsi());
64+
} else {
65+
Utils.error("Some tests failed!");
66+
}
67+
68+
testResults.printToJsonFile();
69+
70+
// Figure out how to fail the build on GitHub
71+
Runnable shutdownServer = () -> HytaleServer.get().shutdownServer();
72+
HytaleServer.SCHEDULED_EXECUTOR.schedule(shutdownServer, 5, TimeUnit.SECONDS);
73+
}
74+
75+
private static void loadScripts(Path directory) {
76+
File scriptsDirectory = directory.toFile();
77+
Utils.log("Loading test directory '" + scriptsDirectory.getAbsolutePath() + "'...");
78+
List<String> scriptNames = loadScriptsInDirectory(scriptsDirectory);
79+
Utils.log("Loaded " + scriptNames.size() + " scripts!");
80+
}
81+
82+
private static List<String> loadScriptsInDirectory(File directory) {
83+
if (directory == null || !directory.isDirectory()) return List.of();
84+
85+
List<String> loadedScripts = new ArrayList<>();
86+
87+
File[] files = directory.listFiles();
88+
if (files == null) return loadedScripts;
89+
90+
Arrays.sort(files,
91+
Comparator.comparing(File::isDirectory).reversed() // Directories first
92+
.thenComparing(File::getName, String.CASE_INSENSITIVE_ORDER)); // Then sort by name alphabetically
93+
94+
for (File file : files) {
95+
// Skip disabled files and hidden files
96+
String fileName = file.getName();
97+
if (fileName.startsWith("-") || fileName.startsWith(".")) continue;
98+
if (file.isDirectory()) {
99+
loadedScripts.addAll(loadScriptsInDirectory(file));
100+
} else {
101+
if (!fileName.endsWith(".sk")) continue;
102+
Utils.log("Loading script '" + fileName + "'...");
103+
List<LogEntry> logEntries = ScriptLoader.loadScript(file.toPath(), false);
104+
for (LogEntry logEntry : logEntries) {
105+
Utils.log(null, logEntry);
106+
}
107+
loadedScripts.add(fileName.substring(0, fileName.length() - 3));
108+
}
109+
}
110+
return loadedScripts;
111+
}
112+
113+
}

0 commit comments

Comments
 (0)