From a68dc42b6a835bd513e9d617c9892e85f321ddb6 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 8 Sep 2014 00:23:46 -0400 Subject: added some tests for a small inheritance hierarchy --- build.gradle | 21 +- test/cuchaz/enigma/EntryFactory.java | 18 +- .../cuchaz/enigma/TestJarIndexInheritanceTree.java | 255 +++++++++++++++++++++ test/cuchaz/enigma/TestJarIndexLoneClass.java | 8 +- .../enigma/inputs/inheritanceTree/BaseClass.java | 18 ++ .../enigma/inputs/inheritanceTree/SubclassA.java | 9 + .../enigma/inputs/inheritanceTree/SubclassB.java | 24 ++ .../inputs/inheritanceTree/SubsubclassAA.java | 21 ++ 8 files changed, 361 insertions(+), 13 deletions(-) create mode 100644 test/cuchaz/enigma/TestJarIndexInheritanceTree.java create mode 100644 test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java create mode 100644 test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java create mode 100644 test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java create mode 100644 test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java diff --git a/build.gradle b/build.gradle index 14f66145..10294292 100644 --- a/build.gradle +++ b/build.gradle @@ -74,18 +74,29 @@ task jarLoneClass( type: Jar ) { archiveName( "testLoneClass.jar" ) } +task jarInheritanceTree( type: Jar ) { + from( sourceSets.test.output ) { + include( "cuchaz/enigma/inputs/Keep.class" ) + include( "cuchaz/enigma/inputs/inheritanceTree/**" ) + } + archiveName( "testInheritanceTree.jar" ) +} + task obfTestCases( type: proguard.gradle.ProGuardTask ) { - dependsOn jarLoneClass - - injars( "build/libs/testLoneClass.jar" ) - outjars( "build/libs/testLoneClass.obf.jar" ) + dependsOn jarLoneClass, jarInheritanceTree libraryjars( "${System.getProperty('java.home')}/lib/rt.jar" ) overloadaggressively repackageclasses allowaccessmodification dontoptimize + dontshrink keep( "class cuchaz.enigma.inputs.Keep" ) - dontshrink + + def jarNames = [ "LoneClass", "InheritanceTree" ]; + jarNames.each() { + injars( "build/libs/test${it}.jar" ) + outjars( "build/libs/test${it}.obf.jar" ) + } } \ No newline at end of file diff --git a/test/cuchaz/enigma/EntryFactory.java b/test/cuchaz/enigma/EntryFactory.java index b275719b..66f83dfd 100644 --- a/test/cuchaz/enigma/EntryFactory.java +++ b/test/cuchaz/enigma/EntryFactory.java @@ -40,13 +40,23 @@ public class EntryFactory return new ConstructorEntry( newClass( className ), signature ); } - public static EntryReference newFieldReferenceByMethod( String fieldClassName, String fieldName, String callerClassName, String callerName, String callerSignature ) + public static EntryReference newFieldReferenceByMethod( FieldEntry fieldEntry, String callerClassName, String callerName, String callerSignature ) { - return new EntryReference( newField( fieldClassName, fieldName ), newMethod( callerClassName, callerName, callerSignature ) ); + return new EntryReference( fieldEntry, newMethod( callerClassName, callerName, callerSignature ) ); } - public static EntryReference newFieldReferenceByConstructor( String fieldClassName, String fieldName, String callerClassName, String callerSignature ) + public static EntryReference newFieldReferenceByConstructor( FieldEntry fieldEntry, String callerClassName, String callerSignature ) { - return new EntryReference( newField( fieldClassName, fieldName ), newConstructor( callerClassName, callerSignature ) ); + return new EntryReference( fieldEntry, newConstructor( callerClassName, callerSignature ) ); + } + + public static EntryReference newBehaviorReferenceByMethod( BehaviorEntry behaviorEntry, String callerClassName, String callerName, String callerSignature ) + { + return new EntryReference( behaviorEntry, newMethod( callerClassName, callerName, callerSignature ) ); + } + + public static EntryReference newBehaviorReferenceByConstructor( BehaviorEntry behaviorEntry, String callerClassName, String callerSignature ) + { + return new EntryReference( behaviorEntry, newConstructor( callerClassName, callerSignature ) ); } } diff --git a/test/cuchaz/enigma/TestJarIndexInheritanceTree.java b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java new file mode 100644 index 00000000..5ded5df0 --- /dev/null +++ b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java @@ -0,0 +1,255 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma; + +import static cuchaz.enigma.EntryFactory.newBehaviorReferenceByConstructor; +import static cuchaz.enigma.EntryFactory.newBehaviorReferenceByMethod; +import static cuchaz.enigma.EntryFactory.newClass; +import static cuchaz.enigma.EntryFactory.newFieldReferenceByConstructor; +import static cuchaz.enigma.EntryFactory.newFieldReferenceByMethod; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +import java.util.Collection; +import java.util.Set; +import java.util.jar.JarFile; + +import org.junit.Test; + +import cuchaz.enigma.analysis.Access; +import cuchaz.enigma.analysis.EntryReference; +import cuchaz.enigma.analysis.JarIndex; +import cuchaz.enigma.analysis.TranslationIndex; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; + +public class TestJarIndexInheritanceTree +{ + private JarIndex m_index; + + private ClassEntry m_baseClass = new ClassEntry( "none/a" ); + private ClassEntry m_subClassA = new ClassEntry( "none/b" ); + private ClassEntry m_subClassAA = new ClassEntry( "none/d" ); + private ClassEntry m_subClassB = new ClassEntry( "none/c" ); + private FieldEntry m_nameField = new FieldEntry( m_baseClass, "a" ); + private FieldEntry m_numThingsField = new FieldEntry( m_subClassB, "a" ); + + public TestJarIndexInheritanceTree( ) + throws Exception + { + m_index = new JarIndex(); + m_index.indexJar( new JarFile( "build/libs/testInheritanceTree.obf.jar" ), false ); + } + + @Test + public void obfEntries( ) + { + assertThat( m_index.getObfClassEntries(), containsInAnyOrder( + newClass( "cuchaz/enigma/inputs/Keep" ), + m_baseClass, + m_subClassA, + m_subClassAA, + m_subClassB + ) ); + } + + @Test + public void translationIndex( ) + { + TranslationIndex index = m_index.getTranslationIndex(); + + // base class + assertThat( index.getSuperclassName( m_baseClass.getName() ), is( nullValue() ) ); + assertThat( index.getAncestry( m_baseClass.getName() ), is( empty() ) ); + assertThat( index.getSubclassNames( m_baseClass.getName() ), containsInAnyOrder( + m_subClassA.getName(), + m_subClassB.getName() + ) ); + + // subclass a + assertThat( index.getSuperclassName( m_subClassA.getName() ), is( m_baseClass.getName() ) ); + assertThat( index.getAncestry( m_subClassA.getName() ), contains( m_baseClass.getName() ) ); + assertThat( index.getSubclassNames( m_subClassA.getName() ), contains( m_subClassAA.getName() ) ); + + // subclass aa + assertThat( index.getSuperclassName( m_subClassAA.getName() ), is( m_subClassA.getName() ) ); + assertThat( index.getAncestry( m_subClassAA.getName() ), contains( + m_subClassA.getName(), + m_baseClass.getName() + ) ); + assertThat( index.getSubclassNames( m_subClassAA.getName() ), is( empty() ) ); + + // subclass b + assertThat( index.getSuperclassName( m_subClassB.getName() ), is( m_baseClass.getName() ) ); + assertThat( index.getAncestry( m_subClassB.getName() ), contains( m_baseClass.getName() ) ); + assertThat( index.getSubclassNames( m_subClassB.getName() ), is( empty() ) ); + } + + @Test + public void access( ) + { + assertThat( m_index.getAccess( m_nameField ), is( Access.Private ) ); + assertThat( m_index.getAccess( m_numThingsField ), is( Access.Private ) ); + } + + @Test + public void isImplemented( ) + { + // getName() + assertThat( m_index.isMethodImplemented( new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ) ), is( true ) ); + assertThat( m_index.isMethodImplemented( new MethodEntry( m_subClassA, "a", "()Ljava/lang/String;" ) ), is( false ) ); + assertThat( m_index.isMethodImplemented( new MethodEntry( m_subClassAA, "a", "()Ljava/lang/String;" ) ), is( true ) ); + assertThat( m_index.isMethodImplemented( new MethodEntry( m_subClassB, "a", "()Ljava/lang/String;" ) ), is( false ) ); + + // doBaseThings() + assertThat( m_index.isMethodImplemented( new MethodEntry( m_baseClass, "a", "()V" ) ), is( true ) ); + assertThat( m_index.isMethodImplemented( new MethodEntry( m_subClassA, "a", "()V" ) ), is( false ) ); + assertThat( m_index.isMethodImplemented( new MethodEntry( m_subClassAA, "a", "()V" ) ), is( true ) ); + assertThat( m_index.isMethodImplemented( new MethodEntry( m_subClassB, "a", "()V" ) ), is( true ) ); + + // doBThings() + assertThat( m_index.isMethodImplemented( new MethodEntry( m_baseClass, "b", "()V" ) ), is( false ) ); + assertThat( m_index.isMethodImplemented( new MethodEntry( m_subClassA, "b", "()V" ) ), is( false ) ); + assertThat( m_index.isMethodImplemented( new MethodEntry( m_subClassAA, "b", "()V" ) ), is( false ) ); + assertThat( m_index.isMethodImplemented( new MethodEntry( m_subClassB, "b", "()V" ) ), is( true ) ); + } + + @Test + public void relatedMethodImplementations( ) + { + Set entries; + + // getName() + entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ) ); + assertThat( entries, containsInAnyOrder( + new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ), + new MethodEntry( m_subClassAA, "a", "()Ljava/lang/String;" ) + ) ); + entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_subClassAA, "a", "()Ljava/lang/String;" ) ); + assertThat( entries, containsInAnyOrder( + new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ), + new MethodEntry( m_subClassAA, "a", "()Ljava/lang/String;" ) + ) ); + + // doBaseThings() + entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_baseClass, "a", "()V" ) ); + assertThat( entries, containsInAnyOrder( + new MethodEntry( m_baseClass, "a", "()V" ), + new MethodEntry( m_subClassAA, "a", "()V" ), + new MethodEntry( m_subClassB, "a", "()V" ) + ) ); + entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_subClassAA, "a", "()V" ) ); + assertThat( entries, containsInAnyOrder( + new MethodEntry( m_baseClass, "a", "()V" ), + new MethodEntry( m_subClassAA, "a", "()V" ), + new MethodEntry( m_subClassB, "a", "()V" ) + ) ); + entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_subClassB, "a", "()V" ) ); + assertThat( entries, containsInAnyOrder( + new MethodEntry( m_baseClass, "a", "()V" ), + new MethodEntry( m_subClassAA, "a", "()V" ), + new MethodEntry( m_subClassB, "a", "()V" ) + ) ); + + // doBThings + entries = m_index.getRelatedMethodImplementations( new MethodEntry( m_subClassB, "b", "()V" ) ); + assertThat( entries, containsInAnyOrder( + new MethodEntry( m_subClassB, "b", "()V" ) + ) ); + } + + @Test + @SuppressWarnings( "unchecked" ) + public void fieldReferences( ) + { + Collection> references; + + // name + references = m_index.getFieldReferences( m_nameField ); + assertThat( references, containsInAnyOrder( + newFieldReferenceByConstructor( m_nameField, m_baseClass.getName(), "(Ljava/lang/String;)V" ), + newFieldReferenceByMethod( m_nameField, m_baseClass.getName(), "a", "()Ljava/lang/String;" ) + ) ); + + // numThings + references = m_index.getFieldReferences( m_numThingsField ); + assertThat( references, containsInAnyOrder( + newFieldReferenceByConstructor( m_numThingsField, m_subClassB.getName(), "()V" ), + newFieldReferenceByMethod( m_numThingsField, m_subClassB.getName(), "b", "()V" ) + ) ); + } + + @Test + @SuppressWarnings( "unchecked" ) + public void behaviorReferences( ) + { + BehaviorEntry source; + Collection> references; + + // baseClass constructor + source = new ConstructorEntry( m_baseClass, "(Ljava/lang/String;)V" ); + references = m_index.getBehaviorReferences( source ); + assertThat( references, containsInAnyOrder( + newBehaviorReferenceByConstructor( source, m_subClassA.getName(), "(Ljava/lang/String;)V" ), + newBehaviorReferenceByConstructor( source, m_subClassB.getName(), "()V" ) + ) ); + + // subClassA constructor + source = new ConstructorEntry( m_subClassA, "(Ljava/lang/String;)V" ); + references = m_index.getBehaviorReferences( source ); + assertThat( references, containsInAnyOrder( + newBehaviorReferenceByConstructor( source, m_subClassAA.getName(), "()V" ) + ) ); + + // baseClass.getName() + source = new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ); + references = m_index.getBehaviorReferences( source ); + assertThat( references, containsInAnyOrder( + newBehaviorReferenceByMethod( source, m_subClassAA.getName(), "a", "()Ljava/lang/String;" ) + ) ); + + // subclassAA.getName() + source = new MethodEntry( m_subClassAA, "a", "()Ljava/lang/String;" ); + references = m_index.getBehaviorReferences( source ); + assertThat( references, containsInAnyOrder( + newBehaviorReferenceByMethod( source, m_subClassAA.getName(), "a", "()V" ) + ) ); + } + + @Test + public void containsEntries( ) + { + // classes + assertThat( m_index.containsObfClass( m_baseClass ), is( true ) ); + assertThat( m_index.containsObfClass( m_subClassA ), is( true ) ); + assertThat( m_index.containsObfClass( m_subClassAA ), is( true ) ); + assertThat( m_index.containsObfClass( m_subClassB ), is( true ) ); + + // fields + assertThat( m_index.containsObfField( m_nameField ), is( true ) ); + assertThat( m_index.containsObfField( m_numThingsField ), is( true ) ); + + // methods + assertThat( m_index.containsObfMethod( new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ) ), is( true ) ); + assertThat( m_index.containsObfMethod( new MethodEntry( m_baseClass, "a", "()V" ) ), is( true ) ); + assertThat( m_index.containsObfMethod( new MethodEntry( m_subClassAA, "a", "()Ljava/lang/String;" ) ), is( true ) ); + assertThat( m_index.containsObfMethod( new MethodEntry( m_subClassAA, "a", "()V" ) ), is( true ) ); + assertThat( m_index.containsObfMethod( new MethodEntry( m_subClassB, "a", "()V" ) ), is( true ) ); + assertThat( m_index.containsObfMethod( new MethodEntry( m_subClassB, "b", "()V" ) ), is( true ) ); + } +} diff --git a/test/cuchaz/enigma/TestJarIndexLoneClass.java b/test/cuchaz/enigma/TestJarIndexLoneClass.java index 56031ddc..9236d0c1 100644 --- a/test/cuchaz/enigma/TestJarIndexLoneClass.java +++ b/test/cuchaz/enigma/TestJarIndexLoneClass.java @@ -95,7 +95,6 @@ public class TestJarIndexLoneClass assertThat( node.getObfClassName(), is( "none/a" ) ); assertThat( node.getChildCount(), is( 0 ) ); } - @Test public void methodInheritance( ) @@ -133,10 +132,11 @@ public class TestJarIndexLoneClass @SuppressWarnings( "unchecked" ) public void fieldReferences( ) { - Collection> references = m_index.getFieldReferences( newField( "none/a", "a" ) ); + FieldEntry source = newField( "none/a", "a" ); + Collection> references = m_index.getFieldReferences( source ); assertThat( references, containsInAnyOrder( - newFieldReferenceByConstructor( "none/a", "a", "none/a", "(Ljava/lang/String;)V" ), - newFieldReferenceByMethod( "none/a", "a", "none/a", "a", "()Ljava/lang/String;" ) + newFieldReferenceByConstructor( source, "none/a", "(Ljava/lang/String;)V" ), + newFieldReferenceByMethod( source, "none/a", "a", "()Ljava/lang/String;" ) ) ); } diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java b/test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java new file mode 100644 index 00000000..a6b38454 --- /dev/null +++ b/test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java @@ -0,0 +1,18 @@ +package cuchaz.enigma.inputs.inheritanceTree; + +public abstract class BaseClass +{ + private String m_name; + + protected BaseClass( String name ) + { + m_name = name; + } + + public String getName( ) + { + return m_name; + } + + public abstract void doBaseThings( ); +} diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java new file mode 100644 index 00000000..f4780a26 --- /dev/null +++ b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java @@ -0,0 +1,9 @@ +package cuchaz.enigma.inputs.inheritanceTree; + +public abstract class SubclassA extends BaseClass +{ + protected SubclassA( String name ) + { + super( name ); + } +} diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java new file mode 100644 index 00000000..4001e7a3 --- /dev/null +++ b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java @@ -0,0 +1,24 @@ +package cuchaz.enigma.inputs.inheritanceTree; + +public class SubclassB extends BaseClass +{ + private int m_numThings; + + protected SubclassB( ) + { + super( "B" ); + + m_numThings = 4; + } + + @Override + public void doBaseThings( ) + { + System.out.println( "Base things by B!" ); + } + + public void doBThings( ) + { + System.out.println( "" + m_numThings + " B things!" ); + } +} diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java b/test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java new file mode 100644 index 00000000..11196d16 --- /dev/null +++ b/test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java @@ -0,0 +1,21 @@ +package cuchaz.enigma.inputs.inheritanceTree; + +public class SubsubclassAA extends SubclassA +{ + protected SubsubclassAA( ) + { + super( "AA" ); + } + + @Override + public String getName( ) + { + return "subsub" + super.getName(); + } + + @Override + public void doBaseThings( ) + { + System.out.println( "Base things by " + getName() ); + } +} -- cgit v1.2.3