-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
941 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
...r/src/integration/java/com/github/naton1/jvmexplorer/integration/e2e/ClassFieldsTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package com.github.naton1.jvmexplorer.integration.e2e; | ||
|
||
import com.github.naton1.jvmexplorer.integration.helper.TestJvm; | ||
import com.github.naton1.jvmexplorer.integration.programs.SleepForeverProgram; | ||
import javafx.scene.control.TextInputControl; | ||
import javafx.scene.control.TreeView; | ||
import javafx.scene.input.Clipboard; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.Timeout; | ||
|
||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import java.util.regex.Pattern; | ||
|
||
@Slf4j | ||
class ClassFieldsTest extends EndToEndTest { | ||
|
||
@Test | ||
void testNestedFieldsShow() throws Exception { | ||
try (final TestJvm testJvm = TestJvm.of(SleepForeverProgram.class)) { | ||
appHelper.selectJvm(testJvm); | ||
appHelper.selectMainClass(testJvm); | ||
appHelper.openTab(2); | ||
appHelper.waitUntilDisassemble(); // not directly related, but means fields are loaded too | ||
final TreeView<?> fieldTree = appHelper.getFieldTree(); | ||
// Verify there is a nested field | ||
fieldTree.getRoot() | ||
.getChildren() | ||
.stream() | ||
.filter(c -> c.getChildren().size() > 0) // verify it has nested fields | ||
.filter(c -> c.getValue().toString().contains("private")) // make sure it's reading a private | ||
// field | ||
.filter(c -> c.getValue().toString().contains("List")) | ||
.findFirst() | ||
.orElseThrow(); | ||
} | ||
} | ||
|
||
@Test | ||
void testCopyField() throws Exception { | ||
try (final TestJvm testJvm = TestJvm.of(SleepForeverProgram.class)) { | ||
appHelper.selectJvm(testJvm); | ||
appHelper.selectMainClass(testJvm); | ||
appHelper.openTab(2); | ||
appHelper.waitUntilDisassemble(); // not directly related, but means fields are loaded too | ||
final TreeView<?> fieldTree = appHelper.getFieldTree(); | ||
// Verify there is a nested field | ||
fxRobot.interact(() -> fieldTree.getSelectionModel().selectFirst()); | ||
fxRobot.selectContextMenu(fieldTree, "Copy"); | ||
|
||
fxRobot.interact(() -> { | ||
final String text = fieldTree.getSelectionModel().getSelectedItem().getValue().toString(); | ||
final String clipboard = Clipboard.getSystemClipboard().getString(); | ||
|
||
Assertions.assertTrue(text.matches(".* = " + Pattern.quote(clipboard))); | ||
}); | ||
} | ||
} | ||
|
||
@Test | ||
@Timeout(30) | ||
void testModifyField() throws Exception { | ||
try (final TestJvm testJvm = TestJvm.of(SleepForeverProgram.class)) { | ||
appHelper.selectJvm(testJvm); | ||
appHelper.selectMainClass(testJvm); | ||
appHelper.openTab(2); | ||
final TreeView<?> fieldTree = appHelper.getFieldTree(); | ||
fxRobot.interact(() -> fieldTree.getSelectionModel().selectFirst()); | ||
final AtomicBoolean success = new AtomicBoolean(false); | ||
final Thread thread = new Thread(() -> { | ||
// Dialog is blocking | ||
fxRobot.waitForStageExists("Update Field"); | ||
final TextInputControl textField = fxRobot.targetWindow("Update Field") | ||
.lookup(".text-field") | ||
.match(t -> t instanceof TextInputControl | ||
&& ((TextInputControl) t).getText().equals("15")) | ||
.queryTextInputControl(); | ||
fxRobot.interact(() -> { | ||
textField.setText("1000"); | ||
fxRobot.targetWindow("Update Field").lookup("OK").queryButton().fire(); | ||
}); | ||
fxRobot.waitUntil(() -> fieldTree.getSelectionModel() | ||
.getSelectedItem() | ||
.getValue() | ||
.toString() | ||
.contains("1000"), 5000); | ||
success.set(true); | ||
}); | ||
thread.setUncaughtExceptionHandler((t, e) -> log.warn("Async thread failed", e)); | ||
thread.start(); | ||
fxRobot.selectContextMenu(fieldTree, "Edit Value"); | ||
thread.join(); | ||
Assertions.assertTrue(success.get()); | ||
} | ||
} | ||
|
||
} |
30 changes: 9 additions & 21 deletions
30
...rc/integration/java/com/github/naton1/jvmexplorer/integration/e2e/DecompileClassTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
.../src/integration/java/com/github/naton1/jvmexplorer/integration/e2e/ImportExportTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package com.github.naton1.jvmexplorer.integration.e2e; | ||
|
||
import com.github.naton1.jvmexplorer.integration.helper.TestJvm; | ||
import com.github.naton1.jvmexplorer.integration.programs.SleepForeverProgram; | ||
import com.github.naton1.jvmexplorer.protocol.helper.ClassNameHelper; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import java.io.File; | ||
|
||
@Slf4j | ||
class ImportExportTest extends EndToEndTest { | ||
|
||
@Test | ||
void testGlobalExportThenPatch() throws Exception { | ||
try (final TestJvm testJvm = TestJvm.of(SleepForeverProgram.class)) { | ||
appHelper.selectJvm(testJvm); | ||
appHelper.waitForClassesToLoad(); | ||
|
||
final String simpleName = ClassNameHelper.getSimpleName(testJvm.getMainClassName()); | ||
appHelper.searchClasses(simpleName); | ||
|
||
// Make sure it works with both classloader settings | ||
|
||
appHelper.disableClassLoaders(); | ||
doJarExportThenImport("Export Classes", "Replace Classes"); | ||
|
||
appHelper.enableClassLoaders(); | ||
doJarExportThenImport("Export Classes", "Replace Classes"); | ||
} | ||
} | ||
|
||
@Test | ||
void testExportClassThenPatch() throws Exception { | ||
try (final TestJvm testJvm = TestJvm.of(SleepForeverProgram.class)) { | ||
appHelper.selectJvm(testJvm); | ||
appHelper.waitForClassesToLoad(); | ||
final String simpleName = ClassNameHelper.getSimpleName(testJvm.getMainClassName()); | ||
appHelper.selectClass(simpleName); | ||
|
||
final File tempClass = appHelper.createTempClass(); | ||
appHelper.setTestFile(tempClass); | ||
|
||
appHelper.selectClassAction("Export Class"); | ||
|
||
fxRobot.waitUntil(() -> tempClass.length() > 0, 5000); | ||
|
||
appHelper.setTestFile(tempClass); | ||
appHelper.selectClassAction("Replace Class"); | ||
|
||
appHelper.waitForAlert("Replaced Class", "Successfully replaced class"); | ||
} | ||
} | ||
|
||
@Test | ||
void testExportPackageThenPatch() throws Exception { | ||
try (final TestJvm testJvm = TestJvm.of(SleepForeverProgram.class)) { | ||
appHelper.selectJvm(testJvm); | ||
appHelper.waitForClassesToLoad(); | ||
|
||
final String packageName = ClassNameHelper.getPackageName(testJvm.getMainClassName()); | ||
final String simplePackageName = ClassNameHelper.getSimpleName(packageName); | ||
appHelper.selectClass(simplePackageName); | ||
|
||
doJarExportThenImport("Export Package", "Replace Package"); | ||
} | ||
} | ||
|
||
@Test | ||
void testExportClassLoaderThenPatch() throws Exception { | ||
try (final TestJvm testJvm = TestJvm.of(SleepForeverProgram.class)) { | ||
appHelper.selectJvm(testJvm); | ||
appHelper.waitForClassesToLoad(); | ||
|
||
appHelper.enableClassLoaders(); | ||
|
||
appHelper.selectClass("AppClassLoader"); | ||
|
||
doJarExportThenImport("Export Class Loader", "Replace Class Loader"); | ||
} | ||
} | ||
|
||
private void doJarExportThenImport(String exportAction, String importAction) { | ||
final File tempJar = appHelper.createTempJar(); | ||
appHelper.setTestFile(tempJar); | ||
|
||
appHelper.selectClassAction(exportAction); | ||
|
||
fxRobot.waitUntil(() -> tempJar.length() > 0, 5000); | ||
fxRobot.waitForStageExists("Export Finished"); | ||
final long exportedClasses = appHelper.streamClasses(tempJar).count(); | ||
Assertions.assertTrue(exportedClasses > 0); | ||
|
||
log.info("Exported {} classes", exportedClasses); | ||
|
||
appHelper.setTestFile(tempJar); | ||
appHelper.selectClassAction(importAction); | ||
|
||
fxRobot.waitForStageExists("Patching Finished"); | ||
appHelper.waitForAlert("Patching Finished", "Patch succeeded"); | ||
log.info("Patched {} classes", exportedClasses); | ||
} | ||
|
||
} |
Oops, something went wrong.