diff --git a/libraries-5/pom.xml b/libraries-5/pom.xml index 74326251d089..451acbe83931 100644 --- a/libraries-5/pom.xml +++ b/libraries-5/pom.xml @@ -132,6 +132,26 @@ lanterna ${lanterna.version} + + org.soot-oss + sootup.core + ${sootup.version} + + + org.soot-oss + sootup.java.core + ${sootup.version} + + + org.soot-oss + sootup.java.sourcecode + ${sootup.version} + + + org.soot-oss + sootup.java.bytecode + ${sootup.version} + org.springframework.boot spring-boot-starter-test @@ -149,6 +169,7 @@ 1.29.2 7.28.1 0.14.1 + 1.3.0 diff --git a/libraries-5/src/test/java/com/baeldung/sootup/AnalyzeUnitTest.java b/libraries-5/src/test/java/com/baeldung/sootup/AnalyzeUnitTest.java new file mode 100644 index 000000000000..709269529bb3 --- /dev/null +++ b/libraries-5/src/test/java/com/baeldung/sootup/AnalyzeUnitTest.java @@ -0,0 +1,58 @@ +package com.baeldung.sootup; + +import org.junit.jupiter.api.Test; +import sootup.core.inputlocation.AnalysisInputLocation; +import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; +import sootup.java.bytecode.inputlocation.JrtFileSystemAnalysisInputLocation; +import sootup.java.bytecode.inputlocation.OTFCompileAnalysisInputLocation; +import sootup.java.core.views.JavaView; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class AnalyzeUnitTest { + @Test + void whenAnalyzingTheJvm_thenWeCanListClasses() { + AnalysisInputLocation inputLocation = new JrtFileSystemAnalysisInputLocation(); + + JavaView view = new JavaView(inputLocation); + + assertThat(view.getClasses()).isNotEmpty(); + } + + @Test + void whenAnalyzingThisTestClass_thenWeCanListClasses() { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/AnalyzeUnitTest.java"); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(javaFile); + + JavaView view = new JavaView(inputLocation); + + assertEquals(1, view.getClasses().size()); + } + + @Test + void whenAnalyzingAString_thenWeCanListClasses() throws IOException { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/AnalyzeUnitTest.java"); + String javaContents = Files.readString(javaFile); + + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation("AnalyzeUnitTest.java", javaContents); + + JavaView view = new JavaView(inputLocation); + + assertEquals(1, view.getClasses().size()); + } + + @Test + void whenAnalyzingCompiledByteCode_thenWeCanListClasses() { + AnalysisInputLocation inputLocation = new JavaClassPathAnalysisInputLocation("target/classes"); + + JavaView view = new JavaView(inputLocation); + + assertThat(view.getClasses()).isNotEmpty(); + } +} diff --git a/libraries-5/src/test/java/com/baeldung/sootup/ClassUnitTest.java b/libraries-5/src/test/java/com/baeldung/sootup/ClassUnitTest.java new file mode 100644 index 000000000000..ba7256df479d --- /dev/null +++ b/libraries-5/src/test/java/com/baeldung/sootup/ClassUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.sootup; + +import org.junit.jupiter.api.Test; +import sootup.core.IdentifierFactory; +import sootup.core.inputlocation.AnalysisInputLocation; +import sootup.core.model.SootClass; +import sootup.core.types.ClassType; +import sootup.java.bytecode.inputlocation.OTFCompileAnalysisInputLocation; +import sootup.java.core.JavaSootClass; +import sootup.java.core.views.JavaView; + +import java.nio.file.Path; +import java.util.Optional; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; + +public class ClassUnitTest { + @Test + void whenAnalyzingThisTestClass_thenWeCanGetASingleClass() { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/ClassUnitTest.java"); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(javaFile); + + JavaView view = new JavaView(inputLocation); + + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + ClassType javaClass = identifierFactory.getClassType("com.baeldung.sootup.ClassUnitTest"); + + Optional sootClass = view.getClass(javaClass); + assertTrue(sootClass.isPresent()); + + JavaSootClass classUnitTest = sootClass.get(); + assertTrue(classUnitTest.isPublic()); + assertTrue(classUnitTest.isConcrete()); + assertFalse(classUnitTest.isFinal()); + assertFalse(classUnitTest.isEnum()); + } + + @Test + void whenAnalyzingThisTestClass_thenWeCanGetTheSuperclass() { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/ClassUnitTest.java"); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(javaFile); + + JavaView view = new JavaView(inputLocation); + + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + ClassType javaClass = identifierFactory.getClassType("com.baeldung.sootup.ClassUnitTest"); + + SootClass sootClass = view.getClassOrThrow(javaClass); + Optional superclass = sootClass.getSuperclass(); + + assertTrue(superclass.isPresent()); + assertEquals("java.lang.Object", superclass.get().getFullyQualifiedName()); + } + + @Test + void whenAnalyzingThisTestClass_thenWeCanGetTheInterfaces() { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/ClassUnitTest.java"); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(javaFile); + + JavaView view = new JavaView(inputLocation); + + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + ClassType javaClass = identifierFactory.getClassType("com.baeldung.sootup.ClassUnitTest"); + + SootClass sootClass = view.getClassOrThrow(javaClass); + Set interfaces = sootClass.getInterfaces(); + + assertTrue(interfaces.isEmpty()); + } + +} diff --git a/libraries-5/src/test/java/com/baeldung/sootup/FieldUnitTest.java b/libraries-5/src/test/java/com/baeldung/sootup/FieldUnitTest.java new file mode 100644 index 000000000000..310292b35847 --- /dev/null +++ b/libraries-5/src/test/java/com/baeldung/sootup/FieldUnitTest.java @@ -0,0 +1,54 @@ +package com.baeldung.sootup; + +import org.junit.jupiter.api.Test; +import sootup.core.IdentifierFactory; +import sootup.core.inputlocation.AnalysisInputLocation; +import sootup.core.model.SootClass; +import sootup.core.model.SootField; +import sootup.core.types.ClassType; +import sootup.java.bytecode.inputlocation.OTFCompileAnalysisInputLocation; +import sootup.java.core.views.JavaView; + +import java.nio.file.Path; +import java.util.Optional; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; + +public class FieldUnitTest { + private String aField; + + @Test + void whenAnalyzingThisClass_thenWeCanAccessFields() { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/FieldUnitTest.java"); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(javaFile); + + JavaView view = new JavaView(inputLocation); + + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + ClassType javaClass = identifierFactory.getClassType("com.baeldung.sootup.FieldUnitTest"); + + SootClass sootClass = view.getClassOrThrow(javaClass); + Set fields = sootClass.getFields(); + assertEquals(1, fields.size()); + } + + @Test + void whenAnalyzingThisClass_thenWeCanAccessASingleField() { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/FieldUnitTest.java"); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(javaFile); + + JavaView view = new JavaView(inputLocation); + + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + ClassType javaClass = identifierFactory.getClassType("com.baeldung.sootup.FieldUnitTest"); + + SootClass sootClass = view.getClassOrThrow(javaClass); + Optional field = sootClass.getField("aField"); + assertTrue(field.isPresent()); + + SootField sootField = field.get(); + assertTrue(sootField.isPrivate()); + assertFalse(sootField.isStatic()); + } +} diff --git a/libraries-5/src/test/java/com/baeldung/sootup/MethodBodyUnitTest.java b/libraries-5/src/test/java/com/baeldung/sootup/MethodBodyUnitTest.java new file mode 100644 index 000000000000..079523e46986 --- /dev/null +++ b/libraries-5/src/test/java/com/baeldung/sootup/MethodBodyUnitTest.java @@ -0,0 +1,91 @@ +package com.baeldung.sootup; + +import org.junit.jupiter.api.Test; +import sootup.core.IdentifierFactory; +import sootup.core.graph.StmtGraph; +import sootup.core.inputlocation.AnalysisInputLocation; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; +import sootup.java.bytecode.inputlocation.OTFCompileAnalysisInputLocation; +import sootup.java.core.views.JavaView; + +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class MethodBodyUnitTest { + @Test + void whenAnalyzingAMethod_thenWeCanAccessTheLocals() { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/MethodBodyUnitTest.java"); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(javaFile); + + JavaView view = new JavaView(inputLocation); + + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + ClassType javaClass = identifierFactory.getClassType("com.baeldung.sootup.MethodBodyUnitTest"); + + SootClass sootClass = view.getClassOrThrow(javaClass); + Optional method = sootClass.getMethod("someMethod", + List.of( + identifierFactory.getClassType("java.lang.String") + )); + assertTrue(method.isPresent()); + + SootMethod sootMethod = method.get(); + + Body methodBody = sootMethod.getBody(); + assertThat(methodBody.getLocalCount()).isGreaterThan(0); + var thisLocal = methodBody.getLocals() + .stream() + .filter(local -> local.getName().equals("this")) + .findFirst(); + assertTrue(thisLocal.isPresent()); + assertEquals(javaClass, thisLocal.get().getType()); + } + + @Test + void whenAnalyzingAMethod_thenWeCanAccessTheCallGraph() { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/MethodBodyUnitTest.java"); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(javaFile); + + JavaView view = new JavaView(inputLocation); + + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + ClassType javaClass = identifierFactory.getClassType("com.baeldung.sootup.MethodBodyUnitTest"); + + SootClass sootClass = view.getClassOrThrow(javaClass); + Optional method = sootClass.getMethod("someMethod", + List.of( + identifierFactory.getClassType("java.lang.String") + )); + assertTrue(method.isPresent()); + + SootMethod sootMethod = method.get(); + + Body methodBody = sootMethod.getBody(); + StmtGraph stmtGraph = methodBody.getStmtGraph(); + List stmts = stmtGraph.getStmts(); + + assertThat(stmts).hasSize(7); + assertThat(stmts.get(0)).asString().isEqualTo("this := @this: com.baeldung.sootup.MethodBodyUnitTest"); + assertThat(stmts.get(1)).asString().isEqualTo("l1 := @parameter0: java.lang.String"); + assertThat(stmts.get(2)).asString().isEqualTo("l2 = virtualinvoke l1.()"); + assertThat(stmts.get(3)).asString().isEqualTo("$stack3 = "); + assertThat(stmts.get(4)).asString().isEqualTo("$stack4 = dynamicinvoke \"makeConcatWithConstants\" (l2) (\"Hello, \\u0001\")"); + assertThat(stmts.get(5)).asString().isEqualTo("virtualinvoke $stack3.($stack4)"); + assertThat(stmts.get(6)).asString().isEqualTo("return"); + } + + + private void someMethod(String name) { + var capitals = name.toUpperCase(); + System.out.println("Hello, " + capitals); + } +} diff --git a/libraries-5/src/test/java/com/baeldung/sootup/MethodUnitTest.java b/libraries-5/src/test/java/com/baeldung/sootup/MethodUnitTest.java new file mode 100644 index 000000000000..c04f635854db --- /dev/null +++ b/libraries-5/src/test/java/com/baeldung/sootup/MethodUnitTest.java @@ -0,0 +1,77 @@ +package com.baeldung.sootup; + +import org.junit.jupiter.api.Test; +import sootup.core.IdentifierFactory; +import sootup.core.inputlocation.AnalysisInputLocation; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; +import sootup.java.bytecode.inputlocation.OTFCompileAnalysisInputLocation; +import sootup.java.core.views.JavaView; + +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class MethodUnitTest { + + @Test + void whenAnalyzingThisClass_thenWeCanAccessMethods() { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/MethodUnitTest.java"); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(javaFile); + + JavaView view = new JavaView(inputLocation); + + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + ClassType javaClass = identifierFactory.getClassType("com.baeldung.sootup.MethodUnitTest"); + + SootClass sootClass = view.getClassOrThrow(javaClass); + Set methods = sootClass.getMethods(); + assertThat(methods).isNotEmpty(); + } + + @Test + void whenAnalyzingThisClass_thenWeCanAccessASingleMethod() { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/MethodUnitTest.java"); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(javaFile); + + JavaView view = new JavaView(inputLocation); + + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + ClassType javaClass = identifierFactory.getClassType("com.baeldung.sootup.MethodUnitTest"); + + SootClass sootClass = view.getClassOrThrow(javaClass); + Optional method = sootClass.getMethod("someMethod", + List.of( + identifierFactory.getClassType("java.lang.String") + )); + assertTrue(method.isPresent()); + + SootMethod sootMethod = method.get(); + assertTrue(sootMethod.isPrivate()); + assertTrue(sootMethod.isConcrete()); + } + + @Test + void whenAnalyzingThisClass_thenWeCanListMethodsByName() { + Path javaFile = Path.of("src/test/java/com/baeldung/sootup/MethodUnitTest.java"); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(javaFile); + + JavaView view = new JavaView(inputLocation); + + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + ClassType javaClass = identifierFactory.getClassType("com.baeldung.sootup.MethodUnitTest"); + + SootClass sootClass = view.getClassOrThrow(javaClass); + Set method = sootClass.getMethodsByName("someMethod"); + assertEquals(2, method.size()); + } + + private void someMethod(String name) {} + private void someMethod(int value) {} +}