Java tutorial
/* * Copyright (c) 2008 Kasper Nielsen. * * 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.cakeframework.container.spi; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.cakeframework.container.Container; import org.cakeframework.container.ContainerConfiguration; import org.cakeframework.container.HierarchicalContainerConfiguration; import org.cakeframework.container.RuntimeContainerException; import org.cakeframework.container.spi.ClassPool.Builder; import org.cakeframework.test.stubs.throwables.Exception1; import org.junit.Before; import org.junit.Test; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.util.ASMifier; import stubs.ContainerStub; /** * Tests {@link DynamicContainerFactory}. * * @author Kasper Nielsen */ public class DynamicContainerFactoryTest implements Opcodes { ContainerConfiguration conf; ContainerComposer cc; @Before public void setup() { conf = new ContainerConfiguration(); cc = new ContainerComposer(conf); } @Test public void defaults() { Container c = new DynamicContainerFactory<Container, ContainerConfiguration>() { protected String defineClasses(ContainerConfiguration configuration, ContainerComposer composer, Builder builder) { assertSame(conf, configuration); assertSame(cc, composer); builder.addClass("Foo", dump(ContainerStub.class, ContainerConfiguration.class)); return "Foo"; } }.create(conf, cc); assertSame(conf, ((ContainerStub) c).configuration); assertSame(cc, ((ContainerStub) c).composer); } @Test public void defaultsSuperConfigurationClass() { Container c = new DynamicContainerFactory<Container, ContainerConfiguration>() { protected String defineClasses(ContainerConfiguration configuration, ContainerComposer composer, Builder builder) { assertSame(conf, configuration); assertSame(cc, composer); builder.addClass("Foo", dump(ContainerStub.class, AbstractContainerConfiguration.class)); return "Foo"; } }.create(conf, cc); assertSame(conf, ((ContainerStub) c).configuration); assertSame(cc, ((ContainerStub) c).composer); } @Test public void noValidConstructor() { try { new DynamicContainerFactory<Container, ContainerConfiguration>() { protected String defineClasses(ContainerConfiguration configuration, ContainerComposer composer, Builder builder) { builder.addClass("Foo", dump(ContainerStub.class, HierarchicalContainerConfiguration.class)); return "Foo"; } }.create(conf, cc); } catch (RuntimeContainerException ok) { assertEquals("A valid constructor Foo(ContainerConfiguration, ContainerComposer) could not be found", ok.getMessage()); } } @Test public void abstractClassGenerated() { try { new DynamicContainerFactory<Container, ContainerConfiguration>() { protected String defineClasses(ContainerConfiguration configuration, ContainerComposer composer, Builder builder) { builder.addClass("Foo", dump(ContainerStub.class, ContainerConfiguration.class, true, false)); return "Foo"; } }.create(conf, cc); fail(); } catch (RuntimeContainerException ok) { assertTrue(ok.getCause() instanceof InstantiationException); } } @Test public void constructorThrows() { try { new DynamicContainerFactory<Container, ContainerConfiguration>() { protected String defineClasses(ContainerConfiguration configuration, ContainerComposer composer, Builder builder) { builder.addClass("Foo", dump(ContainerStub.class, ContainerConfiguration.class, false, true)); return "Foo"; } }.create(conf, cc); fail(); } catch (RuntimeContainerException ok) { assertSame(Exception1.INSTANCE, ok.getCause()); } } @Test public void unknownName() { try { new DynamicContainerFactory<Container, ContainerConfiguration>() { protected String defineClasses(ContainerConfiguration configuration, ContainerComposer composer, Builder builder) { builder.addClass("Foo", dump(ContainerStub.class, ContainerConfiguration.class)); return "org.XYZ"; } }.create(conf, cc); fail(); } catch (RuntimeContainerException ok) { assertEquals("Could not find the generated class: org.XYZ", ok.getMessage()); assertTrue(ok.getCause() instanceof ClassNotFoundException); } } @Test public void invalidNamed() { try { new DynamicContainerFactory<Container, ContainerConfiguration>() { protected String defineClasses(ContainerConfiguration configuration, ContainerComposer composer, Builder builder) { builder.addClass("Foo", dump(ContainerStub.class, ContainerConfiguration.class)); return "or#$%#$%g.XYZ"; } }.create(conf, cc); fail(); } catch (RuntimeContainerException ok) { assertEquals("defineClasses() dit not return a valid class name, was: or#$%#$%g.XYZ", ok.getMessage()); } } @Test public void cached() { DynamicContainerFactory<Container, ContainerConfiguration> f = new DynamicContainerFactory<Container, ContainerConfiguration>() { protected Object generateCacheKey(ContainerConfiguration configuration) { return "abcd"; // cached under same key } protected String defineClasses(ContainerConfiguration configuration, ContainerComposer composer, Builder builder) { if (configuration.getName() != null) { throw new AssertionError(); } builder.addClass("Foo", dump(ContainerStub.class, ContainerConfiguration.class)); return "Foo"; } }; Container c = f.create(conf, cc); assertSame(conf, ((ContainerStub) c).configuration); assertSame(cc, ((ContainerStub) c).composer); conf.setName("Fail"); c = f.create(conf, cc); assertSame(conf, ((ContainerStub) c).configuration); assertSame(cc, ((ContainerStub) c).composer); } static byte[] dump(Class<?> parent, Class<?> confType) { return dump(parent, confType, false, false); } static byte[] dump(Class<?> parent, Class<?> confType, boolean isAbstract, boolean throwException1) { ClassWriter cw = new ClassWriter(0); int mod = ACC_PUBLIC + ACC_SUPER; if (isAbstract) { mod += ACC_ABSTRACT; } cw.visit(V1_7, mod, "Foo", null, c(parent), null); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(L" + c(confType) + ";L" + c(ContainerComposer.class) + ";)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKESPECIAL, "stubs/ContainerStub", "<init>", "(L" + c(AbstractContainerConfiguration.class) + ";L" + c(ContainerComposer.class) + ";)V", false); if (throwException1) { // throw Exception1.instance from the constructor mv.visitFieldInsn(GETSTATIC, c(Exception1.class), "INSTANCE", "L" + c(Exception1.class) + ";"); mv.visitInsn(ATHROW); } else { mv.visitInsn(RETURN); } mv.visitMaxs(3, 3); cw.visitEnd(); return cw.toByteArray(); } static String c(Class<?> c) { return c.getName().replace(".", "/"); } // @Test public void ff() throws Exception { ASMifier.main(new String[] { "stubs.GeneratedContainer" }); } }