feat: input plugin for java bytecode
This commit is contained in:
@@ -1,13 +1,11 @@
|
||||
package jadx.tests.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -18,18 +16,21 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.CodePosition;
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.api.JadxInternalAccess;
|
||||
import jadx.api.data.annotations.InsnCodeOffset;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.AttrList;
|
||||
@@ -47,7 +48,6 @@ import jadx.tests.api.compiler.DynamicCompiler;
|
||||
import jadx.tests.api.compiler.StaticCompiler;
|
||||
import jadx.tests.api.utils.TestUtils;
|
||||
|
||||
import static jadx.core.utils.files.FileUtils.addFileToJar;
|
||||
import static org.apache.commons.lang3.StringUtils.leftPad;
|
||||
import static org.apache.commons.lang3.StringUtils.rightPad;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
@@ -63,11 +63,18 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public abstract class IntegrationTest extends TestUtils {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(IntegrationTest.class);
|
||||
private static final String TEST_DIRECTORY = "src/test/java";
|
||||
private static final String TEST_DIRECTORY2 = "jadx-core/" + TEST_DIRECTORY;
|
||||
|
||||
private static final String OUT_DIR = "test-out-tmp";
|
||||
|
||||
private static final String DEFAULT_INPUT_PLUGIN = "dx";
|
||||
/**
|
||||
* Set 'TEST_INPUT_PLUGIN' env variable to use 'java' or 'dx' input in tests
|
||||
*/
|
||||
private static final boolean USE_JAVA_INPUT = Utils.getOrElse(System.getenv("TEST_INPUT_PLUGIN"), DEFAULT_INPUT_PLUGIN).equals("java");
|
||||
|
||||
/**
|
||||
* Run auto check method if defined:
|
||||
*
|
||||
@@ -80,26 +87,20 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
|
||||
protected JadxArgs args;
|
||||
|
||||
protected boolean deleteTmpFiles;
|
||||
protected boolean withDebugInfo;
|
||||
protected boolean unloadCls;
|
||||
protected boolean compile;
|
||||
protected boolean useEclipseCompiler;
|
||||
protected Map<Integer, String> resMap = Collections.emptyMap();
|
||||
|
||||
private boolean allowWarnInCode;
|
||||
private boolean printLineNumbers;
|
||||
private boolean printSmali;
|
||||
private boolean printOffsets;
|
||||
private boolean printDisassemble;
|
||||
private Boolean useJavaInput = null;
|
||||
|
||||
private DynamicCompiler dynamicCompiler;
|
||||
|
||||
static {
|
||||
// needed for post decompile check
|
||||
AType.SKIP_ON_UNLOAD.addAll(Arrays.asList(
|
||||
AType.JADX_ERROR,
|
||||
AType.JADX_WARN,
|
||||
AType.COMMENTS));
|
||||
|
||||
// enable debug checks
|
||||
DebugChecks.checksEnabled = true;
|
||||
}
|
||||
@@ -108,8 +109,6 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
|
||||
@BeforeEach
|
||||
public void init() {
|
||||
this.deleteTmpFiles = true;
|
||||
this.unloadCls = true;
|
||||
this.withDebugInfo = true;
|
||||
this.compile = true;
|
||||
this.useEclipseCompiler = false;
|
||||
@@ -141,8 +140,9 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
|
||||
public ClassNode getClassNode(Class<?> clazz) {
|
||||
try {
|
||||
File jar = getJarForClass(clazz);
|
||||
return getClassNodeFromFiles(Collections.singletonList(jar), clazz.getName());
|
||||
List<File> files = compileClass(clazz);
|
||||
assertThat("File list is empty", files, not(empty()));
|
||||
return getClassNodeFromFiles(files, clazz.getName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage());
|
||||
@@ -181,6 +181,13 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
protected JadxDecompiler loadFiles(List<File> inputFiles) {
|
||||
args.setInputFiles(inputFiles);
|
||||
JadxDecompiler d = new JadxDecompiler(args);
|
||||
if (isJavaInput()) {
|
||||
d.getPluginManager().unload("java-convert");
|
||||
LOG.info("Using java input");
|
||||
} else {
|
||||
d.getPluginManager().unload("java-input");
|
||||
LOG.info("Using dex input");
|
||||
}
|
||||
try {
|
||||
d.load();
|
||||
} catch (Exception e) {
|
||||
@@ -199,25 +206,24 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
}
|
||||
|
||||
protected void decompileAndCheck(List<ClassNode> clsList) {
|
||||
if (!unloadCls) {
|
||||
clsList.forEach(cls -> cls.add(AFlag.DONT_UNLOAD_CLASS));
|
||||
}
|
||||
clsList.forEach(cls -> cls.add(AFlag.DONT_UNLOAD_CLASS)); // keep error and warning attributes
|
||||
clsList.forEach(ClassNode::decompile);
|
||||
|
||||
for (ClassNode cls : clsList) {
|
||||
System.out.println("-----------------------------------------------------------");
|
||||
ICodeInfo code = cls.getCode();
|
||||
if (printLineNumbers) {
|
||||
printCodeWithLineNumbers(cls.getCode());
|
||||
printCodeWithLineNumbers(code);
|
||||
} else if (printOffsets) {
|
||||
printCodeWithOffsets(code);
|
||||
} else {
|
||||
System.out.println(cls.getCode());
|
||||
System.out.println(code);
|
||||
}
|
||||
}
|
||||
System.out.println("-----------------------------------------------------------");
|
||||
|
||||
if (printSmali) {
|
||||
if (printDisassemble) {
|
||||
clsList.forEach(this::printSmali);
|
||||
}
|
||||
|
||||
runChecks(clsList);
|
||||
}
|
||||
|
||||
@@ -233,7 +239,7 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
|
||||
private void printSmali(ClassNode cls) {
|
||||
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
||||
System.out.println(cls.getSmali());
|
||||
System.out.println(cls.getDisassembledCode());
|
||||
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
||||
}
|
||||
|
||||
@@ -253,6 +259,23 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private void printCodeWithOffsets(ICodeInfo code) {
|
||||
String codeStr = code.getCodeStr();
|
||||
Map<CodePosition, Object> annotations = code.getAnnotations();
|
||||
String[] lines = codeStr.split(ICodeWriter.NL);
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
String line = lines[i];
|
||||
int curLine = i + 1;
|
||||
Object ann = annotations.get(new CodePosition(curLine, 0));
|
||||
String offsetStr = "";
|
||||
if (ann instanceof InsnCodeOffset) {
|
||||
int offset = ((InsnCodeOffset) ann).getOffset();
|
||||
offsetStr = "/* " + leftPad(String.valueOf(offset), 5) + " */";
|
||||
}
|
||||
System.out.println(rightPad(offsetStr, 12) + line);
|
||||
}
|
||||
}
|
||||
|
||||
private void insertResources(RootNode root) {
|
||||
if (resMap.isEmpty()) {
|
||||
return;
|
||||
@@ -275,7 +298,10 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
+ "\n " + Utils.listToString(mthNode.getAttributesStringsList(), "\n "));
|
||||
}
|
||||
}
|
||||
assertThat(cls.getCode().toString(), not(containsString("inconsistent")));
|
||||
|
||||
String code = cls.getCode().getCodeStr();
|
||||
assertThat(code, not(containsString("inconsistent")));
|
||||
assertThat(code, not(containsString("JADX ERROR")));
|
||||
}
|
||||
|
||||
private boolean hasErrors(IAttributeNode node) {
|
||||
@@ -407,36 +433,6 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
return dynamicCompiler.invoke(cls, methodName, types, args);
|
||||
}
|
||||
|
||||
private File getJarForClass(Class<?> cls) throws IOException {
|
||||
List<File> files = compileClass(cls);
|
||||
assertThat("File list is empty", files, not(empty()));
|
||||
|
||||
String path = cls.getPackage().getName().replace('.', '/');
|
||||
File temp = createTempFile(".jar");
|
||||
try (JarOutputStream jo = new JarOutputStream(new FileOutputStream(temp))) {
|
||||
for (File file : files) {
|
||||
addFileToJar(jo, file, path + '/' + file.getName());
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
protected File createTempFile(String suffix) {
|
||||
try {
|
||||
Path temp;
|
||||
if (deleteTmpFiles) {
|
||||
temp = FileUtils.createTempFile(suffix);
|
||||
} else {
|
||||
// don't delete on exit
|
||||
temp = FileUtils.createTempFileNoDelete(suffix);
|
||||
System.out.println("Temporary file saved: " + temp.toAbsolutePath());
|
||||
}
|
||||
return temp.toFile();
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private List<File> compileClass(Class<?> cls) throws IOException {
|
||||
String clsFullName = cls.getName();
|
||||
String rootClsName;
|
||||
@@ -499,10 +495,6 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
this.compile = false;
|
||||
}
|
||||
|
||||
protected void dontUnloadClass() {
|
||||
this.unloadCls = false;
|
||||
}
|
||||
|
||||
protected void enableDeobfuscation() {
|
||||
args.setDeobfuscationOn(true);
|
||||
args.setDeobfuscationForceSave(true);
|
||||
@@ -518,6 +510,22 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
printLineNumbers = true;
|
||||
}
|
||||
|
||||
protected void printOffsets() {
|
||||
printOffsets = true;
|
||||
}
|
||||
|
||||
protected void useJavaInput() {
|
||||
this.useJavaInput = true;
|
||||
}
|
||||
|
||||
protected void useDexInput() {
|
||||
this.useJavaInput = false;
|
||||
}
|
||||
|
||||
protected boolean isJavaInput() {
|
||||
return Utils.getOrElse(useJavaInput, USE_JAVA_INPUT);
|
||||
}
|
||||
|
||||
// Use only for debug purpose
|
||||
@Deprecated
|
||||
protected void outputCFG() {
|
||||
@@ -527,8 +535,8 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
|
||||
// Use only for debug purpose
|
||||
@Deprecated
|
||||
protected void printSmali() {
|
||||
this.printSmali = true;
|
||||
protected void printDisassemble() {
|
||||
this.printDisassemble = true;
|
||||
}
|
||||
|
||||
// Use only for debug purpose
|
||||
@@ -536,10 +544,4 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
protected void outputRawCFG() {
|
||||
this.args.setRawCFGOutput(true);
|
||||
}
|
||||
|
||||
// Use only for debug purpose
|
||||
@Deprecated
|
||||
protected void notDeleteTmpJar() {
|
||||
this.deleteTmpFiles = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
import jadx.api.JadxInternalAccess;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
@@ -21,6 +22,12 @@ public abstract class SmaliTest extends IntegrationTest {
|
||||
private static final String SMALI_TESTS_DIR = "src/test/smali";
|
||||
private static final String SMALI_TESTS_EXT = ".smali";
|
||||
|
||||
@BeforeEach
|
||||
public void init() {
|
||||
super.init();
|
||||
this.useDexInput();
|
||||
}
|
||||
|
||||
protected ClassNode getClassNodeFromSmali(String file, String clsName) {
|
||||
File smaliFile = getSmaliFile(file);
|
||||
return getClassNodeFromFiles(Collections.singletonList(smaliFile), clsName);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package jadx.tests.api.utils.assertj;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.assertj.core.api.AbstractStringAssert;
|
||||
|
||||
import jadx.api.ICodeWriter;
|
||||
@@ -72,4 +74,15 @@ public class JadxCodeAssertions extends AbstractStringAssert<JadxCodeAssertions>
|
||||
System.out.println("-----------------------------------------------------------");
|
||||
return this;
|
||||
}
|
||||
|
||||
public JadxCodeAssertions containsOneOf(String... substringArr) {
|
||||
int matches = 0;
|
||||
for (String substring : substringArr) {
|
||||
matches += TestUtils.count(actual, substring);
|
||||
}
|
||||
if (matches != 1) {
|
||||
failWithMessage("Expected a only one match from <%s> but was <%d>", Arrays.toString(substringArr), matches);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ package jadx.tests.functional;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.api.plugins.input.data.attributes.IJadxAttribute;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.AttributeStorage;
|
||||
import jadx.core.dex.attributes.IAttribute;
|
||||
|
||||
import static jadx.core.dex.attributes.AFlag.SYNTHETIC;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
@@ -35,9 +35,9 @@ public class AttributeStorageTest {
|
||||
|
||||
public static final AType<TestAttr> TEST = new AType<>();
|
||||
|
||||
public static class TestAttr implements IAttribute {
|
||||
public static class TestAttr implements IJadxAttribute {
|
||||
@Override
|
||||
public AType<TestAttr> getType() {
|
||||
public AType<TestAttr> getAttrType() {
|
||||
return TEST;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.fldinit.FieldInitAttr;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedValue;
|
||||
import jadx.api.plugins.input.data.attributes.JadxAttrType;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
@@ -56,8 +56,8 @@ public class TestRFieldRestore extends IntegrationTest {
|
||||
// check 'Button' field
|
||||
FieldNode buttonField = idCls.searchFieldByName("Button");
|
||||
assertThat(buttonField, notNullValue());
|
||||
FieldInitAttr fieldInitAttr = buttonField.get(AType.FIELD_INIT);
|
||||
Integer buttonValue = (Integer) fieldInitAttr.getEncodedValue().getValue();
|
||||
EncodedValue constVal = buttonField.get(JadxAttrType.CONSTANT_VALUE);
|
||||
Integer buttonValue = (Integer) constVal.getValue();
|
||||
assertThat(buttonValue, is(buttonConstValue));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ public class TestAnnotationsMix extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// useDexInput();
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ public class TestArith extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
|
||||
public static final int F = 7;
|
||||
|
||||
public int test(int a) {
|
||||
a += 2;
|
||||
use(a);
|
||||
|
||||
@@ -25,13 +25,15 @@ public class TestArith4 extends IntegrationTest {
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("int k = b & 7;")
|
||||
.containsOne("return (1 - k) & (k + 1);");
|
||||
.containsOne("& 255")
|
||||
.containsOneOf("return (1 - k) & (1 + k);", "return (1 - k) & (k + 1);");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoDebug() {
|
||||
noDebugInfo();
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code();
|
||||
.code()
|
||||
.containsOne("& 255");
|
||||
}
|
||||
}
|
||||
|
||||
+5
-7
@@ -2,11 +2,9 @@ package jadx.tests.integration.arrays;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.JadxMatchers.containsOne;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestArrayFillConstReplace extends IntegrationTest {
|
||||
|
||||
@@ -20,9 +18,9 @@ public class TestArrayFillConstReplace extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsOne("return new int[]{127, 129, CONST_INT};"));
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne(" int CONST_INT = 65535;")
|
||||
.containsOne("return new int[]{127, 129, CONST_INT};");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
@SuppressWarnings("IfCanBeSwitch")
|
||||
public class TestElseIf extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
@@ -25,6 +26,7 @@ public class TestElseIf extends IntegrationTest {
|
||||
r = 4;
|
||||
} else {
|
||||
r = -1;
|
||||
System.out.println();
|
||||
}
|
||||
r = r * 10;
|
||||
return Math.abs(r);
|
||||
|
||||
@@ -2,13 +2,9 @@ package jadx.tests.integration.conditions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.JadxMatchers.containsOne;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestTernaryInIf extends IntegrationTest {
|
||||
|
||||
@@ -24,12 +20,14 @@ public class TestTernaryInIf extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsOne("return a ? b : c;"));
|
||||
assertThat(code, containsOne("return (a ? b : c) ? 1 : 2;"));
|
||||
assertThat(code, not(containsString("if")));
|
||||
assertThat(code, not(containsString("else")));
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.doesNotContain("if")
|
||||
.doesNotContain("else")
|
||||
.containsOne("return a ? b : c;")
|
||||
.containsOneOf(
|
||||
"return (a ? b : c) ? 1 : 2;",
|
||||
"return (a ? !b : !c) ? 2 : 1;" // TODO: simplify this
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package jadx.tests.integration.debuginfo;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -15,7 +14,7 @@ public class TestLineNumbers2 extends IntegrationTest {
|
||||
public static class TestCls {
|
||||
private WeakReference<TestCls> f;
|
||||
|
||||
// keep at line 18
|
||||
// keep constructor at line 18
|
||||
public TestCls(TestCls s) {
|
||||
}
|
||||
|
||||
@@ -38,8 +37,12 @@ public class TestLineNumbers2 extends IntegrationTest {
|
||||
printLineNumbers();
|
||||
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
Map<Integer, Integer> lineMapping = cls.getCode().getLineMapping();
|
||||
assertEquals("{6=17, 9=18, 12=22, 13=23, 14=24, 15=28, 17=25, 18=26, 19=28, 22=31, 23=32}",
|
||||
lineMapping.toString());
|
||||
String linesMapStr = cls.getCode().getLineMapping().toString();
|
||||
if (isJavaInput()) {
|
||||
assertEquals("{6=16, 9=17, 12=21, 13=22, 14=23, 16=25, 18=27, 21=30}", linesMapStr);
|
||||
} else {
|
||||
// TODO: invert condition to match source lines
|
||||
assertEquals("{6=16, 9=17, 12=21, 13=22, 14=23, 15=27, 17=24, 18=25, 19=27, 22=30, 23=31}", linesMapStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package jadx.tests.integration.debuginfo;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.NotYetImplemented;
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.core.dex.attributes.nodes.LineAttrNode;
|
||||
@@ -51,28 +50,24 @@ public class TestReturnSourceLine extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
printLineNumbers();
|
||||
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
ICodeInfo codeInfo = cls.getCode();
|
||||
String code = codeInfo.toString();
|
||||
String[] lines = code.split(ICodeWriter.NL);
|
||||
String[] lines = codeInfo.getCodeStr().split(ICodeWriter.NL);
|
||||
|
||||
MethodNode test1 = cls.searchMethodByShortId("test1(Z)I");
|
||||
checkLine(lines, codeInfo, test1, 3, "return 1;");
|
||||
|
||||
MethodNode test2 = cls.searchMethodByShortId("test2(I)I");
|
||||
checkLine(lines, codeInfo, test2, 3, "return v - 1;");
|
||||
}
|
||||
|
||||
@Test
|
||||
@NotYetImplemented
|
||||
public void test2() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
ICodeInfo codeInfo = cls.getCode();
|
||||
String code = codeInfo.toString();
|
||||
String[] lines = code.split(ICodeWriter.NL);
|
||||
checkLine(lines, codeInfo, test2, 6, "return v + 1;");
|
||||
|
||||
MethodNode test3 = cls.searchMethodByShortId("test3(I)I");
|
||||
checkLine(lines, codeInfo, test3, 3, "return v;");
|
||||
if (isJavaInput()) { // dx lost line number for this return
|
||||
checkLine(lines, codeInfo, test3, 3, "return v;");
|
||||
}
|
||||
checkLine(lines, codeInfo, test3, 6, "return v + 1;");
|
||||
}
|
||||
|
||||
private static void checkLine(String[] lines, ICodeInfo cw, LineAttrNode node, int offset, String str) {
|
||||
|
||||
@@ -24,6 +24,7 @@ public class TestFallbackMode extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
useDexInput();
|
||||
setFallback();
|
||||
disableCompilation();
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package jadx.tests.integration.invoke;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestInvokeWithWideVars extends IntegrationTest {
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
public static class TestCls {
|
||||
|
||||
public long test1() {
|
||||
return call(1, 2);
|
||||
}
|
||||
|
||||
public long test2() {
|
||||
return rangeCall(1, 2, 3.0d, (byte) 4);
|
||||
}
|
||||
|
||||
private long call(int a, long b) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
private long rangeCall(long a, int b, double c, byte d) {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("return call(1, 2);")
|
||||
.containsOne("return rangeCall(1, 2, 3.0d, (byte) 4);");
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ public class TestLambdaConstructor extends IntegrationTest {
|
||||
setFallback();
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("RuntimeException::new");
|
||||
.containsOne("r0 = java.lang.RuntimeException::new")
|
||||
.containsOne("return r0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class TestArrayForEach extends IntegrationTest {
|
||||
assertThat(code, containsLines(2,
|
||||
"int sum = 0;",
|
||||
"for (int n : a) {",
|
||||
indent(1) + "sum += n;",
|
||||
indent() + "sum += n;",
|
||||
"}",
|
||||
"return sum;"));
|
||||
}
|
||||
|
||||
@@ -32,13 +32,15 @@ public class TestCodeComments extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int insnOffset = isJavaInput() ? 13 : 11;
|
||||
|
||||
String baseClsId = TestCls.class.getName();
|
||||
ICodeComment clsComment = new JadxCodeComment(JadxNodeRef.forCls(baseClsId), "class comment");
|
||||
ICodeComment innerClsComment = new JadxCodeComment(JadxNodeRef.forCls(baseClsId + ".A"), "inner class comment");
|
||||
ICodeComment fldComment = new JadxCodeComment(new JadxNodeRef(RefType.FIELD, baseClsId, "intField:I"), "field comment");
|
||||
JadxNodeRef mthRef = new JadxNodeRef(RefType.METHOD, baseClsId, "test()I");
|
||||
ICodeComment mthComment = new JadxCodeComment(mthRef, "method comment");
|
||||
ICodeComment insnComment = new JadxCodeComment(mthRef, "insn comment", 11);
|
||||
ICodeComment insnComment = new JadxCodeComment(mthRef, "insn comment", insnOffset);
|
||||
|
||||
JadxCodeData codeData = new JadxCodeData();
|
||||
getArgs().setCodeData(codeData);
|
||||
@@ -60,7 +62,7 @@ public class TestCodeComments extends IntegrationTest {
|
||||
.reloadCode(this)
|
||||
.isEqualTo(code);
|
||||
|
||||
ICodeComment updInsnComment = new JadxCodeComment(mthRef, "updated insn comment", 11);
|
||||
ICodeComment updInsnComment = new JadxCodeComment(mthRef, "updated insn comment", insnOffset);
|
||||
codeData.setComments(Collections.singletonList(updInsnComment));
|
||||
assertThat(cls)
|
||||
.reloadCode(this)
|
||||
|
||||
@@ -27,10 +27,12 @@ public class TestCodeComments2 extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
printOffsets();
|
||||
|
||||
String baseClsId = TestCls.class.getName();
|
||||
JadxNodeRef mthRef = new JadxNodeRef(RefType.METHOD, baseClsId, "test(Z)I");
|
||||
ICodeComment insnComment = new JadxCodeComment(mthRef, "return comment", 10);
|
||||
ICodeComment insnComment2 = new JadxCodeComment(mthRef, "another return comment", 11);
|
||||
ICodeComment insnComment = new JadxCodeComment(mthRef, "return comment", isJavaInput() ? 13 : 10);
|
||||
ICodeComment insnComment2 = new JadxCodeComment(mthRef, "another return comment", isJavaInput() ? 15 : 11);
|
||||
|
||||
JadxCodeData codeData = new JadxCodeData();
|
||||
codeData.setComments(Arrays.asList(insnComment, insnComment2));
|
||||
@@ -40,7 +42,7 @@ public class TestCodeComments2 extends IntegrationTest {
|
||||
.decompile()
|
||||
.checkCodeOffsets()
|
||||
.code()
|
||||
.containsOne("// " + insnComment.getComment())
|
||||
.containsOne("// " + insnComment2.getComment());
|
||||
.containsOne("return 1; // " + insnComment.getComment())
|
||||
.containsOne("return 3; // " + insnComment2.getComment());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,12 @@ public class TestCodeComments2a extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
printOffsets();
|
||||
|
||||
String baseClsId = TestCls.class.getName();
|
||||
JadxNodeRef mthRef = new JadxNodeRef(RefType.METHOD, baseClsId, "test(Z)I");
|
||||
ICodeComment insnComment = new JadxCodeComment(mthRef, "return comment", 18);
|
||||
ICodeComment insnComment2 = new JadxCodeComment(mthRef, "another return comment", 19);
|
||||
ICodeComment insnComment = new JadxCodeComment(mthRef, "return comment", isJavaInput() ? 22 : 18);
|
||||
ICodeComment insnComment2 = new JadxCodeComment(mthRef, "another return comment", isJavaInput() ? 27 : 19);
|
||||
|
||||
JadxCodeData codeData = new JadxCodeData();
|
||||
codeData.setComments(Arrays.asList(insnComment, insnComment2));
|
||||
|
||||
+3
-1
@@ -27,9 +27,11 @@ public class TestCodeCommentsMultiline extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
printOffsets();
|
||||
|
||||
String baseClsId = TestCls.class.getName();
|
||||
JadxNodeRef mthRef = new JadxNodeRef(RefType.METHOD, baseClsId, "test(Z)I");
|
||||
ICodeComment insnComment = new JadxCodeComment(mthRef, "multi\nline\ncomment", 11);
|
||||
ICodeComment insnComment = new JadxCodeComment(mthRef, "multi\nline\ncomment", isJavaInput() ? 15 : 11);
|
||||
|
||||
JadxCodeData codeData = new JadxCodeData();
|
||||
codeData.setComments(Collections.singletonList(insnComment));
|
||||
|
||||
@@ -32,7 +32,6 @@ public class TestDuplicateCast extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
dontUnloadClass();
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
MethodNode mth = getMethod(cls, "method");
|
||||
|
||||
|
||||
@@ -6,13 +6,9 @@ import java.util.Random;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.JadxMatchers.containsOne;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestFieldInit extends IntegrationTest {
|
||||
|
||||
@@ -35,15 +31,16 @@ public class TestFieldInit extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsOne("List<String> s = new ArrayList"));
|
||||
assertThat(code, containsOne("A a = new A();"));
|
||||
assertThat(code, containsOne("int i = (Random.class.getSimpleName().length() + 1);"));
|
||||
assertThat(code, containsOne("int n = 0;"));
|
||||
assertThat(code, not(containsString("static {")));
|
||||
assertThat(code, containsOne("this.n = z;"));
|
||||
assertThat(code, containsOne("this.n = 0;"));
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("List<String> s = new ArrayList")
|
||||
.containsOne("A a = new A();")
|
||||
.containsOneOf(
|
||||
"int i = (Random.class.getSimpleName().length() + 1);",
|
||||
"int i = (1 + Random.class.getSimpleName().length());")
|
||||
.containsOne("int n = 0;")
|
||||
.doesNotContain("static {")
|
||||
.containsOne("this.n = z;")
|
||||
.containsOne("this.n = 0;");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ public class TestFieldInit2 extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
printDisassemble();
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
|
||||
@@ -2,35 +2,31 @@ package jadx.tests.integration.others;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestFloatValue extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
public float[] method() {
|
||||
public float[] test() {
|
||||
float[] fa = { 0.55f };
|
||||
fa[0] /= 2;
|
||||
return fa;
|
||||
}
|
||||
|
||||
public void check() {
|
||||
assertEquals(0.275f, method()[0], 0.0001f);
|
||||
assertEquals(0.275f, test()[0], 0.0001f);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, not(containsString("1073741824")));
|
||||
assertThat(code, containsString("0.55f"));
|
||||
assertThat(code, containsString("fa[0] = fa[0] / 2.0f;"));
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.doesNotContain("1073741824")
|
||||
.containsOne("0.55f")
|
||||
.containsOne("fa[0] = fa[0] / 2.0f;");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package jadx.tests.integration.others;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestJavaDupInsn extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
private MethodNode mth;
|
||||
private BlockNode block;
|
||||
private SSAVar[] vars;
|
||||
private int[] versions;
|
||||
|
||||
public SSAVar test(RegisterArg regArg) {
|
||||
int regNum = regArg.getRegNum();
|
||||
int version = versions[regNum]++;
|
||||
SSAVar ssaVar = mth.makeNewSVar(regNum, version, regArg);
|
||||
vars[regNum] = ssaVar;
|
||||
return ssaVar;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
noDebugInfo();
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code();
|
||||
}
|
||||
}
|
||||
-2
@@ -4,7 +4,6 @@ import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.NotYetImplemented;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
@@ -42,7 +41,6 @@ public class TestOverridePackagePrivateMethod extends SmaliTest {
|
||||
*/
|
||||
// @formatter:on
|
||||
|
||||
@NotYetImplemented("Don't change access modifiers if not needed")
|
||||
@Test
|
||||
public void test() {
|
||||
commonChecks();
|
||||
|
||||
@@ -11,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestSwitch extends IntegrationTest {
|
||||
public static class TestCls {
|
||||
public String escape(String str) {
|
||||
public String test(String str) {
|
||||
int len = str.length();
|
||||
StringBuilder sb = new StringBuilder(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
||||
@@ -31,6 +31,8 @@ public class TestSynchronized2 extends IntegrationTest {
|
||||
@Test
|
||||
@NotYetImplemented
|
||||
public void test2() {
|
||||
useDexInput(); // java bytecode don't add exception handlers
|
||||
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ public class TestTryCatch7 extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void testNoDebug() {
|
||||
// useDexInput();
|
||||
noDebugInfo();
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
+2
@@ -25,6 +25,8 @@ public class TestTryCatchMultiException extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// printDisassemble();
|
||||
// setFallback();
|
||||
noDebugInfo();
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
@@ -14,7 +14,7 @@ public class TestGenerics5 extends IntegrationTest {
|
||||
public static class TestCls {
|
||||
private InheritableThreadLocal<Map<String, String>> inheritableThreadLocal;
|
||||
|
||||
public void put(String key, String val) {
|
||||
public void test(String key, String val) {
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("key cannot be null");
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ public class TestDontInlineThis extends IntegrationTest {
|
||||
TestCls res;
|
||||
if (field == 7) {
|
||||
res = this;
|
||||
System.out.println();
|
||||
} else {
|
||||
res = new TestCls();
|
||||
}
|
||||
|
||||
@@ -5,10 +5,7 @@ import org.junit.jupiter.api.Test;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.JadxMatchers.containsOne;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class TestVariables5 extends IntegrationTest {
|
||||
@@ -47,12 +44,10 @@ public class TestVariables5 extends IntegrationTest {
|
||||
public void test() {
|
||||
noDebugInfo();
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, not(containsString("int i2++;")));
|
||||
assertThat(code, containsOne("int i = 0;"));
|
||||
assertThat(code, containsOne("&& (i = i + 1) == 2"));
|
||||
// assertThat(code, containsOne("i++;"));
|
||||
// assertThat(code, containsOne("if (i == 2) {"));
|
||||
assertThat(cls)
|
||||
.code()
|
||||
.doesNotContain("int i2++;")
|
||||
.containsOne("int i = 0;")
|
||||
.containsOneOf("i++;", "&& (i = i + 1) == 2");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user