1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
/*******************************************************************************
* Copyright (c) 2015 Jeff Martin.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public
* License v3.0 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl.html
*
* Contributors:
* Jeff Martin - initial API and implementation
******************************************************************************/
package cuchaz.enigma;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import java.util.jar.JarFile;
import org.junit.Test;
import static cuchaz.enigma.TestEntryFactory.*;
import cuchaz.enigma.analysis.JarIndex;
import cuchaz.enigma.mapping.ClassEntry;
public class TestInnerClasses {
private JarIndex m_index;
private Deobfuscator m_deobfuscator;
private static final ClassEntry AnonymousOuter = newClass("none/a");
private static final ClassEntry AnonymousInner = newClass("none/a$1");
private static final ClassEntry SimpleOuter = newClass("none/d");
private static final ClassEntry SimpleInner = newClass("none/d$a");
private static final ClassEntry ConstructorArgsOuter = newClass("none/c");
private static final ClassEntry ConstructorArgsInner = newClass("none/c$a");
private static final ClassEntry AnonymousWithScopeArgsOuter = newClass("none/b");
private static final ClassEntry AnonymousWithScopeArgsInner = newClass("none/b$1");
private static final ClassEntry AnonymousWithOuterAccessOuter = newClass("none/e");
private static final ClassEntry AnonymousWithOuterAccessInner = newClass("none/e$1");
private static final ClassEntry ClassTreeRoot = newClass("none/f");
private static final ClassEntry ClassTreeLevel1 = newClass("none/f$a");
private static final ClassEntry ClassTreeLevel2 = newClass("none/f$a$a");
private static final ClassEntry ClassTreeLevel3 = newClass("none/f$a$a$a");
public TestInnerClasses()
throws Exception {
m_index = new JarIndex();
JarFile jar = new JarFile("build/test-obf/innerClasses.jar");
m_index.indexJar(jar, true);
m_deobfuscator = new Deobfuscator(jar);
}
@Test
public void simple() {
assertThat(m_index.getOuterClass(SimpleInner), is(SimpleOuter));
assertThat(m_index.getInnerClasses(SimpleOuter), containsInAnyOrder(SimpleInner));
assertThat(m_index.isAnonymousClass(SimpleInner), is(false));
decompile(SimpleOuter);
}
@Test
public void anonymous() {
assertThat(m_index.getOuterClass(AnonymousInner), is(AnonymousOuter));
assertThat(m_index.getInnerClasses(AnonymousOuter), containsInAnyOrder(AnonymousInner));
assertThat(m_index.isAnonymousClass(AnonymousInner), is(true));
decompile(AnonymousOuter);
}
@Test
public void constructorArgs() {
assertThat(m_index.getOuterClass(ConstructorArgsInner), is(ConstructorArgsOuter));
assertThat(m_index.getInnerClasses(ConstructorArgsOuter), containsInAnyOrder(ConstructorArgsInner));
assertThat(m_index.isAnonymousClass(ConstructorArgsInner), is(false));
decompile(ConstructorArgsOuter);
}
@Test
public void anonymousWithScopeArgs() {
assertThat(m_index.getOuterClass(AnonymousWithScopeArgsInner), is(AnonymousWithScopeArgsOuter));
assertThat(m_index.getInnerClasses(AnonymousWithScopeArgsOuter), containsInAnyOrder(AnonymousWithScopeArgsInner));
assertThat(m_index.isAnonymousClass(AnonymousWithScopeArgsInner), is(true));
decompile(AnonymousWithScopeArgsOuter);
}
@Test
public void anonymousWithOuterAccess() {
assertThat(m_index.getOuterClass(AnonymousWithOuterAccessInner), is(AnonymousWithOuterAccessOuter));
assertThat(m_index.getInnerClasses(AnonymousWithOuterAccessOuter), containsInAnyOrder(AnonymousWithOuterAccessInner));
assertThat(m_index.isAnonymousClass(AnonymousWithOuterAccessInner), is(true));
decompile(AnonymousWithOuterAccessOuter);
}
@Test
public void classTree() {
// root level
assertThat(m_index.containsObfClass(ClassTreeRoot), is(true));
assertThat(m_index.getOuterClass(ClassTreeRoot), is(nullValue()));
assertThat(m_index.getInnerClasses(ClassTreeRoot), containsInAnyOrder(ClassTreeLevel1));
// level 1
ClassEntry fullClassEntry = new ClassEntry(ClassTreeRoot.getName()
+ "$" + ClassTreeLevel1.getInnermostClassName()
);
assertThat(m_index.containsObfClass(fullClassEntry), is(true));
assertThat(m_index.getOuterClass(ClassTreeLevel1), is(ClassTreeRoot));
assertThat(m_index.getInnerClasses(ClassTreeLevel1), containsInAnyOrder(ClassTreeLevel2));
// level 2
fullClassEntry = new ClassEntry(ClassTreeRoot.getName()
+ "$" + ClassTreeLevel1.getInnermostClassName()
+ "$" + ClassTreeLevel2.getInnermostClassName()
);
assertThat(m_index.containsObfClass(fullClassEntry), is(true));
assertThat(m_index.getOuterClass(ClassTreeLevel2), is(ClassTreeLevel1));
assertThat(m_index.getInnerClasses(ClassTreeLevel2), containsInAnyOrder(ClassTreeLevel3));
// level 3
fullClassEntry = new ClassEntry(ClassTreeRoot.getName()
+ "$" + ClassTreeLevel1.getInnermostClassName()
+ "$" + ClassTreeLevel2.getInnermostClassName()
+ "$" + ClassTreeLevel3.getInnermostClassName()
);
assertThat(m_index.containsObfClass(fullClassEntry), is(true));
assertThat(m_index.getOuterClass(ClassTreeLevel3), is(ClassTreeLevel2));
assertThat(m_index.getInnerClasses(ClassTreeLevel3), is(empty()));
}
private void decompile(ClassEntry classEntry) {
m_deobfuscator.getSourceTree(classEntry.getName());
}
}
|