/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.asm; import com.liferay.portal.kernel.test.ReflectionTestUtil; import com.liferay.portal.kernel.test.rule.AggregateTestRule; import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor; import com.liferay.portal.kernel.test.rule.NewEnv; import com.liferay.portal.kernel.test.util.RandomTestUtil; import com.liferay.portal.kernel.util.ArrayUtil; import com.liferay.portal.kernel.util.PredicateFilter; import com.liferay.portal.test.aspects.ReflectionUtilAdvice; import com.liferay.portal.test.rule.AdviseWith; import com.liferay.portal.test.rule.AspectJNewEnvTestRule; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; import org.junit.Assert; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; /** * @author Matthew Tambara */ public class ASMWrapperUtilTest { @ClassRule @Rule public static final AggregateTestRule aggregateTestRule = new AggregateTestRule( CodeCoverageAssertor.INSTANCE, AspectJNewEnvTestRule.INSTANCE); @Test public void testASMWrapper() throws Exception { Object asmWrapper = ASMWrapperUtil.createASMWrapper( TestInterface.class.getClassLoader(), TestInterface.class, new TestDelegate(), new TestDefault()); Class<?> asmWrapperClass = asmWrapper.getClass(); Method method = asmWrapperClass.getDeclaredMethod( "objectMethod", Object.class); Object object = new Object(); Assert.assertNotSame(object, method.invoke(asmWrapper, object)); method = asmWrapperClass.getDeclaredMethod("intMethod", Integer.TYPE); int randomInt = RandomTestUtil.randomInt(); Assert.assertEquals(randomInt, method.invoke(asmWrapper, randomInt)); } @AdviseWith(adviceClasses = {ReflectionUtilAdvice.class}) @NewEnv(type = NewEnv.Type.CLASSLOADER) @Test public void testClassInitializationFailure() throws Exception { Throwable throwable = new Throwable(); ReflectionUtilAdvice.setDeclaredMethodThrowable(throwable); try { ASMWrapperUtil.createASMWrapper( TestInterface.class.getClassLoader(), TestInterface.class, new TestDelegate(), new TestDefault()); Assert.fail(); } catch (ExceptionInInitializerError eiie) { Assert.assertSame(throwable, eiie.getCause()); } ReflectionUtilAdvice.setDeclaredFieldThrowable(null); } @Test public void testConstructor() throws Exception { Class<ASMWrapperUtil> clazz = ASMWrapperUtil.class; Constructor<ASMWrapperUtil> constructor = clazz.getDeclaredConstructor(); Assert.assertEquals(Modifier.PRIVATE, constructor.getModifiers()); constructor.setAccessible(true); constructor.newInstance(); } @Test public void testCreateASMWrapper() throws Exception { Object asmWrapper = ASMWrapperUtil.createASMWrapper( TestInterface.class.getClassLoader(), TestInterface.class, new TestDelegate(), new TestDefault()); Class<?> asmWrapperClass = asmWrapper.getClass(); Assert.assertEquals(Modifier.PUBLIC, asmWrapperClass.getModifiers()); Package pkg = TestDelegate.class.getPackage(); Assert.assertEquals( pkg.getName() + "." + TestInterface.class.getSimpleName() + "ASMWrapper", asmWrapperClass.getName()); Assert.assertSame(Object.class, asmWrapperClass.getSuperclass()); Method[] expectedMethods = _getDeclaredMethods(TestInterface.class); Method[] actualMethods = _getDeclaredMethods(asmWrapperClass); // See LPS-71495 Assert.assertTrue(asmWrapper.equals(null)); Assert.assertEquals(0, asmWrapper.hashCode()); Assert.assertEquals("test", asmWrapper.toString()); Assert.assertEquals( "Expected: " + Arrays.toString(expectedMethods) + ", actual: " + Arrays.toString(actualMethods), expectedMethods.length, actualMethods.length); for (int i = 0; i < expectedMethods.length; i++) { _assertEquals(expectedMethods[i], actualMethods[i]); } } @NewEnv(type = NewEnv.Type.CLASSLOADER) @Test public void testErrorCreateASMWrapper() throws Exception { Method defineClassMethod = ReflectionTestUtil.getAndSetFieldValue( ASMWrapperUtil.class, "_defineClassMethod", null); try { ASMWrapperUtil.createASMWrapper( TestInterface.class.getClassLoader(), TestInterface.class, new TestDelegate(), new TestDefault()); Assert.fail(); } catch (RuntimeException re) { Throwable throwable = re.getCause(); Assert.assertSame(NullPointerException.class, throwable.getClass()); } finally { ReflectionTestUtil.setFieldValue( ASMWrapperUtil.class, "_defineClassMethod", defineClassMethod); } try { ASMWrapperUtil.createASMWrapper( ClassLoader.getSystemClassLoader(), Object.class, new Object(), Object.class); Assert.fail(); } catch (IllegalArgumentException iae) { Assert.assertEquals( Object.class + " is not an interface", iae.getMessage()); } } public static class TestDefault implements TestInterface { @Override public boolean booleanMethod(boolean booleanArg) { return booleanArg; } @Override public byte byteMethod(byte byteArg) { return byteArg; } @Override public char charMethod(char charArg) { return charArg; } @Override public double doubleMethod(double doubleArg) { return doubleArg; } @Override public float floatMethod(float floatArg) { return floatArg; } @Override public int intMethod(int intArg) { return intArg; } @Override public long longMethod(long longArg) { return longArg; } @Override public Object objectMethod(Object objectArg) { return objectArg; } @Override public short shortMethod(short shortArg) { return shortArg; } @Override public void voidWithExceptionMethod() throws Exception { } } public static class TestDelegate { @Override public boolean equals(Object object) { return true; } @Override public int hashCode() { return 0; } public Object objectMethod(Object object) { return new Object(); } @Override public String toString() { return "test"; } } public interface TestInterface { public boolean booleanMethod(boolean booleanArg); public byte byteMethod(byte byteArg); public char charMethod(char charArg); public double doubleMethod(double doubleArg); public float floatMethod(float floatArg); public int intMethod(int intArg); public long longMethod(long longArg); public Object objectMethod(Object objectArg); public short shortMethod(short shortArg); public void voidWithExceptionMethod() throws Exception; } private void _assertEquals(Method expectedMethod, Method actualMethod) { Assert.assertEquals( "Expected:" + expectedMethod + ", actual: " + actualMethod, expectedMethod.getModifiers() - Modifier.ABSTRACT, actualMethod.getModifiers()); Assert.assertSame( "Expected:" + expectedMethod + ", actual: " + actualMethod, expectedMethod.getReturnType(), actualMethod.getReturnType()); Assert.assertEquals( "Expected:" + expectedMethod + ", actual: " + actualMethod, expectedMethod.getName(), actualMethod.getName()); Assert.assertArrayEquals( "Expected:" + expectedMethod + ", actual: " + actualMethod, expectedMethod.getParameterTypes(), actualMethod.getParameterTypes()); Assert.assertArrayEquals( "Expected:" + expectedMethod + ", actual: " + actualMethod, expectedMethod.getExceptionTypes(), actualMethod.getExceptionTypes()); } private Method[] _getDeclaredMethods(Class<?> clazz) { Method[] methods = clazz.getDeclaredMethods(); methods = ArrayUtil.<Method>filter( methods, new PredicateFilter<Method>() { @Override public boolean filter(Method method) { String name = method.getName(); if (name.equals("equals") || name.equals("hashCode") || name.equals("toString")) { return false; } return true; } }); Arrays.sort( methods, (method1, method2) -> { String name1 = method1.getName(); String name2 = method2.getName(); return name1.compareTo(name2); }); return methods; } }