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