/* * Copyright 2015 the original author or authors. * * 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 org.powermock.core.transformers.impl; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.powermock.core.classloader.MockClassLoader; import powermock.test.support.MainMockTransformerTestSupport.SupportClasses; import org.powermock.core.IndicateReloadClass; import static java.lang.reflect.Modifier.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; @RunWith(Parameterized.class) public class TestClassTransformerTest { @Parameterized.Parameter(0) public MockClassLoaderCase classLoaderCase; @Parameterized.Parameters(name = "{0}") public static List<?> values() { MockClassLoaderCase[] factoryAlternatives = MockClassLoaderCase.values(); List<Object[]> values = Arrays.asList(new Object[factoryAlternatives.length][]); for (MockClassLoaderCase eachFactoryAlternative : factoryAlternatives) { values.set(eachFactoryAlternative.ordinal(), new Object[] {eachFactoryAlternative}); } return values; } @Test public void preparedSubclassShouldNotGetPublicDeferConstructor() throws Exception { MockClassLoader mockClassLoader = classLoaderCase .createMockClassLoaderThatPrepare(SupportClasses.SubClass.class); final Class<?> clazz = Class.forName(SupportClasses.SubClass.class.getName(), true, mockClassLoader); assertEquals("Original number of constructoprs", 1, SupportClasses.SubClass.class.getConstructors().length); try { fail("A public defer-constructor is not expected: " + clazz.getConstructor(IndicateReloadClass.class)); } catch (NoSuchMethodException is_expected) {} assertEquals("Number of (public) constructors in modified class", 1, clazz.getConstructors().length); assertNotNull("But there should still be a non-public defer constructor!", clazz.getDeclaredConstructor(IndicateReloadClass.class)); } @Test public void preparedClassConstructorsShouldKeepTheirAccessModifier() throws Exception { MockClassLoader mockClassLoader = classLoaderCase .createMockClassLoaderThatPrepare(SupportClasses.MultipleConstructors.class); final Class<?> clazz = Class.forName( SupportClasses.MultipleConstructors.class.getName(), true, mockClassLoader); for (Constructor<?> originalConstructor : SupportClasses .MultipleConstructors.class.getDeclaredConstructors()) { Class[] paramTypes = originalConstructor.getParameterTypes(); int originalModifiers = originalConstructor.getModifiers(); int newModifiers = clazz.getDeclaredConstructor(paramTypes).getModifiers(); String constructorName = 0 == paramTypes.length ? "Default constructor " : paramTypes[0].getSimpleName() + " constructor "; assertEquals(constructorName + "is public?", isPublic(originalModifiers), isPublic(newModifiers)); assertEquals(constructorName + "is protected?", isProtected(originalModifiers), isProtected(newModifiers)); assertEquals(constructorName + "is private?", isPrivate(originalModifiers), isPrivate(newModifiers)); } } enum MockClassLoaderCase { WHEN_PREPARED_CLASS_IS_TESTCLASS { @Override Class<?> chooseTestClass(Class<?> prepare4test) { return prepare4test; } @Override String[] preparations(Class<?> prepare4test) { return new String[] {MockClassLoader.MODIFY_ALL_CLASSES}; } }, WHEN_ENCLOSING_CLASS_IS_TESTCLASS { @Override Class<?> chooseTestClass(Class<?> prepare4test) { return prepare4test.getDeclaringClass(); } @Override String[] preparations(Class<?> prepare4test) { return new String[] {prepare4test.getName()}; } }; abstract Class<?> chooseTestClass(Class<?> prepare4test); abstract String[] preparations(Class<?> prepare4test); MockClassLoader createMockClassLoaderThatPrepare(Class<?> prepare4test) { TestClassTransformer testClassTransformer = TestClassTransformer .forTestClass(chooseTestClass(prepare4test)) .removesTestMethodAnnotation(Test.class) .fromMethods(Collections.<Method>emptyList()); MockClassLoader mockClassLoader = new MockClassLoader(preparations(prepare4test)); mockClassLoader.setMockTransformerChain(Arrays.asList( new ClassMockTransformer(), testClassTransformer)); return mockClassLoader; } } }