blob: ad9055c77c9fed3b9526bdc166950f46d53b13f7 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tools.layoutlib.create;
import com.android.tools.layoutlib.create.AsmAnalyzer.DependencyVisitor;
import com.android.tools.layoutlib.create.AsmAnalyzer.Result;
import org.junit.Test;
import org.objectweb.asm.ClassReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Unit tests for some methods of {@link AsmAnalyzer}.
*/
public class AsmAnalyzerTest {
private static final List<String> MOCK_ANDROID_JAR;
private static final String[] DEFAULT_EXCLUDES = new String[]{"notjava.lang.JavaClass"};
private static final String[] DEFAULT_INCLUDE_FILES = new String[]{"mock_android/data/data*"};
static {
List<String> mockJar = new ArrayList<>();
URL url = AsmAnalyzerTest.class.getClassLoader().getResource("data/mock_android.jar");
assert url != null : "Unable to locate mock_android.jar";
mockJar.add(url.getFile());
MOCK_ANDROID_JAR = Collections.unmodifiableList(mockJar);
}
private static AsmAnalyzer getDefaultAnalyzer() {
MockLog log = new MockLog();
return new AsmAnalyzer(log, MOCK_ANDROID_JAR, null ,
null /* includeGlobs */, DEFAULT_EXCLUDES, DEFAULT_INCLUDE_FILES);
}
@Test
public void testParseZip() throws IOException {
Map<String, ClassReader> map = new TreeMap<>();
Map<String, InputStream> filesFound = new TreeMap<>();
getDefaultAnalyzer().parseZip(MOCK_ANDROID_JAR, map, filesFound);
assertArrayEquals(new String[] {
"mock_android.fake.FakeClass",
"mock_android.fake.InnerTest",
"mock_android.fake.InnerTest$1",
"mock_android.fake.InnerTest$DerivingClass",
"mock_android.fake.InnerTest$MyGenerics1",
"mock_android.fake.InnerTest$MyIntEnum",
"mock_android.fake.InnerTest$MyStaticInnerClass",
"mock_android.fake.InnerTest$NotStaticInner1",
"mock_android.fake.InnerTest$NotStaticInner2",
"mock_android.fake.subpackage.SubpackageClassA",
"mock_android.fake.subpackage.SubpackageClassB",
"mock_android.fake.subpackage.SubpackageClassC",
"mock_android.fake.subpackage.SubpackageClassC$InnerClass",
"mock_android.fake.subpackage.SubpackageClassC$StaticInnerClass",
"mock_android.fake2.FakeClass",
"mock_android.fake2.keep.DoNotRemove",
"mock_android.util.EmptyArray",
"mock_android.util.NotNeeded",
"mock_android.view.View",
"mock_android.view.ViewGroup",
"mock_android.view.ViewGroup$LayoutParams",
"mock_android.view.ViewGroup$MarginLayoutParams",
"mock_android.widget.LinearLayout",
"mock_android.widget.LinearLayout$LayoutParams",
"mock_android.widget.TableLayout",
"mock_android.widget.TableLayout$LayoutParams",
"notjava.lang.JavaClass",
},
map.keySet().toArray());
assertArrayEquals(new String[] {"mock_android/data/dataFile"},
filesFound.keySet().toArray());
}
@Test
public void testFindClass() throws IOException {
Map<String, ClassReader> zipClasses = new TreeMap<>();
Map<String, InputStream> filesFound = new TreeMap<>();
getDefaultAnalyzer().parseZip(MOCK_ANDROID_JAR, zipClasses, filesFound);
TreeMap<String, ClassReader> found = new TreeMap<>();
ClassReader cr = AsmAnalyzer.findClass("mock_android.view.ViewGroup$LayoutParams",
zipClasses, found);
assertNotNull(cr);
assertEquals("mock_android/view/ViewGroup$LayoutParams", cr.getClassName());
assertArrayEquals(new String[] { "mock_android.view.ViewGroup$LayoutParams" },
found.keySet().toArray());
assertArrayEquals(new ClassReader[] { cr }, found.values().toArray());
}
@Test
public void testInclude() throws IOException {
AsmAnalyzer analyzer = new AsmAnalyzer(new MockLog(), MOCK_ANDROID_JAR, null,
new String[] {
"mock_android.util.EmptyArray", // Single class select
"mock_android.fake.**", // Multi package select
"mock_android.fake2.*", // Exclude subpackages select
},
DEFAULT_EXCLUDES,
DEFAULT_INCLUDE_FILES);
Result result = analyzer.analyze();
assertArrayEquals(new String[] {
"mock_android.fake.FakeClass",
"mock_android.fake.InnerTest$MyIntEnum",
"mock_android.util.EmptyArray",
"mock_android.fake.InnerTest$DerivingClass",
"mock_android.fake2.FakeClass",
"mock_android.fake.subpackage.SubpackageClassC$InnerClass",
"mock_android.fake.InnerTest$MyGenerics1",
"mock_android.fake.subpackage.SubpackageClassC$StaticInnerClass",
"mock_android.fake.InnerTest$MyStaticInnerClass",
"mock_android.fake.InnerTest$NotStaticInner1",
"mock_android.fake.InnerTest$NotStaticInner2",
"mock_android.fake.subpackage.SubpackageClassA",
"mock_android.fake.InnerTest",
"mock_android.fake.InnerTest$1",
"mock_android.fake.subpackage.SubpackageClassC",
"mock_android.fake.subpackage.SubpackageClassB",
},
result.getFound().keySet().toArray());
}
@Test
public void testFindClassesDerivingFrom() throws IOException {
Map<String, ClassReader> zipClasses = new TreeMap<>();
Map<String, InputStream> filesFound = new TreeMap<>();
getDefaultAnalyzer().parseZip(MOCK_ANDROID_JAR, zipClasses, filesFound);
TreeMap<String, ClassReader> found = new TreeMap<>();
AsmAnalyzer.findClassesDerivingFrom("mock_android.view.View", zipClasses, found);
assertArrayEquals(new String[] {
"mock_android.view.View",
"mock_android.view.ViewGroup",
"mock_android.widget.LinearLayout",
"mock_android.widget.TableLayout",
},
found.keySet().toArray());
for (String key : found.keySet()) {
ClassReader value = found.get(key);
assertNotNull("No value for " + key, value);
assertEquals(key, AsmAnalyzer.classReaderToClassName(value));
}
}
@Test
public void testDependencyVisitor() throws IOException {
Map<String, ClassReader> zipClasses = new TreeMap<>();
Map<String, InputStream> filesFound = new TreeMap<>();
getDefaultAnalyzer().parseZip(MOCK_ANDROID_JAR, zipClasses, filesFound);
TreeMap<String, ClassReader> keep = new TreeMap<>();
TreeMap<String, ClassReader> new_keep = new TreeMap<>();
TreeMap<String, ClassReader> in_deps = new TreeMap<>();
TreeMap<String, ClassReader> out_deps = new TreeMap<>();
ClassReader cr = AsmAnalyzer.findClass("mock_android.widget.LinearLayout", zipClasses, keep);
DependencyVisitor visitor = getDefaultAnalyzer().getVisitor(zipClasses, keep, new_keep, in_deps, out_deps);
// get first level dependencies
cr.accept(visitor, 0 /* flags */);
assertArrayEquals(new String[] {
"mock_android.util.EmptyArray",
"mock_android.view.ViewGroup",
"mock_android.widget.LinearLayout$LayoutParams",
},
out_deps.keySet().toArray());
in_deps.putAll(out_deps);
out_deps.clear();
// get second level dependencies
for (ClassReader cr2 : in_deps.values()) {
cr2.accept(visitor, 0 /* flags */);
}
assertArrayEquals(new String[] {
"mock_android.view.View",
"mock_android.view.ViewGroup$LayoutParams",
"mock_android.view.ViewGroup$MarginLayoutParams",
},
out_deps.keySet().toArray());
in_deps.putAll(out_deps);
out_deps.clear();
// get third level dependencies (there are none)
for (ClassReader cr2 : in_deps.values()) {
cr2.accept(visitor, 0 /* flags */);
}
keep.putAll(new_keep);
assertArrayEquals(new String[] { }, out_deps.keySet().toArray());
assertArrayEquals(new String[] {
"mock_android.widget.LinearLayout",
"notjava.lang.JavaClass",
}, keep.keySet().toArray());
}
}