/* Copyright 2009 Ben Gunter
*
* 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 net.sourceforge.stripes.controller;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.concurrent.atomic.AtomicInteger;
import net.sourceforge.stripes.StripesTestFixture;
import net.sourceforge.stripes.controller.ObjectFactory.ConstructorWrapper;
import net.sourceforge.stripes.exception.StripesRuntimeException;
import net.sourceforge.stripes.util.Log;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* Unit tests for {@link ObjectFactory} and {@link DefaultObjectFactory}.
*
* @author Ben Gunter
*/
public class ObjectFactoryTests extends StripesTestFixture {
public static final class Adder {
private int a;
private int b;
public Adder(int a, int b) {
this.a = a;
this.b = b;
}
public int sum() {
return a + b;
}
}
public static class MyRunnable implements Runnable {
public void run() {
}
}
private static final Log log = Log.getInstance(ObjectFactoryTests.class);
public void instantiateClasses(ObjectFactory factory, Class<?>... classes) {
for (Class<?> clazz : classes) {
log.debug("Instantiating ", clazz);
Object o = factory.newInstance(clazz);
Assert.assertNotNull(o);
Assert.assertSame(o.getClass(), clazz);
}
}
public void instantiateInterfaces(ObjectFactory factory, Class<?>... classes) {
for (Class<?> clazz : classes) {
log.debug("Instantiating ", clazz);
Object o = factory.newInstance(clazz);
log.debug("Implementation class is ", o.getClass().getName());
Assert.assertNotNull(o);
Assert.assertTrue(clazz.isAssignableFrom(o.getClass()));
}
}
/** Test basic instantiation of classes. */
@Test(groups = "fast")
public void basic() {
ObjectFactory factory = super.getDefaultConfiguration().getObjectFactory();
instantiateClasses(factory, Object.class, String.class, Exception.class,
StringBuilder.class);
}
/** Test instantiation of interfaces. */
@Test(groups = "fast")
public void interfaces() {
ObjectFactory factory = getDefaultConfiguration().getObjectFactory();
instantiateInterfaces(factory, Collection.class, List.class, Set.class, SortedSet.class,
Queue.class, Map.class, SortedMap.class);
}
/** Test instantiation via constructor. */
@Test(groups = "fast")
public void constructor() {
log.info("Instantiating ", Adder.class, " via constructor call");
ConstructorWrapper<Adder> constructor = getDefaultConfiguration().getObjectFactory()
.constructor(Adder.class, Integer.TYPE, Integer.TYPE);
int a = 37, b = 91;
Adder adder = constructor.newInstance(a, b);
Assert.assertNotNull(adder);
Assert.assertSame(adder.getClass(), Adder.class);
Assert.assertEquals(adder.sum(), a + b);
}
/** Attempt to instantiate an interface that does not have a known implementing class. */
@Test(groups = "fast", expectedExceptions = InstantiationException.class)
public void missingInterfaceImpl() throws Throwable {
try {
log.debug("Attempting to instantiate ", Runnable.class, " expecting failure");
getDefaultConfiguration().getObjectFactory().newInstance(Runnable.class);
}
catch (StripesRuntimeException e) {
throw e.getCause();
}
}
@Test(groups = "fast")
public void customInterfaceImpl() {
DefaultObjectFactory factory = new DefaultObjectFactory();
factory.addImplementingClass(CharSequence.class, String.class);
factory.addImplementingClass(List.class, LinkedList.class);
factory.addImplementingClass(Runnable.class, MyRunnable.class);
instantiateInterfaces(factory, CharSequence.class, List.class, Runnable.class);
Assert.assertSame(factory.newInstance(List.class).getClass(), LinkedList.class);
}
/** Attempt to instantiate a class that does not have a no-arg constructor. */
@Test(groups = "fast", expectedExceptions = InstantiationException.class)
public void missingNoArgsConstructor() throws Throwable {
try {
log.debug("Attempting to instantiate ", Adder.class, " expecting failure");
getDefaultConfiguration().getObjectFactory().newInstance(Adder.class);
}
catch (StripesRuntimeException e) {
throw e.getCause();
}
}
/** Alter an instance via {@link DefaultObjectFactory#postProcess(Object)}. */
@Test(groups = "fast")
public void postProcessMethod() {
final String prefix = "Stripey!";
DefaultObjectFactory factory = new DefaultObjectFactory() {
@SuppressWarnings("unchecked")
@Override
protected <T> T postProcess(T object) {
if (object instanceof String)
object = (T) (prefix + object);
return object;
}
};
final String expect = "TEST";
String string;
log.debug("Testing post-process method skips StringBuilder");
string = factory.constructor(StringBuilder.class, String.class).newInstance(expect)
.toString();
log.debug("Got " + string);
Assert.assertEquals(string, expect);
log.debug("Testing post-process method via no-arg constructor");
string = factory.newInstance(String.class);
log.debug("Got " + string);
Assert.assertEquals(string, prefix);
log.debug("Testing post-process method via constructor with args");
string = factory.constructor(String.class, String.class).newInstance(expect);
log.debug("Got " + string);
Assert.assertEquals(string, prefix + expect);
}
/** Alter an instance via {@link DefaultObjectFactory#postProcess(Object)}. */
@Test(groups = "fast")
public void classPostProcessor() {
final String prefix = "Stripey!";
class MyObjectPostProcessor implements ObjectPostProcessor<String> {
public void setObjectFactory(DefaultObjectFactory factory) {}
public String postProcess(String object) {
log.debug("Altering '", object, "'");
return (prefix + object);
}
}
DefaultObjectFactory factory = new DefaultObjectFactory();
factory.addPostProcessor(new MyObjectPostProcessor());
final String expect = "TEST";
String string;
log.debug("Testing post-processor impl skips StringBuilder");
string = factory.constructor(StringBuilder.class, String.class).newInstance(expect)
.toString();
log.debug("Got " + string);
Assert.assertEquals(string, expect);
log.debug("Testing post-processor impl via no-arg constructor");
string = factory.newInstance(String.class);
log.debug("Got " + string);
Assert.assertEquals(string, prefix);
log.debug("Testing post-processor impl via constructor with args");
string = factory.constructor(String.class, String.class).newInstance(expect);
log.debug("Got " + string);
Assert.assertEquals(string, prefix + expect);
}
/** Alter an instance via {@link DefaultObjectFactory#postProcess(Object)}. */
@Test(groups = "fast")
public void interfacePostProcessor() {
final String prefix = "Stripey!";
class MyObjectPostProcessor implements ObjectPostProcessor<CharSequence> {
public void setObjectFactory(DefaultObjectFactory factory) {}
public CharSequence postProcess(CharSequence object) {
log.debug("Altering '", object, "'");
return (prefix + object);
}
}
DefaultObjectFactory factory = new DefaultObjectFactory();
factory.addImplementingClass(Runnable.class, MyRunnable.class);
factory.addPostProcessor(new MyObjectPostProcessor());
final String expect = "TEST";
String string;
log.debug("Testing post-processor impl handles StringBuilder");
string = String.valueOf(factory.constructor(StringBuilder.class, String.class).newInstance(
expect));
log.debug("Got " + string);
Assert.assertEquals(string, prefix + expect);
log.debug("Testing post-processor impl via no-arg constructor");
string = factory.newInstance(String.class);
log.debug("Got " + string);
Assert.assertEquals(string, prefix);
log.debug("Testing post-processor impl via constructor with args");
string = factory.constructor(String.class, String.class).newInstance(expect);
log.debug("Got " + string);
Assert.assertEquals(string, prefix + expect);
log.debug("Testing post-processor does not handle Runnable");
string = factory.newInstance(Runnable.class).getClass().getName();
log.debug("Got " + string);
Assert.assertEquals(string, MyRunnable.class.getName());
}
@Test(groups = "fast")
public void multipleSequentialPostProcessors() {
final AtomicInteger counter = new AtomicInteger(0);
class MyObjectPostProcessor implements ObjectPostProcessor<StringBuilder> {
public void setObjectFactory(DefaultObjectFactory factory) {}
public StringBuilder postProcess(StringBuilder object) {
log.debug("Altering '", object, "'");
return object.append("Touched by ").append(this.toString().replaceAll(".*@", ""))
.append(" (counter=").append(counter.addAndGet(1)).append(") ... ");
}
}
DefaultObjectFactory factory = new DefaultObjectFactory();
for (int i = 0; i < 5; i++) {
factory.addPostProcessor(new MyObjectPostProcessor());
}
log.debug("Testing multiple post-processors");
StringBuilder buf = factory.newInstance(StringBuilder.class);
log.debug("Got ", buf);
Assert.assertEquals(counter.intValue(), 5);
}
}