blob: 066619897c0e38b684b0de1fc3c40e1496148bb0 [file] [log] [blame]
package ioc.specs
import org.apache.tapestry5.func.F
import org.apache.tapestry5.func.Predicate
import org.apache.tapestry5.ioc.annotations.Inject
import org.apache.tapestry5.ioc.def.ServiceDef
import org.apache.tapestry5.ioc.def.ServiceDef2
import org.apache.tapestry5.ioc.internal.QuietOperationTracker
import org.apache.tapestry5.ioc.services.Builtin
import org.apache.tapestry5.ioc.services.Coercion
import org.apache.tapestry5.ioc.services.SymbolSource
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll
import java.lang.reflect.Method
import org.apache.tapestry5.ioc.*
import org.apache.tapestry5.ioc.internal.util.*
class InternalUtilsSpec extends Specification {
private static class PrivateInnerClass {
public PrivateInnerClass() {
}
}
static class PublicInnerClass {
protected PublicInnerClass() {
}
}
@Shared
def tracker = new QuietOperationTracker();
@Unroll
def "asString(): #desc"() {
when:
Method m = clazz.getMethod(methodName, * paramTypes)
then:
InternalUtils.asString(m) == expected
where:
clazz | methodName | paramTypes | expected | desc
Object | "toString" | [] | "java.lang.Object.toString()" | "method with no arguments"
Collections | "sort" | [List, Comparator] | "java.util.Collections.sort(List, Comparator)" | "method with multiple argments"
Object | "wait" | [long] | "java.lang.Object.wait(long)" | "method with primitive argument"
Arrays | "sort" | [int[]] | "java.util.Arrays.sort(int[])" | "method with primitive array argument"
Arrays | "sort" | [Object[]] | "java.util.Arrays.sort(Object[])" | "method with object array argument"
}
@Unroll
def "size(): #desc"() {
expect:
InternalUtils.size(array as Object[]) == expected
where:
array | expected | desc
[] | 0 | "empty array"
null | 0 | "null is size 0"
[1, 2, 3] | 3 | "non-empty array"
}
@Unroll
def "stripMemberName('#input') should be '#expected'"() {
expect:
InternalUtils.stripMemberName(input) == expected
where:
input | expected
"simple" | "simple"
"_name" | "name"
'$name' | "name"
'__$ruby_style_' | "ruby_style"
'$_$__$__$_$____$_$_$_$$name' | "name"
"foo_" | "foo"
"_foo_" | "foo"
}
def "invalid input to stripMemberName() is an exception"() {
when:
InternalUtils.stripMemberName("!foo")
then:
IllegalArgumentException e = thrown()
e.message == "Input '!foo' is not a valid Java identifier."
}
def "toList(Enumeration) is a sorted list"() {
when:
def e = Collections.enumeration(["wilma", "fred", "barney"])
then:
InternalUtils.toList(e) == ["barney", "fred", "wilma"]
}
@Unroll
def "join(): #desc"() {
expect:
InternalUtils.join(list) == expected
where:
list | expected | desc
["barney"] | "barney" | "single value"
["fred", "barney", "wilma"] | "fred, barney, wilma" | "multiple values"
["fred", "barney", "", "wilma"] | "fred, barney, (blank), wilma" | "empty string converted to '(blank)'"
}
@Unroll
def "joinSorted(): #desc"() {
InternalUtils.joinSorted(list) == expected
where:
list | expected | desc
null | "(none)" | "null list is '(none)'"
[] | "(none)" | "empty list is '(none)'"
["barney"] | "barney" | "single value"
["fred", "barney", "wilma"] | "barney, fred, wilma" | "multiple values"
["fred", "barney", "", "wilma"] | "(blank), barney, fred, wilma" | "empty string converted to '(blank)'"
}
@Unroll
def "capitalize('#input') is '#expected'"() {
expect:
InternalUtils.capitalize(input) == expected
where:
input | expected
"hello" | "Hello"
"Goodbye" | "Goodbye"
"" | ""
"a" | "A"
"A" | "A"
}
def "locationOf(Object)"() {
Locatable locatable = Mock()
Location l = Mock()
expect:
InternalUtils.locationOf(null) == null
InternalUtils.locationOf("La! La!") == null
InternalUtils.locationOf(l).is(l)
when:
def actual = InternalUtils.locationOf(locatable)
then:
_ * locatable.location >> l
actual.is(l)
}
@Unroll
def "sortedKeys(): #desc"() {
expect:
InternalUtils.sortedKeys(map) == expected
where:
map | expected | desc
null | [] | "null map"
[:] | [] | "empty map"
["fred": "flintstone", "barney": "rubble"] | ["barney", "fred"] | "standard map"
}
@Unroll
def "get(Map,Object): #desc"() {
expect:
InternalUtils.get(map, key) == expected
where:
map | key | expected | desc
null | null | null | "null key and map"
null | "foo" | null | "null map"
["fred": "flintstone"] | "fred" | "flintstone" | "real map and key"
["fred": "flintstone"] | "barney" | null | "real map with missing key"
}
def "reverseIterator(List)"() {
when:
def i = InternalUtils.reverseIterator(["a", "b", "c"])
then:
i.hasNext()
i.next() == "c"
i.hasNext()
i.next() == "b"
i.hasNext()
i.next() == "a"
!i.hasNext()
}
def "remove() not supported by reverse Iterator"() {
def i = InternalUtils.reverseIterator(["a", "b", "c"])
when:
i.remove()
then:
thrown(UnsupportedOperationException)
}
@Unroll
def "lastTerm(): #desc"() {
expect:
InternalUtils.lastTerm(input) == expected
where:
input | expected | desc
"simple" | "simple" | "single term"
"fee.fie.foe.fum" | "fum" | "dotted name sequence"
}
def "simple value passed to lastTerm() returns the exact input value"() {
def input = "simple"
expect:
InternalUtils.lastTerm(input).is(input)
}
def "addToMapList()"() {
def map = [:]
when:
InternalUtils.addToMapList(map, "fred", 1)
then:
map == ["fred": [1]]
when:
InternalUtils.addToMapList(map, "fred", 2)
then:
map == ["fred": [1, 2]]
}
def "validateMarkerAnnotation()"() {
when:
InternalUtils.validateMarkerAnnotation(Inject)
then:
noExceptionThrown()
when:
InternalUtils.validateMarkerAnnotations([Inject, NotRetainedRuntime] as Class[])
then:
IllegalArgumentException e = thrown()
e.message == "Marker annotation class org.apache.tapestry5.ioc.internal.util.NotRetainedRuntime is not valid because it is not visible at runtime. Add a @Retention(RetentionPolicy.RUNTIME) to the class."
}
def "close(Closable) for null does nothing"() {
when:
InternalUtils.close(null)
then:
noExceptionThrown()
}
def "close(Closable) for success case"() {
Closeable c = Mock()
when:
InternalUtils.close(c)
then:
1 * c.close()
}
def "close(Closable) ignores exceptions"() {
Closeable c = Mock()
when:
InternalUtils.close(c)
then:
1 * c.close() >> {
throw new IOException("ignored")
}
}
def "constructor with Tapestry @Inject annotation"() {
when:
def c = InternalUtils.findAutobuildConstructor(InjectoBean)
then:
c.parameterTypes == [String]
}
def "constructor with javax @Inject annotation"() {
when:
def c = InternalUtils.findAutobuildConstructor(JavaxInjectBean)
then:
c.parameterTypes == [String]
}
def "too many autobuild constructors"() {
when:
InternalUtils.findAutobuildConstructor(TooManyAutobuildConstructorsBean)
then:
IllegalArgumentException e = thrown()
e.message == "Too many autobuild constructors found: use either @org.apache.tapestry5.ioc.annotations.Inject or @javax.inject.Inject annotation to mark a single constructor for autobuilding."
}
def "validateConstructorForAutobuild(): ensure check that the class itself is public"() {
def cons = PrivateInnerClass.constructors[0]
when:
InternalUtils.validateConstructorForAutobuild(cons)
then:
IllegalArgumentException e = thrown()
e.message == "Class ${PrivateInnerClass.name} is not a public class and may not be autobuilt."
}
def "validateConstructorForAutobuild(): ensure check that constructor is public"() {
def cons = PublicInnerClass.declaredConstructors[0]
when:
InternalUtils.validateConstructorForAutobuild(cons)
then:
IllegalArgumentException e = thrown()
e.message == "Constructor protected ${PublicInnerClass.name}() is not public and may not be used for autobuilding an instance of the class. " +
"You should make the constructor public, or mark an alternate public constructor with the @Inject annotation."
}
def "@Inject service annotation on a field"() {
ObjectLocator ol = Mock()
def target = new FieldInjectionViaInjectService()
Runnable fred = Mock()
when:
InternalUtils.injectIntoFields(target, ol, null, tracker)
then:
target.fred.is(fred)
1 * ol.getService("FredService", Runnable) >> fred
}
def "@javax.annotations.Inject / @Named annotation on field"() {
ObjectLocator ol = Mock()
def target = new FieldInjectionViaJavaxNamed()
Runnable fred = Mock()
when:
InternalUtils.injectIntoFields(target, ol, null, tracker)
then:
target.fred.is(fred)
1 * ol.getService("BarneyService", Runnable) >> fred
}
def "@Inject annotation on field"() {
ObjectLocator ol = Mock()
def target = new FieldInjectionViaInject()
SymbolSource source = Mock()
InjectionResources resources = Mock()
when:
InternalUtils.injectIntoFields(target, ol, resources, tracker)
then:
target.symbolSource.is(source)
1 * resources.findResource(SymbolSource, SymbolSource) >> null
1 * ol.getObject(SymbolSource, _) >> { type, ap ->
assert ap.getAnnotation(Builtin) != null
return source
}
}
def "@javax.annotation.Inject annotation on field"() {
ObjectLocator ol = Mock()
def target = new FieldInjectionViaJavaxInject()
SymbolSource source = Mock()
InjectionResources resources = Mock()
when:
InternalUtils.injectIntoFields(target, ol, resources, tracker)
then:
target.symbolSource.is(source)
1 * resources.findResource(SymbolSource, SymbolSource) >> null
1 * ol.getObject(SymbolSource, _) >> { type, ap ->
assert ap.getAnnotation(Builtin) != null
return source
}
}
def "check handling of exception while injecting into a field"() {
ObjectLocator ol = Mock()
def target = new FieldInjectionViaInjectService()
when:
InternalUtils.injectIntoFields(target, ol, null, tracker)
then:
Exception e = thrown()
1 * ol.getService("FredService", Runnable) >> "NotTheRightType"
e.message.contains "Unable to set field 'fred' of <FieldInjectionViaInjectService> to NotTheRightType"
}
@Unroll
def "keys(Map): #desc"() {
expect:
InternalUtils.keys(map) == (expected as Set)
where:
map | expected | desc
null | [] | "null map"
[:] | [] | "empty map"
["fred": "flintstone", "barney": "rubble"] | ["fred", "barney"] | "non-empty map"
}
@Unroll
def "size(Collection): #desc"() {
expect:
InternalUtils.size(coll) == expected
where:
coll | expected | desc
null | 0 | "null collection"
[] | 0 | "empty collection"
[1, 2, 3] | 3 | "non-empty collection"
}
def "toServiceDef2() delegates most methods to ServiceDef instance"() {
ServiceDef delegate = Mock()
ServiceBuilderResources resources = Mock()
ObjectCreator creator = Mock()
def serviceId = "fred"
def markers = [] as Set
ServiceDef2 sd = InternalUtils.toServiceDef2(delegate)
when:
def actual = sd.createServiceCreator(resources)
then:
actual.is creator
1 * delegate.createServiceCreator(resources) >> creator
when:
actual = sd.getServiceId()
then:
actual.is serviceId
1 * delegate.serviceId >> serviceId
when:
actual = sd.markers
then:
actual.is markers
1 * delegate.markers >> markers
when:
actual = sd.serviceInterface
then:
actual == Runnable
1 * delegate.serviceInterface >> Runnable
when:
actual = sd.serviceScope
then:
actual == ScopeConstants.PERTHREAD
1 * delegate.serviceScope >> ScopeConstants.PERTHREAD
when:
actual = sd.eagerLoad
then:
actual == true
1 * delegate.eagerLoad >> true
expect:
!sd.preventDecoration
}
def "matchAndSort()"() {
def pred = { !it.startsWith(".") } as Predicate
expect:
InternalUtils.matchAndSort(["Fred", "Barney", "..", ".hidden", "Wilma"], pred) == ["Barney", "Fred", "Wilma"]
}
def "toMapper(Coercion)"() {
def coercion = { it.toUpperCase() } as Coercion
def flow = F.flow("Mary", "had", "a", "little", "lamb")
expect:
flow.map(InternalUtils.toMapper(coercion)).toList() == ["MARY", "HAD", "A", "LITTLE", "LAMB"]
}
}