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.net.URL;
33import java.util.ArrayList;
34import java.util.HashSet;
35import java.util.Map;
36import java.util.Set;
37import java.util.TreeMap;
38
39/**
40 * Unit tests for some methods of {@link AsmAnalyzer}.
41 */
42public class AsmAnalyzerTest {
43
44    private MockLog mLog;
45    private ArrayList<String> mOsJarPath;
46    private AsmAnalyzer mAa;
47
48    @Before
49    public void setUp() throws Exception {
50        mLog = new MockLog();
51        URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar");
52
53        mOsJarPath = new ArrayList<String>();
54        mOsJarPath.add(url.getFile());
55
56        Set<String> excludeClasses = new HashSet<String>(1);
57        excludeClasses.add("java.lang.JavaClass");
58        mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */,
59                null /* deriveFrom */, null /* includeGlobs */, excludeClasses);
60    }
61
62    @After
63    public void tearDown() throws Exception {
64    }
65
66    @Test
67    public void testParseZip() throws IOException {
68        Map<String, ClassReader> map = mAa.parseZip(mOsJarPath);
69
70        assertArrayEquals(new String[] {
71                "java.lang.JavaClass",
72                "mock_android.dummy.InnerTest",
73                "mock_android.dummy.InnerTest$DerivingClass",
74                "mock_android.dummy.InnerTest$MyGenerics1",
75                "mock_android.dummy.InnerTest$MyIntEnum",
76                "mock_android.dummy.InnerTest$MyStaticInnerClass",
77                "mock_android.dummy.InnerTest$NotStaticInner1",
78                "mock_android.dummy.InnerTest$NotStaticInner2",
79                "mock_android.view.View",
80                "mock_android.view.ViewGroup",
81                "mock_android.view.ViewGroup$LayoutParams",
82                "mock_android.view.ViewGroup$MarginLayoutParams",
83                "mock_android.widget.LinearLayout",
84                "mock_android.widget.LinearLayout$LayoutParams",
85                "mock_android.widget.TableLayout",
86                "mock_android.widget.TableLayout$LayoutParams"
87            },
88            map.keySet().toArray());
89    }
90
91    @Test
92    public void testFindClass() throws IOException, LogAbortException {
93        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
94        TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
95
96        ClassReader cr = mAa.findClass("mock_android.view.ViewGroup$LayoutParams",
97                zipClasses, found);
98
99        assertNotNull(cr);
100        assertEquals("mock_android/view/ViewGroup$LayoutParams", cr.getClassName());
101        assertArrayEquals(new String[] { "mock_android.view.ViewGroup$LayoutParams" },
102                found.keySet().toArray());
103        assertArrayEquals(new ClassReader[] { cr }, found.values().toArray());
104    }
105
106    @Test
107    public void testFindGlobs() throws IOException, LogAbortException {
108        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
109        TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
110
111        // this matches classes, a package match returns nothing
112        found.clear();
113        mAa.findGlobs("mock_android.view", zipClasses, found);
114
115        assertArrayEquals(new String[] { },
116            found.keySet().toArray());
117
118        // a complex glob search. * is a search pattern that matches names, not dots
119        mAa.findGlobs("mock_android.*.*Group$*Layout*", zipClasses, found);
120
121        assertArrayEquals(new String[] {
122                "mock_android.view.ViewGroup$LayoutParams",
123                "mock_android.view.ViewGroup$MarginLayoutParams"
124            },
125            found.keySet().toArray());
126
127        // a complex glob search. ** is a search pattern that matches names including dots
128        mAa.findGlobs("mock_android.**Group*", zipClasses, found);
129
130        assertArrayEquals(new String[] {
131                "mock_android.view.ViewGroup",
132                "mock_android.view.ViewGroup$LayoutParams",
133                "mock_android.view.ViewGroup$MarginLayoutParams"
134            },
135            found.keySet().toArray());
136
137        // matches a single class
138        found.clear();
139        mAa.findGlobs("mock_android.view.View", zipClasses, found);
140
141        assertArrayEquals(new String[] {
142                "mock_android.view.View"
143            },
144            found.keySet().toArray());
145
146        // matches everyting inside the given package but not sub-packages
147        found.clear();
148        mAa.findGlobs("mock_android.view.*", zipClasses, found);
149
150        assertArrayEquals(new String[] {
151                "mock_android.view.View",
152                "mock_android.view.ViewGroup",
153                "mock_android.view.ViewGroup$LayoutParams",
154                "mock_android.view.ViewGroup$MarginLayoutParams"
155            },
156            found.keySet().toArray());
157
158        for (String key : found.keySet()) {
159            ClassReader value = found.get(key);
160            assertNotNull("No value for " + key, value);
161            assertEquals(key, AsmAnalyzer.classReaderToClassName(value));
162        }
163    }
164
165    @Test
166    public void testFindClassesDerivingFrom() throws LogAbortException, IOException {
167        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
168        TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
169
170        mAa.findClassesDerivingFrom("mock_android.view.View", zipClasses, found);
171
172        assertArrayEquals(new String[] {
173                "mock_android.view.View",
174                "mock_android.view.ViewGroup",
175                "mock_android.widget.LinearLayout",
176                "mock_android.widget.TableLayout",
177            },
178            found.keySet().toArray());
179
180        for (String key : found.keySet()) {
181            ClassReader value = found.get(key);
182            assertNotNull("No value for " + key, value);
183            assertEquals(key, AsmAnalyzer.classReaderToClassName(value));
184        }
185    }
186
187    @Test
188    public void testDependencyVisitor() throws IOException, LogAbortException {
189        Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
190        TreeMap<String, ClassReader> keep = new TreeMap<String, ClassReader>();
191        TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>();
192        TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>();
193        TreeMap<String, ClassReader> out_deps = new TreeMap<String, ClassReader>();
194
195        ClassReader cr = mAa.findClass("mock_android.widget.TableLayout", zipClasses, keep);
196        DependencyVisitor visitor = mAa.getVisitor(zipClasses, keep, new_keep, in_deps, out_deps);
197
198        // get first level dependencies
199        cr.accept(visitor, 0 /* flags */);
200
201        assertArrayEquals(new String[] {
202                "mock_android.view.ViewGroup",
203                "mock_android.widget.TableLayout$LayoutParams",
204            },
205            out_deps.keySet().toArray());
206
207        in_deps.putAll(out_deps);
208        out_deps.clear();
209
210        // get second level dependencies
211        for (ClassReader cr2 : in_deps.values()) {
212            cr2.accept(visitor, 0 /* flags */);
213        }
214
215        assertArrayEquals(new String[] {
216                "mock_android.view.View",
217                "mock_android.view.ViewGroup$LayoutParams",
218                "mock_android.view.ViewGroup$MarginLayoutParams",
219            },
220            out_deps.keySet().toArray());
221
222        in_deps.putAll(out_deps);
223        out_deps.clear();
224
225        // get third level dependencies (there are none)
226        for (ClassReader cr2 : in_deps.values()) {
227            cr2.accept(visitor, 0 /* flags */);
228        }
229        keep.putAll(new_keep);
230
231        assertArrayEquals(new String[] { }, out_deps.keySet().toArray());
232        assertArrayEquals(new String[] {
233                "mock_android.widget.TableLayout",
234        }, keep.keySet().toArray());
235    }
236}
237