1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18package com.android.tools.layoutlib.create;
19
20import static org.junit.Assert.assertArrayEquals;
21import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.assertNotNull;
23
24import com.android.tools.layoutlib.create.AsmAnalyzer.DependencyVisitor;
25
26import org.junit.After;
27import org.junit.Before;
28import org.junit.Test;
29import org.objectweb.asm.ClassReader;
30
31import java.io.IOException;
32import java.io.InputStream;
33import java.net.URL;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Map;
37import java.util.Set;
38import java.util.TreeMap;
39
40/**
41 * Unit tests for some methods of {@link AsmAnalyzer}.
42 */
43public class AsmAnalyzerTest {
44
45    private MockLog mLog;
46    private ArrayList<String> mOsJarPath;
47    private AsmAnalyzer mAa;
48
49    @Before
50    public void setUp() throws Exception {
51        mLog = new MockLog();
52        URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar");
53
54        mOsJarPath = new ArrayList<String>();
55        mOsJarPath.add(url.getFile());
56
57        Set<String> excludeClasses = new HashSet<String>(1);
58        excludeClasses.add("java.lang.JavaClass");
59
60        String[] includeFiles = new String[]{"mock_android/data/data*"};
61        mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */, null /* deriveFrom */,
62                null /* includeGlobs */, excludeClasses, includeFiles);
63    }
64
65    @After
66    public void tearDown() throws Exception {
67    }
68
69    @Test
70    public void testParseZip() throws IOException {
71
72        Map<String, ClassReader> map = new TreeMap<String, ClassReader>();
73        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
74
75        mAa.parseZip(mOsJarPath, map, filesFound);
76
77        assertArrayEquals(new String[] {
78                "java.lang.JavaClass",
79                "mock_android.dummy.InnerTest",
80                "mock_android.dummy.InnerTest$DerivingClass",
81                "mock_android.dummy.InnerTest$MyGenerics1",
82                "mock_android.dummy.InnerTest$MyIntEnum",
83                "mock_android.dummy.InnerTest$MyStaticInnerClass",
84                "mock_android.dummy.InnerTest$NotStaticInner1",
85                "mock_android.dummy.InnerTest$NotStaticInner2",
86                "mock_android.util.EmptyArray",
87                "mock_android.view.View",
88                "mock_android.view.ViewGroup",
89                "mock_android.view.ViewGroup$LayoutParams",
90                "mock_android.view.ViewGroup$MarginLayoutParams",
91                "mock_android.widget.LinearLayout",
92                "mock_android.widget.LinearLayout$LayoutParams",
93                "mock_android.widget.TableLayout",
94                "mock_android.widget.TableLayout$LayoutParams"
95            },
96            map.keySet().toArray());
97        assertArrayEquals(new String[] {"mock_android/data/dataFile"},
98            filesFound.keySet().toArray());
99    }
100
101    @Test
102    public void testFindClass() throws IOException, LogAbortException {
103
104        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
105        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
106
107        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
108        TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
109
110        ClassReader cr = mAa.findClass("mock_android.view.ViewGroup$LayoutParams",
111                zipClasses, found);
112
113        assertNotNull(cr);
114        assertEquals("mock_android/view/ViewGroup$LayoutParams", cr.getClassName());
115        assertArrayEquals(new String[] { "mock_android.view.ViewGroup$LayoutParams" },
116                found.keySet().toArray());
117        assertArrayEquals(new ClassReader[] { cr }, found.values().toArray());
118    }
119
120    @Test
121    public void testFindGlobs() throws IOException, LogAbortException {
122
123        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
124        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
125
126        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
127        TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
128
129        // this matches classes, a package match returns nothing
130        found.clear();
131        mAa.findGlobs("mock_android.view", zipClasses, found);
132
133        assertArrayEquals(new String[] { },
134            found.keySet().toArray());
135
136        // a complex glob search. * is a search pattern that matches names, not dots
137        mAa.findGlobs("mock_android.*.*Group$*Layout*", zipClasses, found);
138
139        assertArrayEquals(new String[] {
140                "mock_android.view.ViewGroup$LayoutParams",
141                "mock_android.view.ViewGroup$MarginLayoutParams"
142            },
143            found.keySet().toArray());
144
145        // a complex glob search. ** is a search pattern that matches names including dots
146        mAa.findGlobs("mock_android.**Group*", zipClasses, found);
147
148        assertArrayEquals(new String[] {
149                "mock_android.view.ViewGroup",
150                "mock_android.view.ViewGroup$LayoutParams",
151                "mock_android.view.ViewGroup$MarginLayoutParams"
152            },
153            found.keySet().toArray());
154
155        // matches a single class
156        found.clear();
157        mAa.findGlobs("mock_android.view.View", zipClasses, found);
158
159        assertArrayEquals(new String[] {
160                "mock_android.view.View"
161            },
162            found.keySet().toArray());
163
164        // matches everyting inside the given package but not sub-packages
165        found.clear();
166        mAa.findGlobs("mock_android.view.*", zipClasses, found);
167
168        assertArrayEquals(new String[] {
169                "mock_android.view.View",
170                "mock_android.view.ViewGroup",
171                "mock_android.view.ViewGroup$LayoutParams",
172                "mock_android.view.ViewGroup$MarginLayoutParams"
173            },
174            found.keySet().toArray());
175
176        for (String key : found.keySet()) {
177            ClassReader value = found.get(key);
178            assertNotNull("No value for " + key, value);
179            assertEquals(key, AsmAnalyzer.classReaderToClassName(value));
180        }
181    }
182
183    @Test
184    public void testFindClassesDerivingFrom() throws LogAbortException, IOException {
185
186        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
187        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
188
189        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
190        TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
191
192        mAa.findClassesDerivingFrom("mock_android.view.View", zipClasses, found);
193
194        assertArrayEquals(new String[] {
195                "mock_android.view.View",
196                "mock_android.view.ViewGroup",
197                "mock_android.widget.LinearLayout",
198                "mock_android.widget.TableLayout",
199            },
200            found.keySet().toArray());
201
202        for (String key : found.keySet()) {
203            ClassReader value = found.get(key);
204            assertNotNull("No value for " + key, value);
205            assertEquals(key, AsmAnalyzer.classReaderToClassName(value));
206        }
207    }
208
209    @Test
210    public void testDependencyVisitor() throws IOException, LogAbortException {
211
212        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
213        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
214
215        mAa.parseZip(mOsJarPath, zipClasses, filesFound);
216        TreeMap<String, ClassReader> keep = new TreeMap<String, ClassReader>();
217        TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>();
218        TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>();
219        TreeMap<String, ClassReader> out_deps = new TreeMap<String, ClassReader>();
220
221        ClassReader cr = mAa.findClass("mock_android.widget.LinearLayout", zipClasses, keep);
222        DependencyVisitor visitor = mAa.getVisitor(zipClasses, keep, new_keep, in_deps, out_deps);
223
224        // get first level dependencies
225        cr.accept(visitor, 0 /* flags */);
226
227        assertArrayEquals(new String[] {
228                "mock_android.util.EmptyArray",
229                "mock_android.view.ViewGroup",
230                "mock_android.widget.LinearLayout$LayoutParams",
231            },
232            out_deps.keySet().toArray());
233
234        in_deps.putAll(out_deps);
235        out_deps.clear();
236
237        // get second level dependencies
238        for (ClassReader cr2 : in_deps.values()) {
239            cr2.accept(visitor, 0 /* flags */);
240        }
241
242        assertArrayEquals(new String[] {
243                "mock_android.view.View",
244                "mock_android.view.ViewGroup$LayoutParams",
245                "mock_android.view.ViewGroup$MarginLayoutParams",
246            },
247            out_deps.keySet().toArray());
248
249        in_deps.putAll(out_deps);
250        out_deps.clear();
251
252        // get third level dependencies (there are none)
253        for (ClassReader cr2 : in_deps.values()) {
254            cr2.accept(visitor, 0 /* flags */);
255        }
256        keep.putAll(new_keep);
257
258        assertArrayEquals(new String[] { }, out_deps.keySet().toArray());
259        assertArrayEquals(new String[] {
260                "mock_android.widget.LinearLayout",
261        }, keep.keySet().toArray());
262    }
263}
264