Add proper testing environment
This commit is contained in:
parent
e693b7254a
commit
629ca9d2d9
12 changed files with 395 additions and 35 deletions
|
@ -35,8 +35,6 @@ dependencies {
|
|||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
workingDir = "build"
|
||||
testLogging.showStandardStreams = true
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.mcphackers.launchwrapper.util.OS;
|
|||
|
||||
public class LaunchConfig {
|
||||
private static final File defaultGameDir = getDefaultGameDir();
|
||||
//TODO allow arbitary parameters instead of the ones documented below
|
||||
private Map<String, LaunchParameter<?>> parameters = new HashMap<String, LaunchParameter<?>>();
|
||||
|
||||
public LaunchParameterSwitch demo = new LaunchParameterSwitch("demo", false);
|
||||
|
@ -107,6 +106,7 @@ public class LaunchConfig {
|
|||
if(args[i].startsWith("--")) {
|
||||
String paramName = args[i].substring(2);
|
||||
LaunchParameter<?> param = parameters.get(paramName.toLowerCase(Locale.ENGLISH));
|
||||
//TODO allow arbitary parameter names instead of ignoring them
|
||||
if(param == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -116,21 +116,24 @@ public class LaunchConfig {
|
|||
}
|
||||
if(i + 1 < args.length) {
|
||||
try {
|
||||
// TODO better handling for alternative parameter names
|
||||
if(param.equals(session)) {
|
||||
sessionid.set(args[i + 1]);
|
||||
}
|
||||
if(param.equals(sessionid)) {
|
||||
session.set(args[i + 1]);
|
||||
}
|
||||
if(param.equals(gameDir)) {
|
||||
workDir.set(new File(args[i + 1]));
|
||||
}
|
||||
if(param.equals(workDir)) {
|
||||
gameDir.set(new File(args[i + 1]));
|
||||
}
|
||||
param.setString(args[i + 1]);
|
||||
i++;
|
||||
// TODO better handling for alternative parameter names
|
||||
if(param.equals(gameDir) && assetsDir.get() == null) {
|
||||
assetsDir.set(new File(gameDir.get(), "assets"));
|
||||
}
|
||||
else if(param.equals(session)) {
|
||||
sessionid.set(session.get());
|
||||
}
|
||||
else if(param.equals(sessionid)) {
|
||||
session.set(sessionid.get());
|
||||
}
|
||||
else if(param.equals(gameDir)) {
|
||||
workDir.set(gameDir.get());
|
||||
}
|
||||
else if(param.equals(workDir)) {
|
||||
gameDir.set(workDir.get());
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -303,12 +303,4 @@ public class LaunchClassLoader extends URLClassLoader implements ClassNodeSource
|
|||
return INSTANCE = new LaunchClassLoader(getSystemClassLoader());
|
||||
}
|
||||
|
||||
public URL getLocation(String className) {
|
||||
try {
|
||||
return loadClass(className).getProtectionDomain().getCodeSource().getLocation();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.mcphackers.launchwrapper.tweak;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.mcphackers.launchwrapper.LaunchConfig;
|
||||
|
@ -76,6 +77,10 @@ public abstract class Tweak {
|
|||
return null; // Tweak not found
|
||||
}
|
||||
|
||||
public List<FeatureInfo> getTweakInfo() {
|
||||
return Collections.unmodifiableList(features);
|
||||
}
|
||||
|
||||
protected void tweakInfo(String name, String... extra) {
|
||||
features.add(new FeatureInfo(name));
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.mcphackers.launchwrapper.util;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
@ -15,7 +13,5 @@ public interface ClassNodeSource {
|
|||
MethodNode getMethod(String owner, String name, String desc);
|
||||
|
||||
void overrideClass(ClassNode node);
|
||||
|
||||
URL getLocation(String className);
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.io.ByteArrayOutputStream;
|
|||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
@ -38,6 +39,16 @@ public final class Util {
|
|||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
public static void copyStream(InputStream stream1, OutputStream stream2) throws IOException {
|
||||
int nRead;
|
||||
byte[] data = new byte[16384];
|
||||
|
||||
while((nRead = stream1.read(data, 0, data.length)) != -1) {
|
||||
stream2.write(data, 0, nRead);
|
||||
}
|
||||
stream1.close();
|
||||
}
|
||||
|
||||
public static URL replaceHost(URL url, String hostName, int port) {
|
||||
try {
|
||||
return new URL(url.getProtocol(), hostName, port, url.getFile());
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package org.mcphackers.launchwrapper.test;
|
||||
|
||||
import org.mcphackers.launchwrapper.LaunchConfig;
|
||||
import org.mcphackers.launchwrapper.tweak.LegacyTweak;
|
||||
import org.mcphackers.launchwrapper.tweak.Tweak;
|
||||
import org.mcphackers.launchwrapper.util.ClassNodeSource;
|
||||
|
||||
public class BetaTest extends TweakTest {
|
||||
|
||||
@Override
|
||||
protected String jarName() {
|
||||
return "b1.1_02.jar";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String jarUrl() {
|
||||
return "https://launcher.mojang.com/v1/objects/e1c682219df45ebda589a557aadadd6ed093c86c/client.jar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tweak getTweak(ClassNodeSource source, LaunchConfig config) {
|
||||
return new LegacyTweak(source, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestFeatureBuilder getTests() {
|
||||
return new TestFeatureBuilder()
|
||||
.tweakInfoList("Set default width and height", "Fullscreen init patch", "Fullscreen toggle patch",
|
||||
"Replaced icon", "MouseHelper fix", "Replaced fullscreen", "Replaced width",
|
||||
"Replaced height", "Splash fix", "Shutdown patch", "SoundManager shutdown",
|
||||
"Options load fix", "Replaced canvas getWidth", "Replaced canvas getHeight",
|
||||
"Replaced title", "Replaced gameDir", "Removed canvas null check", "Added main");
|
||||
}
|
||||
}
|
|
@ -1,13 +1,32 @@
|
|||
package org.mcphackers.launchwrapper.test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mcphackers.launchwrapper.LaunchConfig;
|
||||
import org.mcphackers.launchwrapper.tweak.LegacyTweak;
|
||||
import org.mcphackers.launchwrapper.tweak.Tweak;
|
||||
import org.mcphackers.launchwrapper.util.ClassNodeSource;
|
||||
|
||||
public class ClassicTest extends TweakTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(new File(".").getAbsolutePath());
|
||||
@Override
|
||||
protected String jarName() {
|
||||
return "c0.30_01c.jar";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String jarUrl() {
|
||||
return "https://launcher.mojang.com/v1/objects/54622801f5ef1bcc1549a842c5b04cb5d5583005/client.jar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tweak getTweak(ClassNodeSource source, LaunchConfig config) {
|
||||
return new LegacyTweak(source, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestFeatureBuilder getTests() {
|
||||
return new TestFeatureBuilder()
|
||||
.tweakInfoList("Shutdown patch", "Replaced gameDir", "Replaced title", "Replaced icon",
|
||||
"Fullscreen init patch", "Replaced fullscreen", "Replaced width", "Replaced height",
|
||||
"Set fullscreen", "Added main");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
package org.mcphackers.launchwrapper.test;
|
||||
|
||||
import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.mcphackers.launchwrapper.util.ClassNodeSource;
|
||||
import org.mcphackers.rdi.util.NodeHelper;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class FileClassNodeSource implements ClassNodeSource, Closeable {
|
||||
private final ZipFile source;
|
||||
private Map<String, ClassNode> classNodeCache = new HashMap<String, ClassNode>();
|
||||
private File debugOutput;
|
||||
|
||||
public FileClassNodeSource(File jarFile) throws ZipException, IOException {
|
||||
source = new ZipFile(jarFile);
|
||||
}
|
||||
|
||||
public void setDebugOutput(File directory) {
|
||||
debugOutput = directory;
|
||||
}
|
||||
|
||||
private void saveDebugClass(ClassNode node) {
|
||||
if(debugOutput == null) {
|
||||
return;
|
||||
}
|
||||
ClassWriter writer = new ClassWriter(COMPUTE_MAXS);
|
||||
node.accept(writer);
|
||||
byte[] classData = writer.toByteArray();
|
||||
File cls = new File(debugOutput, node.name + ".class");
|
||||
cls.getParentFile().mkdirs();
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(cls);
|
||||
fos.write(classData);
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static String classNodeName(String nameWithDots) {
|
||||
return nameWithDots.replace('.', '/');
|
||||
}
|
||||
|
||||
private static String classResourceName(String name) {
|
||||
return name.replace('.', '/') + ".class";
|
||||
}
|
||||
|
||||
private InputStream getClassAsStream(String name) throws IOException {
|
||||
String className = classResourceName(name);
|
||||
ZipEntry entry = source.getEntry(className);
|
||||
if(entry == null) {
|
||||
return null;
|
||||
}
|
||||
InputStream is = source.getInputStream(entry);
|
||||
if(is != null) {
|
||||
return is;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ClassNode getClass(String name) {
|
||||
ClassNode node = classNodeCache.get(classNodeName(name));
|
||||
if(node != null) {
|
||||
return node;
|
||||
}
|
||||
try {
|
||||
InputStream is = getClassAsStream(name);
|
||||
if(is == null) {
|
||||
return null;
|
||||
}
|
||||
ClassNode classNode = new ClassNode();
|
||||
ClassReader classReader = new ClassReader(is);
|
||||
classReader.accept(classNode, 0);
|
||||
classNodeCache.put(classNode.name, classNode);
|
||||
return classNode;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public FieldNode getField(String owner, String name, String desc) {
|
||||
return NodeHelper.getField(getClass(owner), name, desc);
|
||||
}
|
||||
|
||||
public MethodNode getMethod(String owner, String name, String desc) {
|
||||
return NodeHelper.getMethod(getClass(owner), name, desc);
|
||||
}
|
||||
|
||||
public void overrideClass(ClassNode node) {
|
||||
saveDebugClass(node);
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
source.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package org.mcphackers.launchwrapper.test;
|
||||
|
||||
import org.mcphackers.launchwrapper.LaunchConfig;
|
||||
import org.mcphackers.launchwrapper.tweak.LegacyTweak;
|
||||
import org.mcphackers.launchwrapper.tweak.Tweak;
|
||||
import org.mcphackers.launchwrapper.util.ClassNodeSource;
|
||||
|
||||
public class InfdevTest extends TweakTest {
|
||||
|
||||
@Override
|
||||
protected String jarName() {
|
||||
return "inf-20100630-2.jar";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String jarUrl() {
|
||||
return "http://files.betacraft.uk/launcher/assets/versions/inf-20100630-2.jar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tweak getTweak(ClassNodeSource source, LaunchConfig config) {
|
||||
return new LegacyTweak(source, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestFeatureBuilder getTests() {
|
||||
return new TestFeatureBuilder()
|
||||
.tweakInfoList("Set default width and height", "Fullscreen init patch", "Fullscreen toggle patch",
|
||||
"Replaced icon", "MouseHelper fix", "Replaced fullscreen", "Replaced width",
|
||||
"Replaced height", "Shutdown patch", "SoundManager shutdown",
|
||||
"Options load fix", "Replaced canvas getWidth", "Replaced canvas getHeight",
|
||||
"Replaced title", "Replaced gameDir", "Removed canvas null check", "Set fullscreen",
|
||||
"Set default width and height", "Added main");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package org.mcphackers.launchwrapper.test;
|
||||
|
||||
import org.mcphackers.launchwrapper.LaunchConfig;
|
||||
import org.mcphackers.launchwrapper.tweak.Tweak;
|
||||
import org.mcphackers.launchwrapper.tweak.VanillaTweak;
|
||||
import org.mcphackers.launchwrapper.util.ClassNodeSource;
|
||||
|
||||
public class ReleaseTest extends TweakTest {
|
||||
|
||||
@Override
|
||||
protected String jarName() {
|
||||
return "1.12.2.jar";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String jarUrl() {
|
||||
return "https://piston-data.mojang.com/v1/objects/0f275bc1547d01fa5f56ba34bdc87d981ee12daf/client.jar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tweak getTweak(ClassNodeSource source, LaunchConfig config) {
|
||||
return new VanillaTweak(source, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestFeatureBuilder getTests() {
|
||||
return new TestFeatureBuilder()
|
||||
.tweakInfoList("Minecraft.run()", "Replaced title", "Replaced icon");
|
||||
}
|
||||
}
|
|
@ -1,7 +1,132 @@
|
|||
package org.mcphackers.launchwrapper.test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mcphackers.launchwrapper.LaunchConfig;
|
||||
import org.mcphackers.launchwrapper.tweak.FeatureInfo;
|
||||
import org.mcphackers.launchwrapper.tweak.Tweak;
|
||||
import org.mcphackers.launchwrapper.util.ClassNodeSource;
|
||||
import org.mcphackers.launchwrapper.util.Util;
|
||||
|
||||
public abstract class TweakTest {
|
||||
|
||||
public void testFramePatch() {
|
||||
@Test
|
||||
public void test() {
|
||||
try {
|
||||
File testDir = new File("build/test/");
|
||||
File gameJar = new File(testDir, jarName());
|
||||
downloadMinecraftJar(
|
||||
jarUrl(),
|
||||
gameJar);
|
||||
FileClassNodeSource classNodeSource = new FileClassNodeSource(gameJar);
|
||||
LaunchConfig config = getDefaultConfig(testDir);
|
||||
Tweak tweak = getTweak(classNodeSource, config);
|
||||
assertTrue(tweak.transform());
|
||||
for (FeatureInfo info : tweak.getTweakInfo()) {
|
||||
System.out.println(info.feature);
|
||||
}
|
||||
featureTest(tweak, getTests());
|
||||
} catch (Throwable e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract String jarName();
|
||||
|
||||
protected abstract String jarUrl();
|
||||
|
||||
public abstract Tweak getTweak(ClassNodeSource source, LaunchConfig config);
|
||||
|
||||
public abstract TestFeatureBuilder getTests();
|
||||
|
||||
protected final void downloadMinecraftJar(String url, File outFile) throws IOException {
|
||||
if (outFile.exists()) {
|
||||
return;
|
||||
}
|
||||
outFile.getParentFile().mkdirs();
|
||||
InputStream is = new URL(url).openStream();
|
||||
FileOutputStream fos = new FileOutputStream(outFile);
|
||||
Util.copyStream(is, fos);
|
||||
is.close();
|
||||
fos.close();
|
||||
}
|
||||
|
||||
protected static final LaunchConfig getDefaultConfig(File testDir) {
|
||||
LaunchConfig config = new LaunchConfig();
|
||||
File icon16 = new File("src/main/resources/icon_16x16.png");
|
||||
File icon32 = new File("src/main/resources/icon_32x32.png");
|
||||
config.icon.set(new File[] { icon16, icon32 });
|
||||
config.username.set("Player");
|
||||
config.session.set("-");
|
||||
config.gameDir.set(testDir);
|
||||
config.title.set("Minecraft Test");
|
||||
return config;
|
||||
}
|
||||
|
||||
protected void featureTest(Tweak tweak, TestFeatureBuilder test) {
|
||||
try {
|
||||
for (FeatureInfo featureInfo2 : test.bannedFeatures) {
|
||||
for (FeatureInfo featureInfo : tweak.getTweakInfo()) {
|
||||
if (featureInfo.feature.equals(featureInfo2.feature) &&
|
||||
(featureInfo2.info == null || featureInfo2.info.equals(featureInfo.info))) {
|
||||
fail("Banned feature found");
|
||||
}
|
||||
}
|
||||
}
|
||||
for (FeatureInfo featureInfo2 : test.features) {
|
||||
boolean match = false;
|
||||
for (FeatureInfo featureInfo : tweak.getTweakInfo()) {
|
||||
if (featureInfo.feature.equals(featureInfo2.feature) &&
|
||||
(featureInfo2.info == null || featureInfo2.info.equals(featureInfo.info))) {
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
assertTrue(match, featureInfo2.feature);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestFeatureBuilder {
|
||||
private List<FeatureInfo> features = new ArrayList<FeatureInfo>();
|
||||
private List<FeatureInfo> bannedFeatures = new ArrayList<FeatureInfo>();
|
||||
|
||||
public TestFeatureBuilder() {
|
||||
}
|
||||
|
||||
public TestFeatureBuilder tweakInfo(String name, String... extra) {
|
||||
features.add(new FeatureInfo(name));
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestFeatureBuilder tweakInfoBan(String name, String... extra) {
|
||||
bannedFeatures.add(new FeatureInfo(name));
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestFeatureBuilder tweakInfoList(String... names) {
|
||||
for (String s : names) {
|
||||
features.add(new FeatureInfo(s));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestFeatureBuilder tweakInfoBanList(String... names) {
|
||||
for (String s : names) {
|
||||
bannedFeatures.add(new FeatureInfo(s));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue