Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,20 @@ jobs:

- name: Run tests
shell: bash
run: ./gradlew test --no-daemon --stacktrace
run: |
if [[ "${{ runner.os }}" == "Linux" ]]; then
./gradlew test jacocoTestReport --no-daemon --stacktrace
else
./gradlew test --no-daemon --stacktrace
fi

- name: Upload coverage to Coveralls
if: runner.os == 'Linux'
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
file: de.peeeq.wurstscript/build/reports/jacoco/test/jacocoTestReport.xml
format: jacoco

- name: Report test results
if: always()
Expand Down
17 changes: 10 additions & 7 deletions de.peeeq.wurstscript/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ plugins {
id 'idea'
id 'jacoco'
id 'maven-publish'
id 'com.github.kt3k.coveralls' version '2.12.2'
id 'com.gradleup.shadow' version '9.2.2'
id 'de.undercouch.download' version '5.6.0'
}
Expand Down Expand Up @@ -53,7 +52,16 @@ tasks.named("jacocoTestReport", JacocoReport) {

reports { xml.required.set(true) }

def excluded = ['**/ast/**', '**/jassAst/**', '**/jassIm/**', '**/luaAst/**', '**/antlr/**']
def excluded = [
'**/ast/**',
'**/jassAst/**',
'**/jassIm/**',
'**/luaAst/**',
'**/antlr/**',
'de/peeeq/wurstio/gui/**',
'de/peeeq/wurstio/AbortCompilationException.class',
'de/peeeq/wurstio/ModelChangedException.class'
]

classDirectories.setFrom(
files(classDirectories.files.collect { dir ->
Expand Down Expand Up @@ -473,10 +481,5 @@ tasks.register('create_zips') {
}
}

// TODO add a modern documentation generator replacement for the removed legacy hotdoc pipeline.
tasks.named("coveralls") {
notCompatibleWithConfigurationCache("coveralls plugin task uses Project at execution time")
}

/** -------- Apply deployment settings -------- */
apply from: 'deploy.gradle'
17 changes: 14 additions & 3 deletions de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/Checksums.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;


Expand Down Expand Up @@ -42,22 +44,31 @@ private static String printData(List<Data> data) {

private static List<Data> getData(File f) {
List<Data> result = new ArrayList<>();
for (File p : f.listFiles()) {
for (File p : sortedChildren(f)) {
getDataRec(result, "", p);
}
return result;
}

private static void getDataRec(List<Data> result, String path, File f) {
if (f.isDirectory()) {
for (File p : f.listFiles()) {
for (File p : sortedChildren(f)) {
getDataRec(result, path + "/" + f.getName(), p);
}
} else {
result.add(new Data(path + "/" + f.getName(), md5(f)));
}
}

private static File[] sortedChildren(File directory) {
File[] children = directory.listFiles();
if (children == null) {
throw new IllegalArgumentException("Cannot list directory " + directory);
}
Arrays.sort(children, Comparator.comparing(File::getName));
return children;
}

// stolen from http://stackoverflow.com/a/304350/303637
private static String md5(File f) {
try {
Expand Down Expand Up @@ -98,4 +109,4 @@ public Data(String filePath, String md5) {
this.filePath = filePath;
this.md5 = md5;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,21 @@
import java.util.function.Consumer;

public class WurstServer {
private static final int portNumber = 27425;
private static final int DEFAULT_PORT = 27425;

private final int portNumber;
private volatile boolean stopped;
private Consumer<String> printer = System.out::println;
private @Nullable ServerSocket serverSocket;

public WurstServer() {
this(DEFAULT_PORT);
}

WurstServer(int portNumber) {
this.portNumber = portNumber;
}

public void start() {
try (ServerSocket serverSocket = new ServerSocket(portNumber, 1, InetAddress.getLoopbackAddress())) {
this.serverSocket = serverSocket;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public RunArgs(String... args) {
optionExtractImports = addOptionWithArg("-extractImports", "Extract all files from a map into a folder next to the mapp.", arg -> mapFile = arg);
optionExportObjects = addOptionWithArg("exportobjects", "Export object editor data from a map file or map folder to Wurst source.", arg -> exportObjectsFile = arg);
addOptionWithArg("exportobjectsOut", "Output folder for -exportobjects.", arg -> exportObjectsOut = arg);
optionShowVersion = addOption("-version", "Shows the version of the compiler");
optionShowVersion = addOption("version", "Shows the version of the compiler");

// other
optionNoExtractMapScript = addOption("noExtractMapScript", "Do not extract the map script from the map and use the one from the Wurst folder instead.");
Expand Down
38 changes: 38 additions & 0 deletions de.peeeq.wurstscript/src/test/java/de/peeeq/wurstio/MainTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package de.peeeq.wurstio;

import de.peeeq.wurstscript.CompileTimeInfo;
import org.testng.annotations.Test;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;

public class MainTests {

@Test
public void noArgumentsReturnsWithoutStartingInteractiveComponents() {
String output = captureStdout(() -> Main.main(new String[0]));
assertTrue(output.contains("Usage:"));
}

@Test
public void versionPrintsCompilerVersion() {
String output = captureStdout(() -> Main.main(new String[]{"-version"}));
assertEquals(output.trim(), CompileTimeInfo.version);
}

private String captureStdout(Runnable action) {
PrintStream previousOut = System.out;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
System.setOut(new PrintStream(output, true, StandardCharsets.UTF_8));
action.run();
} finally {
System.setOut(previousOut);
}
return output.toString(StandardCharsets.UTF_8);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package de.peeeq.wurstio.compilationserver;

import org.testng.annotations.Test;

import java.util.ArrayList;
import java.util.List;

import static org.testng.Assert.assertEquals;

public class WurstServerTests {

@Test
public void stoppedServerCanStartAndExitWithoutAcceptingRequests() {
WurstServer server = new WurstServer(0);
List<String> messages = new ArrayList<>();
server.setPrinter(messages::add);

server.stop();
server.start();

assertEquals(messages, List.of("Server started.", "Server stopped."));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package de.peeeq.wurstio.map.importer;

import de.peeeq.wurstio.mpq.MpqEditor;
import de.peeeq.wurstio.utils.FileUtils;
import net.moonlightflower.wc3libs.bin.app.IMP;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;

public class ImportFileTests {
private static final String MANIFEST_PATH = "wurst_cache_manifest.txt";

private Path tempDir;

@AfterMethod(alwaysRun = true)
public void cleanup() throws IOException {
if (tempDir != null) {
FileUtils.deleteRecursively(tempDir.toFile());
}
}

@Test
public void hashesBytesAndFilesWithMd5() throws Exception {
byte[] content = "abc".getBytes(StandardCharsets.UTF_8);
assertEquals(ImportFile.calculateHash(content), "900150983cd24fb0d6963f7d28e17f72");

tempDir = Files.createTempDirectory("wurst-import-hash");
Path file = Files.write(tempDir.resolve("value.bin"), content);
assertEquals(ImportFile.calculateFileHash(file.toFile()), "900150983cd24fb0d6963f7d28e17f72");
}

@Test
public void manifestRoundTripPreservesConfigsAndImports() {
ImportFile.CacheManifest manifest = new ImportFile.CacheManifest();
manifest.setW3iConfig("w3i-hash");
manifest.setMapConfig("map-hash");
manifest.importFiles.put("models\\unit.mdx",
new ImportFile.CacheManifest.FileEntry("file-hash", 123L));

ImportFile.CacheManifest restored = ImportFile.CacheManifest.deserialize(manifest.serialize());

assertTrue(restored.hasW3iConfig());
assertTrue(restored.hasMapConfig());
assertTrue(restored.w3iConfigMatches("w3i-hash"));
assertTrue(restored.mapConfigMatches("map-hash"));
assertEquals(restored.importFiles.get("models\\unit.mdx").hash, "file-hash");
assertEquals(restored.importFiles.get("models\\unit.mdx").lastModified, 123L);
}

@Test
public void malformedManifestLinesAreIgnored() {
ImportFile.CacheManifest restored = ImportFile.CacheManifest.deserialize(
"# comment\ninvalid\nIMPORT|bad|hash|not-a-number\nUNKNOWN|path|hash|1\n");

assertFalse(restored.hasW3iConfig());
assertFalse(restored.hasMapConfig());
assertTrue(restored.importFiles.isEmpty());
}

@Test
public void manifestStorageUsesMpqCacheFile() {
FakeMpqEditor mpq = new FakeMpqEditor();
ImportFile.CacheManifest manifest = new ImportFile.CacheManifest();
manifest.setMapConfig("map-hash");

ImportFile.saveManifest(mpq, manifest);
assertTrue(ImportFile.getCachedManifest(mpq).orElseThrow().mapConfigMatches("map-hash"));

ImportFile.invalidateCache(mpq);
assertTrue(ImportFile.getCachedManifest(mpq).isEmpty());
}

@Test
public void cachedImportUpdatesAndDeletesOnlyChangedFiles() throws Exception {
tempDir = Files.createTempDirectory("wurst-import-cache");
Path imports = Files.createDirectories(tempDir.resolve("imports").resolve("nested"));
Path source = Files.writeString(imports.resolve("unit.txt"), "abc", StandardCharsets.UTF_8);
FakeMpqEditor mpq = new FakeMpqEditor();

ImportFile.ImportResult first = ImportFile.importFilesFromImports(tempDir.toFile(), mpq);
assertEquals(first.filesProcessed, 1);
assertEquals(first.filesUpdated, 1);
assertEquals(first.filesDeleted, 0);
assertFalse(first.cacheUsed);
assertTrue(mpq.hasFile("nested\\unit.txt"));
assertTrue(mpq.hasFile(IMP.GAME_PATH));
assertTrue(mpq.hasFile(MANIFEST_PATH));

ImportFile.ImportResult cached = ImportFile.importFilesFromImports(tempDir.toFile(), mpq);
assertEquals(cached.filesProcessed, 1);
assertEquals(cached.filesUpdated, 0);
assertEquals(cached.filesDeleted, 0);
assertTrue(cached.cacheUsed);

Files.delete(source);
ImportFile.ImportResult deleted = ImportFile.importFilesFromImports(tempDir.toFile(), mpq);
assertEquals(deleted.filesProcessed, 0);
assertEquals(deleted.filesUpdated, 0);
assertEquals(deleted.filesDeleted, 1);
assertFalse(deleted.cacheUsed);
assertFalse(mpq.hasFile("nested\\unit.txt"));
}

private static final class FakeMpqEditor implements MpqEditor {
private final Map<String, byte[]> files = new HashMap<>();

@Override
public boolean canWrite() {
return true;
}

@Override
public byte[] extractFile(String fileToExtract) throws IOException {
byte[] result = files.get(fileToExtract);
if (result == null) {
throw new IOException("Missing " + fileToExtract);
}
return result;
}

@Override
public void insertFile(String filenameInMpq, byte[] contents) {
files.put(filenameInMpq, contents);
}

@Override
public void insertFile(String filenameInMpq, File contents) throws IOException {
files.put(filenameInMpq, Files.readAllBytes(contents.toPath()));
}

@Override
public void deleteFile(String filenameInMpq) {
files.remove(filenameInMpq);
}

@Override
public boolean hasFile(String fileName) {
return files.containsKey(fileName);
}

@Override
public void setKeepHeaderOffset(boolean flag) {
}

@Override
public void closeWithCompression() {
}

@Override
public void close() {
}
}
}
Loading
Loading