M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
@@ -0,0 +1,227 @@
/*
* Copyright (C) 2008 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 static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import com.android.tools.layoutlib.create.AsmAnalyzer.DependencyVisitor;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.objectweb.asm.ClassReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
/**
* Unit tests for some methods of {@link AsmAnalyzer}.
*/
public class AsmAnalyzerTest {
private MockLog mLog;
private ArrayList<String> mOsJarPath;
private AsmAnalyzer mAa;
@Before
public void setUp() throws Exception {
mLog = new MockLog();
URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar");
mOsJarPath = new ArrayList<String>();
mOsJarPath.add(url.getFile());
mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */,
null /* deriveFrom */, null /* includeGlobs */ );
}
@After
public void tearDown() throws Exception {
}
@Test
public void testParseZip() throws IOException {
Map<String, ClassReader> map = mAa.parseZip(mOsJarPath);
assertArrayEquals(new String[] {
"mock_android.dummy.InnerTest",
"mock_android.dummy.InnerTest$DerivingClass",
"mock_android.dummy.InnerTest$MyGenerics1",
"mock_android.dummy.InnerTest$MyIntEnum",
"mock_android.dummy.InnerTest$MyStaticInnerClass",
"mock_android.dummy.InnerTest$NotStaticInner1",
"mock_android.dummy.InnerTest$NotStaticInner2",
"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"
},
map.keySet().toArray());
}
@Test
public void testFindClass() throws IOException, LogAbortException {
Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
ClassReader cr = mAa.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 testFindGlobs() throws IOException, LogAbortException {
Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
// this matches classes, a package match returns nothing
found.clear();
mAa.findGlobs("mock_android.view", zipClasses, found);
assertArrayEquals(new String[] { },
found.keySet().toArray());
// a complex glob search. * is a search pattern that matches names, not dots
mAa.findGlobs("mock_android.*.*Group$*Layout*", zipClasses, found);
assertArrayEquals(new String[] {
"mock_android.view.ViewGroup$LayoutParams",
"mock_android.view.ViewGroup$MarginLayoutParams"
},
found.keySet().toArray());
// a complex glob search. ** is a search pattern that matches names including dots
mAa.findGlobs("mock_android.**Group*", zipClasses, found);
assertArrayEquals(new String[] {
"mock_android.view.ViewGroup",
"mock_android.view.ViewGroup$LayoutParams",
"mock_android.view.ViewGroup$MarginLayoutParams"
},
found.keySet().toArray());
// matches a single class
found.clear();
mAa.findGlobs("mock_android.view.View", zipClasses, found);
assertArrayEquals(new String[] {
"mock_android.view.View"
},
found.keySet().toArray());
// matches everyting inside the given package but not sub-packages
found.clear();
mAa.findGlobs("mock_android.view.*", zipClasses, found);
assertArrayEquals(new String[] {
"mock_android.view.View",
"mock_android.view.ViewGroup",
"mock_android.view.ViewGroup$LayoutParams",
"mock_android.view.ViewGroup$MarginLayoutParams"
},
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 testFindClassesDerivingFrom() throws LogAbortException, IOException {
Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
mAa.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, LogAbortException {
Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
TreeMap<String, ClassReader> keep = new TreeMap<String, ClassReader>();
TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>();
TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>();
TreeMap<String, ClassReader> out_deps = new TreeMap<String, ClassReader>();
ClassReader cr = mAa.findClass("mock_android.widget.TableLayout", zipClasses, keep);
DependencyVisitor visitor = mAa.getVisitor(zipClasses, keep, new_keep, in_deps, out_deps);
// get first level dependencies
cr.accept(visitor, 0 /* flags */);
assertArrayEquals(new String[] {
"mock_android.view.ViewGroup",
"mock_android.widget.TableLayout$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 */);
}
assertArrayEquals(new String[] { }, out_deps.keySet().toArray());
}
}
@@ -0,0 +1,113 @@
/*
* Copyright (C) 2008 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 static org.junit.Assert.assertArrayEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Set;
/**
* Unit tests for some methods of {@link AsmGenerator}.
*/
public class AsmGeneratorTest {
private MockLog mLog;
private ArrayList<String> mOsJarPath;
private String mOsDestJar;
private File mTempFile;
@Before
public void setUp() throws Exception {
mLog = new MockLog();
URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar");
mOsJarPath = new ArrayList<String>();
mOsJarPath.add(url.getFile());
mTempFile = File.createTempFile("mock", "jar");
mOsDestJar = mTempFile.getAbsolutePath();
mTempFile.deleteOnExit();
}
@After
public void tearDown() throws Exception {
if (mTempFile != null) {
mTempFile.delete();
mTempFile = null;
}
}
@Test
public void testClassRenaming() throws IOException, LogAbortException {
ICreateInfo ci = new ICreateInfo() {
public Class<?>[] getInjectedClasses() {
// classes to inject in the final JAR
return new Class<?>[0];
}
public String[] getDelegateMethods() {
return new String[0];
}
public String[] getDelegateClassNatives() {
return new String[0];
}
public String[] getOverriddenMethods() {
// methods to force override
return new String[0];
}
public String[] getRenamedClasses() {
// classes to rename (so that we can replace them)
return new String[] {
"mock_android.view.View", "mock_android.view._Original_View",
"not.an.actual.ClassName", "anoter.fake.NewClassName",
};
}
public String[] getDeleteReturns() {
// methods deleted from their return type.
return new String[0];
}
};
AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
AsmAnalyzer aa = new AsmAnalyzer(mLog, mOsJarPath, agen,
null, // derived from
new String[] { // include classes
"**"
});
aa.analyze();
agen.generate();
Set<String> notRenamed = agen.getClassesNotRenamed();
assertArrayEquals(new String[] { "not/an/actual/ClassName" }, notRenamed.toArray());
}
}
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2010 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 static org.junit.Assert.*;
import org.junit.Test;
import org.objectweb.asm.ClassReader;
import java.io.IOException;
import java.util.ArrayList;
/**
* Tests {@link ClassHasNativeVisitor}.
*/
public class ClassHasNativeVisitorTest {
@Test
public void testHasNative() throws IOException {
MockClassHasNativeVisitor cv = new MockClassHasNativeVisitor();
String className =
this.getClass().getCanonicalName() + "$" + ClassWithNative.class.getSimpleName();
ClassReader cr = new ClassReader(className);
cr.accept(cv, 0 /* flags */);
assertArrayEquals(new String[] { "native_method" }, cv.getMethodsFound());
assertTrue(cv.hasNativeMethods());
}
@Test
public void testHasNoNative() throws IOException {
MockClassHasNativeVisitor cv = new MockClassHasNativeVisitor();
String className =
this.getClass().getCanonicalName() + "$" + ClassWithoutNative.class.getSimpleName();
ClassReader cr = new ClassReader(className);
cr.accept(cv, 0 /* flags */);
assertArrayEquals(new String[0], cv.getMethodsFound());
assertFalse(cv.hasNativeMethods());
}
//-------
/**
* Overrides {@link ClassHasNativeVisitor} to collec the name of the native methods found.
*/
private static class MockClassHasNativeVisitor extends ClassHasNativeVisitor {
private ArrayList<String> mMethodsFound = new ArrayList<String>();
public String[] getMethodsFound() {
return mMethodsFound.toArray(new String[mMethodsFound.size()]);
}
@Override
protected void setHasNativeMethods(boolean hasNativeMethods, String methodName) {
if (hasNativeMethods) {
mMethodsFound.add(methodName);
}
super.setHasNativeMethods(hasNativeMethods, methodName);
}
}
/**
* Dummy test class with a native method.
*/
public static class ClassWithNative {
public ClassWithNative() {
}
public void callTheNativeMethod() {
native_method();
}
private native void native_method();
}
/**
* Dummy test class with no native method.
*/
public static class ClassWithoutNative {
public ClassWithoutNative() {
}
public void someMethod() {
}
}
}
@@ -0,0 +1,409 @@
/*
* Copyright (C) 2010 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import com.android.tools.layoutlib.create.dataclass.ClassWithNative;
import com.android.tools.layoutlib.create.dataclass.OuterClass;
import com.android.tools.layoutlib.create.dataclass.OuterClass.InnerClass;
import org.junit.Before;
import org.junit.Test;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class DelegateClassAdapterTest {
private MockLog mLog;
private static final String NATIVE_CLASS_NAME = ClassWithNative.class.getCanonicalName();
private static final String OUTER_CLASS_NAME = OuterClass.class.getCanonicalName();
private static final String INNER_CLASS_NAME = OuterClass.class.getCanonicalName() + "$" +
InnerClass.class.getSimpleName();
@Before
public void setUp() throws Exception {
mLog = new MockLog();
mLog.setVerbose(true); // capture debug error too
}
/**
* Tests that a class not being modified still works.
*/
@SuppressWarnings("unchecked")
@Test
public void testNoOp() throws Throwable {
// create an instance of the class that will be modified
// (load the class in a distinct class loader so that we can trash its definition later)
ClassLoader cl1 = new ClassLoader(this.getClass().getClassLoader()) { };
Class<ClassWithNative> clazz1 = (Class<ClassWithNative>) cl1.loadClass(NATIVE_CLASS_NAME);
ClassWithNative instance1 = clazz1.newInstance();
assertEquals(42, instance1.add(20, 22));
try {
instance1.callNativeInstance(10, 3.1415, new Object[0] );
fail("Test should have failed to invoke callTheNativeMethod [1]");
} catch (UnsatisfiedLinkError e) {
// This is expected to fail since the native method is not implemented.
}
// Now process it but tell the delegate to not modify any method
ClassWriter cw = new ClassWriter(0 /*flags*/);
HashSet<String> delegateMethods = new HashSet<String>();
String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
DelegateClassAdapter cv = new DelegateClassAdapter(
mLog, cw, internalClassName, delegateMethods);
ClassReader cr = new ClassReader(NATIVE_CLASS_NAME);
cr.accept(cv, 0 /* flags */);
// Load the generated class in a different class loader and try it again
ClassLoader2 cl2 = null;
try {
cl2 = new ClassLoader2() {
@Override
public void testModifiedInstance() throws Exception {
Class<?> clazz2 = loadClass(NATIVE_CLASS_NAME);
Object i2 = clazz2.newInstance();
assertNotNull(i2);
assertEquals(42, callAdd(i2, 20, 22));
try {
callCallNativeInstance(i2, 10, 3.1415, new Object[0]);
fail("Test should have failed to invoke callTheNativeMethod [2]");
} catch (InvocationTargetException e) {
// This is expected to fail since the native method has NOT been
// overridden here.
assertEquals(UnsatisfiedLinkError.class, e.getCause().getClass());
}
// Check that the native method does NOT have the new annotation
Method[] m = clazz2.getDeclaredMethods();
assertEquals("native_instance", m[2].getName());
assertTrue(Modifier.isNative(m[2].getModifiers()));
Annotation[] a = m[2].getAnnotations();
assertEquals(0, a.length);
}
};
cl2.add(NATIVE_CLASS_NAME, cw);
cl2.testModifiedInstance();
} catch (Throwable t) {
throw dumpGeneratedClass(t, cl2);
}
}
/**
* {@link DelegateMethodAdapter} does not support overriding constructors yet,
* so this should fail with an {@link UnsupportedOperationException}.
*
* Although not tested here, the message of the exception should contain the
* constructor signature.
*/
@Test(expected=UnsupportedOperationException.class)
public void testConstructorsNotSupported() throws IOException {
ClassWriter cw = new ClassWriter(0 /*flags*/);
String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
HashSet<String> delegateMethods = new HashSet<String>();
delegateMethods.add("<init>");
DelegateClassAdapter cv = new DelegateClassAdapter(
mLog, cw, internalClassName, delegateMethods);
ClassReader cr = new ClassReader(NATIVE_CLASS_NAME);
cr.accept(cv, 0 /* flags */);
}
@Test
public void testDelegateNative() throws Throwable {
ClassWriter cw = new ClassWriter(0 /*flags*/);
String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
HashSet<String> delegateMethods = new HashSet<String>();
delegateMethods.add(DelegateClassAdapter.ALL_NATIVES);
DelegateClassAdapter cv = new DelegateClassAdapter(
mLog, cw, internalClassName, delegateMethods);
ClassReader cr = new ClassReader(NATIVE_CLASS_NAME);
cr.accept(cv, 0 /* flags */);
// Load the generated class in a different class loader and try it
ClassLoader2 cl2 = null;
try {
cl2 = new ClassLoader2() {
@Override
public void testModifiedInstance() throws Exception {
Class<?> clazz2 = loadClass(NATIVE_CLASS_NAME);
Object i2 = clazz2.newInstance();
assertNotNull(i2);
// Use reflection to access inner methods
assertEquals(42, callAdd(i2, 20, 22));
Object[] objResult = new Object[] { null };
int result = callCallNativeInstance(i2, 10, 3.1415, objResult);
assertEquals((int)(10 + 3.1415), result);
assertSame(i2, objResult[0]);
// Check that the native method now has the new annotation and is not native
Method[] m = clazz2.getDeclaredMethods();
assertEquals("native_instance", m[2].getName());
assertFalse(Modifier.isNative(m[2].getModifiers()));
Annotation[] a = m[2].getAnnotations();
assertEquals("LayoutlibDelegate", a[0].annotationType().getSimpleName());
}
};
cl2.add(NATIVE_CLASS_NAME, cw);
cl2.testModifiedInstance();
} catch (Throwable t) {
throw dumpGeneratedClass(t, cl2);
}
}
@Test
public void testDelegateInner() throws Throwable {
// We'll delegate the "get" method of both the inner and outer class.
HashSet<String> delegateMethods = new HashSet<String>();
delegateMethods.add("get");
// Generate the delegate for the outer class.
ClassWriter cwOuter = new ClassWriter(0 /*flags*/);
String outerClassName = OUTER_CLASS_NAME.replace('.', '/');
DelegateClassAdapter cvOuter = new DelegateClassAdapter(
mLog, cwOuter, outerClassName, delegateMethods);
ClassReader cr = new ClassReader(OUTER_CLASS_NAME);
cr.accept(cvOuter, 0 /* flags */);
// Generate the delegate for the inner class.
ClassWriter cwInner = new ClassWriter(0 /*flags*/);
String innerClassName = INNER_CLASS_NAME.replace('.', '/');
DelegateClassAdapter cvInner = new DelegateClassAdapter(
mLog, cwInner, innerClassName, delegateMethods);
cr = new ClassReader(INNER_CLASS_NAME);
cr.accept(cvInner, 0 /* flags */);
// Load the generated classes in a different class loader and try them
ClassLoader2 cl2 = null;
try {
cl2 = new ClassLoader2() {
@Override
public void testModifiedInstance() throws Exception {
// Check the outer class
Class<?> outerClazz2 = loadClass(OUTER_CLASS_NAME);
Object o2 = outerClazz2.newInstance();
assertNotNull(o2);
// The original Outer.get returns 1+10+20,
// but the delegate makes it return 4+10+20
assertEquals(4+10+20, callGet(o2, 10, 20));
// Check the inner class. Since it's not a static inner class, we need
// to use the hidden constructor that takes the outer class as first parameter.
Class<?> innerClazz2 = loadClass(INNER_CLASS_NAME);
Constructor<?> innerCons = innerClazz2.getConstructor(
new Class<?>[] { outerClazz2 });
Object i2 = innerCons.newInstance(new Object[] { o2 });
assertNotNull(i2);
// The original Inner.get returns 3+10+20,
// but the delegate makes it return 6+10+20
assertEquals(6+10+20, callGet(i2, 10, 20));
}
};
cl2.add(OUTER_CLASS_NAME, cwOuter.toByteArray());
cl2.add(INNER_CLASS_NAME, cwInner.toByteArray());
cl2.testModifiedInstance();
} catch (Throwable t) {
throw dumpGeneratedClass(t, cl2);
}
}
//-------
/**
* A class loader than can define and instantiate our modified classes.
* <p/>
* The trick here is that this class loader will test our <em>modified</em> version
* of the classes, the one with the delegate calls.
* <p/>
* Trying to do so in the original class loader generates all sort of link issues because
* there are 2 different definitions of the same class name. This class loader will
* define and load the class when requested by name and provide helpers to access the
* instance methods via reflection.
*/
private abstract class ClassLoader2 extends ClassLoader {
private final Map<String, byte[]> mClassDefs = new HashMap<String, byte[]>();
public ClassLoader2() {
super(null);
}
public ClassLoader2 add(String className, byte[] definition) {
mClassDefs.put(className, definition);
return this;
}
public ClassLoader2 add(String className, ClassWriter rewrittenClass) {
mClassDefs.put(className, rewrittenClass.toByteArray());
return this;
}
private Set<Entry<String, byte[]>> getByteCode() {
return mClassDefs.entrySet();
}
@SuppressWarnings("unused")
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
return super.findClass(name);
} catch (ClassNotFoundException e) {
byte[] def = mClassDefs.get(name);
if (def != null) {
// Load the modified ClassWithNative from its bytes representation.
return defineClass(name, def, 0, def.length);
}
try {
// Load everything else from the original definition into the new class loader.
ClassReader cr = new ClassReader(name);
ClassWriter cw = new ClassWriter(0);
cr.accept(cw, 0);
byte[] bytes = cw.toByteArray();
return defineClass(name, bytes, 0, bytes.length);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
}
/**
* Accesses {@link OuterClass#get()} or {@link InnerClass#get() }via reflection.
*/
public int callGet(Object instance, int a, long b) throws Exception {
Method m = instance.getClass().getMethod("get",
new Class<?>[] { int.class, long.class } );
Object result = m.invoke(instance, new Object[] { a, b });
return ((Integer) result).intValue();
}
/**
* Accesses {@link ClassWithNative#add(int, int)} via reflection.
*/
public int callAdd(Object instance, int a, int b) throws Exception {
Method m = instance.getClass().getMethod("add",
new Class<?>[] { int.class, int.class });
Object result = m.invoke(instance, new Object[] { a, b });
return ((Integer) result).intValue();
}
/**
* Accesses {@link ClassWithNative#callNativeInstance(int, double, Object[])}
* via reflection.
*/
public int callCallNativeInstance(Object instance, int a, double d, Object[] o)
throws Exception {
Method m = instance.getClass().getMethod("callNativeInstance",
new Class<?>[] { int.class, double.class, Object[].class });
Object result = m.invoke(instance, new Object[] { a, d, o });
return ((Integer) result).intValue();
}
public abstract void testModifiedInstance() throws Exception;
}
/**
* For debugging, it's useful to dump the content of the generated classes
* along with the exception that was generated.
*
* However to make it work you need to pull in the org.objectweb.asm.util.TraceClassVisitor
* class and associated utilities which are found in the ASM source jar. Since we don't
* want that dependency in the source code, we only put it manually for development and
* access the TraceClassVisitor via reflection if present.
*
* @param t The exception thrown by {@link ClassLoader2#testModifiedInstance()}
* @param cl2 The {@link ClassLoader2} instance with the generated bytecode.
* @return Either original {@code t} or a new wrapper {@link Throwable}
*/
private Throwable dumpGeneratedClass(Throwable t, ClassLoader2 cl2) {
try {
// For debugging, dump the bytecode of the class in case of unexpected error
// if we can find the TraceClassVisitor class.
Class<?> tcvClass = Class.forName("org.objectweb.asm.util.TraceClassVisitor");
StringBuilder sb = new StringBuilder();
sb.append('\n').append(t.getClass().getCanonicalName());
if (t.getMessage() != null) {
sb.append(": ").append(t.getMessage());
}
for (Entry<String, byte[]> entry : cl2.getByteCode()) {
String className = entry.getKey();
byte[] bytes = entry.getValue();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
// next 2 lines do: TraceClassVisitor tcv = new TraceClassVisitor(pw);
Constructor<?> cons = tcvClass.getConstructor(new Class<?>[] { pw.getClass() });
Object tcv = cons.newInstance(new Object[] { pw });
ClassReader cr2 = new ClassReader(bytes);
cr2.accept((ClassVisitor) tcv, 0 /* flags */);
sb.append("\nBytecode dump: <").append(className).append(">:\n")
.append(sw.toString());
}
// Re-throw exception with new message
RuntimeException ex = new RuntimeException(sb.toString(), t);
return ex;
} catch (Throwable ignore) {
// In case of problem, just throw the original exception as-is.
return t;
}
}
}
@@ -0,0 +1,88 @@
/*
* Copyright (C) 2008 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 static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class LogTest {
private MockLog mLog;
@Before
public void setUp() throws Exception {
mLog = new MockLog();
}
@After
public void tearDown() throws Exception {
// pass
}
@Test
public void testDebug() {
assertEquals("", mLog.getOut());
assertEquals("", mLog.getErr());
mLog.setVerbose(false);
mLog.debug("Test %d", 42);
assertEquals("", mLog.getOut());
mLog.setVerbose(true);
mLog.debug("Test %d", 42);
assertEquals("Test 42\n", mLog.getOut());
assertEquals("", mLog.getErr());
}
@Test
public void testInfo() {
assertEquals("", mLog.getOut());
assertEquals("", mLog.getErr());
mLog.info("Test %d", 43);
assertEquals("Test 43\n", mLog.getOut());
assertEquals("", mLog.getErr());
}
@Test
public void testError() {
assertEquals("", mLog.getOut());
assertEquals("", mLog.getErr());
mLog.error("Test %d", 44);
assertEquals("", mLog.getOut());
assertEquals("Test 44\n", mLog.getErr());
}
@Test
public void testException() {
assertEquals("", mLog.getOut());
assertEquals("", mLog.getErr());
Exception e = new Exception("My Exception");
mLog.exception(e, "Test %d", 44);
assertEquals("", mLog.getOut());
assertTrue(mLog.getErr().startsWith("Test 44\njava.lang.Exception: My Exception"));
}
}
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2010 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;
public class MockLog extends Log {
StringBuilder mOut = new StringBuilder();
StringBuilder mErr = new StringBuilder();
public String getOut() {
return mOut.toString();
}
public String getErr() {
return mErr.toString();
}
@Override
protected void outPrintln(String msg) {
mOut.append(msg);
mOut.append('\n');
}
@Override
protected void errPrintln(String msg) {
mErr.append(msg);
mErr.append('\n');
}
}
@@ -0,0 +1,120 @@
/*
* Copyright (C) 2008 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 static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
*
*/
public class RenameClassAdapterTest {
private RenameClassAdapter mOuter;
private RenameClassAdapter mInner;
@Before
public void setUp() throws Exception {
mOuter = new RenameClassAdapter(null, // cv
"com.pack.Old",
"org.blah.New");
mInner = new RenameClassAdapter(null, // cv
"com.pack.Old$Inner",
"org.blah.New$Inner");
}
@After
public void tearDown() throws Exception {
}
/**
* Renames a type, e.g. "Lcom.package.My;"
* If the type doesn't need to be renamed, returns the input string as-is.
*/
@Test
public void testRenameTypeDesc() {
// primitive types are left untouched
assertEquals("I", mOuter.renameTypeDesc("I"));
assertEquals("D", mOuter.renameTypeDesc("D"));
assertEquals("V", mOuter.renameTypeDesc("V"));
// object types that need no renaming are left untouched
assertEquals("Lcom.package.MyClass;", mOuter.renameTypeDesc("Lcom.package.MyClass;"));
assertEquals("Lcom.package.MyClass;", mInner.renameTypeDesc("Lcom.package.MyClass;"));
// object types that match the requirements
assertEquals("Lorg.blah.New;", mOuter.renameTypeDesc("Lcom.pack.Old;"));
assertEquals("Lorg.blah.New$Inner;", mInner.renameTypeDesc("Lcom.pack.Old$Inner;"));
// inner classes match the base type which is being renamed
assertEquals("Lorg.blah.New$Other;", mOuter.renameTypeDesc("Lcom.pack.Old$Other;"));
assertEquals("Lorg.blah.New$Other;", mInner.renameTypeDesc("Lcom.pack.Old$Other;"));
// arrays
assertEquals("[Lorg.blah.New;", mOuter.renameTypeDesc("[Lcom.pack.Old;"));
assertEquals("[[Lorg.blah.New;", mOuter.renameTypeDesc("[[Lcom.pack.Old;"));
assertEquals("[Lorg.blah.New;", mInner.renameTypeDesc("[Lcom.pack.Old;"));
assertEquals("[[Lorg.blah.New;", mInner.renameTypeDesc("[[Lcom.pack.Old;"));
}
/**
* Renames an object type, e.g. "Lcom.package.MyClass;" or an array type that has an
* object element, e.g. "[Lcom.package.MyClass;"
* If the type doesn't need to be renamed, returns the internal name of the input type.
*/
@Test
public void testRenameType() {
// Skip. This is actually tested by testRenameTypeDesc above.
}
/**
* Renames an internal type name, e.g. "com.package.MyClass".
* If the type doesn't need to be renamed, returns the input string as-is.
*/
@Test
public void testRenameInternalType() {
// a descriptor is not left untouched
assertEquals("Lorg.blah.New;", mOuter.renameInternalType("Lcom.pack.Old;"));
assertEquals("Lorg.blah.New$Inner;", mOuter.renameInternalType("Lcom.pack.Old$Inner;"));
// an actual FQCN
assertEquals("org.blah.New", mOuter.renameInternalType("com.pack.Old"));
assertEquals("org.blah.New$Inner", mOuter.renameInternalType("com.pack.Old$Inner"));
assertEquals("org.blah.New$Other", mInner.renameInternalType("com.pack.Old$Other"));
assertEquals("org.blah.New$Other", mInner.renameInternalType("com.pack.Old$Other"));
}
/**
* Renames a method descriptor, i.e. applies renameType to all arguments and to the
* return value.
*/
@Test
public void testRenameMethodDesc() {
assertEquals("(IDLorg.blah.New;[Lorg.blah.New$Inner;)Lorg.blah.New$Other;",
mOuter.renameMethodDesc("(IDLcom.pack.Old;[Lcom.pack.Old$Inner;)Lcom.pack.Old$Other;"));
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2010 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.dataclass;
import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
/**
* Dummy test class with a native method.
* The native method is not defined and any attempt to invoke it will
* throw an {@link UnsatisfiedLinkError}.
*
* Used by {@link DelegateClassAdapterTest}.
*/
public class ClassWithNative {
public ClassWithNative() {
}
public int add(int a, int b) {
return a + b;
}
// Note: it's good to have a long or double for testing parameters since they take
// 2 slots in the stack/locals maps.
public int callNativeInstance(int a, double d, Object[] o) {
return native_instance(a, d, o);
}
private native int native_instance(int a, double d, Object[] o);
}
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2010 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.dataclass;
import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
/**
* The delegate that receives the call to {@link ClassWithNative_Delegate}'s overridden methods.
*
* Used by {@link DelegateClassAdapterTest}.
*/
public class ClassWithNative_Delegate {
public static int native_instance(ClassWithNative instance, int a, double d, Object[] o) {
if (o != null && o.length > 0) {
o[0] = instance;
}
return (int)(a + d);
}
}
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2011 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.dataclass;
import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
/**
* Test class with an inner class.
*
* Used by {@link DelegateClassAdapterTest}.
*/
public class OuterClass {
private int mOuterValue = 1;
public OuterClass() {
}
// Outer.get returns 1 + a + b
// Note: it's good to have a long or double for testing parameters since they take
// 2 slots in the stack/locals maps.
public int get(int a, long b) {
return mOuterValue + a + (int) b;
}
public class InnerClass {
public InnerClass() {
}
// Inner.get returns 1+2=3 + a + b
public int get(int a, long b) {
return 2 + mOuterValue + a + (int) b;
}
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2011 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.dataclass;
import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
/**
* Used by {@link DelegateClassAdapterTest}.
*/
public class OuterClass_Delegate {
// The delegate override of Outer.get returns 4 + a + b
public static int get(OuterClass instance, int a, long b) {
return 4 + a + (int) b;
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2011 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.dataclass;
import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
import com.android.tools.layoutlib.create.dataclass.OuterClass.InnerClass;
/**
* Used by {@link DelegateClassAdapterTest}.
*/
public class OuterClass_InnerClass_Delegate {
// The delegate override of Inner.get return 6 + a + b
public static int get(OuterClass outer, InnerClass inner, int a, long b) {
return 6 + a + (int) b;
}
}
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="WINDOWS-1252" standalone="no"?>
<jardesc>
<jar path="C:/ralf/google/src/raphael-lapdroid/device/tools/layoutlib/create/tests/data/mock_android.jar"/>
<options buildIfNeeded="true" compress="true" descriptionLocation="/layoutlib_create/tests/data/mock_android.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
<selectedProjects/>
<manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
<sealing sealJar="false">
<packagesToSeal/>
<packagesToUnSeal/>
</sealing>
</manifest>
<selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false">
<javaElement handleIdentifier="=layoutlib_create/tests&lt;mock_android.widget"/>
<javaElement handleIdentifier="=layoutlib_create/tests&lt;mock_android.view"/>
<javaElement handleIdentifier="=layoutlib_create/tests&lt;mock_android.dummy"/>
</selectedElements>
</jardesc>
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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 mock_android.dummy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class InnerTest {
private int mSomeField;
private MyStaticInnerClass mInnerInstance;
private MyIntEnum mTheIntEnum;
private MyGenerics1<int[][], InnerTest, MyIntEnum, float[]> mGeneric1;
public class NotStaticInner2 extends NotStaticInner1 {
}
public class NotStaticInner1 {
public void someThing() {
mSomeField = 2;
mInnerInstance = null;
}
}
private static class MyStaticInnerClass {
}
private static class DerivingClass extends InnerTest {
}
// enums are a kind of inner static class
public enum MyIntEnum {
VALUE0(0),
VALUE1(1),
VALUE2(2);
MyIntEnum(int myInt) {
this.myInt = myInt;
}
final int myInt;
}
public static class MyGenerics1<T, U, V, W> {
public MyGenerics1() {
int a = 1;
}
}
public <X> void genericMethod1(X a, X[] a) {
}
public <X, Y> void genericMethod2(X a, List<Y> b) {
}
public <X, Y> void genericMethod3(X a, List<Y extends InnerTest> b) {
}
public <T extends InnerTest> void genericMethod4(T[] a, Collection<T> b, Collection<?> c) {
Iterator<T> i = b.iterator();
}
public void someMethod(InnerTest self) {
mSomeField = self.mSomeField;
MyStaticInnerClass m = new MyStaticInnerClass();
mInnerInstance = m;
mTheIntEnum = null;
mGeneric1 = new MyGenerics1();
genericMethod(new DerivingClass[0], new ArrayList<DerivingClass>(), new ArrayList<InnerTest>());
}
}
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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 mock_android.view;
public class View {
}
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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 mock_android.view;
public class ViewGroup extends View {
public class MarginLayoutParams extends LayoutParams {
}
public class LayoutParams {
}
}
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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 mock_android.widget;
import mock_android.view.ViewGroup;
public class LinearLayout extends ViewGroup {
public class LayoutParams extends mock_android.view.ViewGroup.LayoutParams {
}
}
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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 mock_android.widget;
import mock_android.view.ViewGroup;
public class TableLayout extends ViewGroup {
public class LayoutParams extends MarginLayoutParams {
}
}