You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2012/06/21 19:28:19 UTC
[3/9] git commit: Refactor all the tapestry-ioc Spock specifications
into the ioc.specs package Convert some package-private classes and
constructors to public
Refactor all the tapestry-ioc Spock specifications into the ioc.specs package
Convert some package-private classes and constructors to public
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/a1bef869
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/a1bef869
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/a1bef869
Branch: refs/heads/master
Commit: a1bef8696b1737a15986de2ce502842de6989f00
Parents: 313b7bf
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Thu Jun 21 10:01:11 2012 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Thu Jun 21 10:08:39 2012 -0700
----------------------------------------------------------------------
.../ioc/internal/services/BridgeBuilder.java | 24 +-
.../internal/services/FilterMethodAnalyzer.java | 2 +-
.../ioc/internal/services/MethodIterator.java | 14 +-
.../ioc/internal/services/MethodSignature.java | 8 +-
.../ioc/internal/util/InheritanceSearch.java | 7 +-
.../ioc/specs/AbstractRegistrySpecification.groovy | 33 +
.../AbstractSharedRegistrySpecification.groovy | 46 +
.../src/test/groovy/ioc/specs/AdvisorsSpec.groovy | 83 ++
.../specs/AspectInterceptorBuilderImplSpec.groovy | 151 +++
.../src/test/groovy/ioc/specs/AutobuildSpec.groovy | 172 ++++
.../test/groovy/ioc/specs/BaseLocatableSpec.groovy | 36 +
.../test/groovy/ioc/specs/BridgeBuilderSpec.groovy | 169 ++++
.../groovy/ioc/specs/CaseInsensitiveMapSpec.groovy | 303 ++++++
.../groovy/ioc/specs/ChainBuilderImplSpec.groovy | 121 +++
.../ioc/specs/ClassNameLocatorImplSpec.groovy | 76 ++
.../ClasspathResourceSymbolProviderSpec.groovy | 31 +
.../groovy/ioc/specs/ConcurrentBarrierSpec.groovy | 146 +++
.../groovy/ioc/specs/ConfigurationsSpec.groovy | 317 +++++++
.../ioc/specs/ContributionDefImplSpec.groovy | 209 +++++
.../groovy/ioc/specs/CronExpressionSpec.groovy | 104 +++
.../test/groovy/ioc/specs/CronScheduleSpec.groovy | 26 +
.../test/groovy/ioc/specs/DecoratorsSpec.groovy | 110 +++
.../DefaultImplementationBuilderImplSpec.groovy | 39 +
.../ioc/specs/DefaultModuleDefImplSpec.groovy | 450 +++++++++
.../src/test/groovy/ioc/specs/DummyLockSpec.groovy | 28 +
.../src/test/groovy/ioc/specs/EagerLoadSpec.groovy | 22 +
.../ioc/specs/ExceptionAnalyzerImplSpec.groovy | 214 +++++
.../ioc/specs/ExceptionTrackerImplSpec.groovy | 32 +
.../groovy/ioc/specs/ExceptionUtilsSpec.groovy | 53 ++
.../ioc/specs/FilterMethodAnalyzerSpec.groovy | 37 +
.../groovy/ioc/specs/GeneralIntegrationSpec.groovy | 25 +
.../test/groovy/ioc/specs/GenericUtilsSpec.groovy | 40 +
.../groovy/ioc/specs/GlobPatternMatcherSpec.groovy | 63 ++
.../test/groovy/ioc/specs/IdAllocatorSpec.groovy | 163 ++++
.../groovy/ioc/specs/InheritanceSearchSpec.groovy | 68 ++
.../src/test/groovy/ioc/specs/InjectionSpec.groovy | 125 +++
.../test/groovy/ioc/specs/InternalUtilsSpec.groovy | 607 ++++++++++++
.../ioc/specs/JustInTimeObjectCreatorSpec.groovy | 53 ++
.../groovy/ioc/specs/LazyAdvisorImplSpec.groovy | 140 +++
.../ioc/specs/LocalizedNamesGeneratorSpec.groovy | 39 +
.../test/groovy/ioc/specs/LocationImplSpec.groovy | 89 ++
.../ioc/specs/LoggingDecoratorImplSpec.groovy | 173 ++++
.../groovy/ioc/specs/LoggingSourceImplSpec.groovy | 30 +
.../groovy/ioc/specs/ManifestProcessingSpec.groovy | 37 +
.../ioc/specs/MasterObjectProviderImplSpec.groovy | 110 +++
.../ioc/specs/MessageFormatterImplSpec.groovy | 28 +
.../test/groovy/ioc/specs/MessagesImplSpec.groovy | 76 ++
.../groovy/ioc/specs/MethodIteratorSpec.groovy | 115 +++
.../groovy/ioc/specs/MethodSignatureSpec.groovy | 179 ++++
.../test/groovy/ioc/specs/ModuleImplSpec.groovy | 280 ++++++
.../ioc/specs/ModuleInstantiationSpec.groovy | 55 ++
.../ioc/specs/NonParallelExecutorSpec.groovy | 59 ++
.../test/groovy/ioc/specs/OneShotLockSpec.groovy | 42 +
.../groovy/ioc/specs/OperationAdvisorSpec.groovy | 87 ++
.../ioc/specs/OrderedConstraintBuilderSpec.groovy | 31 +
.../src/test/groovy/ioc/specs/OrdererSpec.groovy | 285 ++++++
.../groovy/ioc/specs/ParallelExecutorSpec.groovy | 104 +++
.../groovy/ioc/specs/PerThreadScopeSpec.groovy | 91 ++
.../groovy/ioc/specs/PeriodicExecutorSpec.groovy | 29 +
.../ioc/specs/PerthreadManagerImplSpec.groovy | 183 ++++
.../ioc/specs/PipelineBuilderImplSpec.groovy | 87 ++
.../groovy/ioc/specs/PropertyAccessImplSpec.groovy | 709 +++++++++++++++
.../ioc/specs/PropertyShadowBuilderImplSpec.groovy | 121 +++
...RecursiveServiceCreationCheckWrapperSpec.groovy | 82 ++
.../groovy/ioc/specs/RegistryBuilderSpec.groovy | 96 ++
...RegistryConstructionAndRuntimeErrorsSpec.groovy | 118 +++
.../src/test/groovy/ioc/specs/RegistrySpec.groovy | 56 ++
.../groovy/ioc/specs/RegistryStartupSpec.groovy | 97 ++
.../ioc/specs/RegistryshutdownHubImplSpec.groovy | 106 +++
.../src/test/groovy/ioc/specs/ReloadSpec.groovy | 403 ++++++++
.../ioc/specs/ResourceSymbolProviderSpec.groovy | 32 +
.../ioc/specs/ServiceActivityScoreboardSpec.groovy | 75 ++
.../test/groovy/ioc/specs/ServiceBinderSpec.groovy | 37 +
.../specs/ServiceBuilderMethodInvokerSpec.groovy | 199 ++++
.../ioc/specs/ServiceCreatorGenericsSpec.groovy | 82 ++
.../test/groovy/ioc/specs/ServiceLookupSpec.groovy | 118 +++
.../test/groovy/ioc/specs/ServiceProxySpec.groovy | 98 ++
.../src/test/groovy/ioc/specs/StackSpec.groovy | 113 +++
.../ioc/specs/StrategyBuilderImplSpec.groovy | 69 ++
.../groovy/ioc/specs/StrategyRegistrySpec.groovy | 148 +++
.../ioc/specs/StringToEnumCoercionSpec.groovy | 53 ++
.../ioc/specs/SystemEnvSymbolProviderSpec.groovy | 21 +
.../test/groovy/ioc/specs/TimeIntervalSpec.groovy | 72 ++
.../src/test/groovy/ioc/specs/ToString.groovy | 7 +
.../groovy/ioc/specs/URLChangeTrackerSpec.groovy | 187 ++++
.../ValidatingConfigurationWrapperSpec.groovy | 80 ++
...ValidatingMappedConfigurationWrapperSpec.groovy | 154 ++++
...alidatingOrderedConfigurationWrapperSpec.groovy | 82 ++
.../ioc/AbstractRegistrySpecification.groovy | 31 -
.../ioc/AbstractSharedRegistrySpecification.groovy | 44 -
.../org/apache/tapestry5/ioc/AdvisorsSpec.groovy | 83 --
.../org/apache/tapestry5/ioc/AutobuildSpec.groovy | 171 ----
.../apache/tapestry5/ioc/BaseLocatableSpec.groovy | 33 -
.../apache/tapestry5/ioc/ConfigurationsSpec.groovy | 316 -------
.../org/apache/tapestry5/ioc/DecoratorsSpec.groovy | 109 ---
.../org/apache/tapestry5/ioc/EagerLoadSpec.groovy | 20 -
.../org/apache/tapestry5/ioc/InjectionSpec.groovy | 123 ---
.../tapestry5/ioc/ManifestProcessingSpec.groovy | 36 -
.../tapestry5/ioc/ModuleInstantiationSpec.groovy | 53 --
.../ioc/OrderedConstraintBuilderSpec.groovy | 30 -
.../apache/tapestry5/ioc/PerThreadScopeSpec.groovy | 88 --
.../tapestry5/ioc/RegistryBuilderSpec.groovy | 95 --
...RegistryConstructionAndRuntimeErrorsSpec.groovy | 117 ---
.../org/apache/tapestry5/ioc/RegistrySpec.groovy | 53 --
.../org/apache/tapestry5/ioc/ReloadSpec.groovy | 401 --------
.../ioc/ServiceActivityScoreboardSpec.groovy | 74 --
.../apache/tapestry5/ioc/ServiceBinderSpec.groovy | 35 -
.../apache/tapestry5/ioc/ServiceLookupSpec.groovy | 116 ---
.../apache/tapestry5/ioc/ServiceProxySpec.groovy | 96 --
.../ioc/internal/ContributionDefImplSpec.groovy | 208 -----
.../ioc/internal/DefaultModuleDefImplSpec.groovy | 449 ---------
.../ioc/internal/GlobPatternMatcherSpec.groovy | 63 --
.../ioc/internal/LazyAdvisorImplSpec.groovy | 141 ---
.../ioc/internal/LoggingDecoratorImplSpec.groovy | 172 ----
.../ioc/internal/LoggingSourceImplSpec.groovy | 29 -
.../tapestry5/ioc/internal/ModuleImplSpec.groovy | 280 ------
...RecursiveServiceCreationCheckWrapperSpec.groovy | 80 --
.../ServiceBuilderMethodInvokerSpec.groovy | 195 ----
.../ioc/internal/ServiceCreatorGenericsSpec.groovy | 79 --
.../ValidatingConfigurationWrapperSpec.groovy | 78 --
...ValidatingMappedConfigurationWrapperSpec.groovy | 152 ---
...alidatingOrderedConfigurationWrapperSpec.groovy | 80 --
.../AspectInterceptorBuilderImplSpec.groovy | 152 ---
.../ioc/internal/services/BridgeBuilderSpec.groovy | 169 ----
.../internal/services/ChainBuilderImplSpec.groovy | 122 ---
.../services/ClassNameLocatorImplSpec.groovy | 74 --
.../ClasspathResourceSymbolProviderSpec.groovy | 30 -
.../DefaultImplementationBuilderImplSpec.groovy | 40 -
.../services/ExceptionAnalyzerImplSpec.groovy | 215 -----
.../services/ExceptionTrackerImplSpec.groovy | 32 -
.../services/FilterMethodAnalyzerSpec.groovy | 33 -
.../services/JustInTimeObjectCreatorSpec.groovy | 52 --
.../services/MasterObjectProviderImplSpec.groovy | 109 ---
.../internal/services/MethodIteratorSpec.groovy | 113 ---
.../internal/services/MethodSignatureSpec.groovy | 178 ----
.../services/NonParallelExecutorSpec.groovy | 58 --
.../internal/services/ParallelExecutorSpec.groovy | 105 ---
.../services/PerthreadManagerImplSpec.groovy | 182 ----
.../services/PipelineBuilderImplSpec.groovy | 86 --
.../services/PropertyAccessImplSpec.groovy | 708 --------------
.../services/PropertyShadowBuilderImplSpec.groovy | 122 ---
.../internal/services/RegistryStartupSpec.groovy | 95 --
.../services/RegistryshutdownHubImplSpec.groovy | 105 ---
.../services/ResourceSymbolProviderSpec.groovy | 31 -
.../services/StrategyBuilderImplSpec.groovy | 70 --
.../ioc/internal/services/ToString.groovy | 7 -
.../services/cron/CronExpressionSpec.groovy | 103 ---
.../tapestry5/ioc/services/CronScheduleSpec.groovy | 27 -
.../ioc/services/GeneralIntegrationSpec.groovy | 26 -
.../ioc/services/OperationAdvisorSpec.groovy | 83 --
.../ioc/services/PeriodicExecutorSpec.groovy | 30 -
.../services/SystemEnvSymbolProviderSpec.groovy | 20 -
.../ioc/util/CaseInsensitiveMapSpec.groovy | 303 ------
.../ioc/util/ConcurrentBarrierSpec.groovy | 146 ---
.../apache/tapestry5/ioc/util/DummyLockSpec.groovy | 28 -
.../tapestry5/ioc/util/GenericUtilsSpec.groovy | 40 -
.../ioc/util/InheritanceSearchSpec.groovy | 68 --
.../tapestry5/ioc/util/InternalUtilsSpec.groovy | 607 ------------
.../tapestry5/ioc/util/LocationImplSpec.groovy | 89 --
.../ioc/util/MessageFormatterImplSpec.groovy | 28 -
.../tapestry5/ioc/util/MessagesImplSpec.groovy | 76 --
.../tapestry5/ioc/util/OneShotLockSpec.groovy | 42 -
.../apache/tapestry5/ioc/util/OrdererSpec.groovy | 285 ------
.../tapestry5/ioc/util/URLChangeTrackerSpec.groovy | 187 ----
.../tapestry5/util/ExceptionUtilsSpec.groovy | 53 --
.../org/apache/tapestry5/util/StackSpec.groovy | 113 ---
.../tapestry5/util/StrategyRegistrySpec.groovy | 148 ---
.../tapestry5/util/StringToEnumCoercionSpec.groovy | 52 --
.../apache/tapestry5/util/TimeIntervalSpec.groovy | 72 --
.../org/apache/tapestry5/ioc/MasterModule.java | 4 +-
.../test/java/org/apache/tapestry5/ioc/Square.java | 2 +-
.../internal/ExtraPublicConstructorsModule.java | 2 +-
.../ioc/internal/ModuleImplTestModule.java | 4 +-
.../ioc/internal/PrivateConstructorModule.java | 7 +-
.../ioc/internal/ServiceBuilderMethodFixture.java | 13 +-
.../apache/tapestry5/ioc/internal/util/Bar.java | 2 +-
.../tapestry5/ioc/internal/util/BarImpl.java | 2 +-
.../apache/tapestry5/ioc/internal/util/Foo.java | 2 +-
.../apache/tapestry5/ioc/internal/util/FooBar.java | 2 +-
.../tapestry5/ioc/internal/util/FooBarImpl.java | 2 +-
.../tapestry5/ioc/internal/util/FooImpl.java | 2 +-
.../ioc/internal/util/TargetMessages.java | 2 +-
.../tapestry5/ioc/util/IdAllocatorSpec.groovy | 163 ----
.../ioc/util/LocalizedNamesGeneratorSpec.groovy | 39 -
184 files changed, 9966 insertions(+), 9897 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/BridgeBuilder.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/BridgeBuilder.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/BridgeBuilder.java
index 4a0276c..8ff4762 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/BridgeBuilder.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/BridgeBuilder.java
@@ -14,26 +14,20 @@
package org.apache.tapestry5.ioc.internal.services;
-import java.util.Iterator;
-import java.util.List;
-
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
-import org.apache.tapestry5.plastic.ClassInstantiator;
-import org.apache.tapestry5.plastic.InstructionBuilder;
-import org.apache.tapestry5.plastic.InstructionBuilderCallback;
-import org.apache.tapestry5.plastic.PlasticClass;
-import org.apache.tapestry5.plastic.PlasticClassTransformer;
-import org.apache.tapestry5.plastic.PlasticField;
-import org.apache.tapestry5.plastic.PlasticMethod;
+import org.apache.tapestry5.plastic.*;
import org.slf4j.Logger;
+import java.util.Iterator;
+import java.util.List;
+
/**
* Used by the {@link org.apache.tapestry5.ioc.internal.services.PipelineBuilderImpl} to create bridge classes and to
* create instances of bridge classes. A bridge class implements the <em>service</em> interface. Within the chain,
* bridge 1 is passed to filter 1. Invoking methods on bridge 1 will invoke methods on filter 2.
*/
-class BridgeBuilder<S, F>
+public class BridgeBuilder<S, F>
{
private final Logger logger;
@@ -47,7 +41,7 @@ class BridgeBuilder<S, F>
private ClassInstantiator<S> instantiator;
- BridgeBuilder(Logger logger, Class<S> serviceInterface, Class<F> filterInterface, PlasticProxyFactory proxyFactory)
+ public BridgeBuilder(Logger logger, Class<S> serviceInterface, Class<F> filterInterface, PlasticProxyFactory proxyFactory)
{
this.logger = logger;
this.serviceInterface = serviceInterface;
@@ -61,8 +55,10 @@ class BridgeBuilder<S, F>
/**
* Instantiates a bridge object.
*
- * @param nextBridge the next Bridge object in the pipeline, or the terminator service
- * @param filter the filter object for this step of the pipeline
+ * @param nextBridge
+ * the next Bridge object in the pipeline, or the terminator service
+ * @param filter
+ * the filter object for this step of the pipeline
*/
public S instantiateBridge(S nextBridge, F filter)
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/FilterMethodAnalyzer.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/FilterMethodAnalyzer.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/FilterMethodAnalyzer.java
index b11d80b..9632bb0 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/FilterMethodAnalyzer.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/FilterMethodAnalyzer.java
@@ -18,7 +18,7 @@ package org.apache.tapestry5.ioc.internal.services;
* Used by {@link org.apache.tapestry5.ioc.internal.services.PipelineBuilderImpl} to analyze service interface methods
* against filter interface methods to find the position of the extra service parameter (in the filter method).
*/
-class FilterMethodAnalyzer
+public class FilterMethodAnalyzer
{
private final Class serviceInterface;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MethodIterator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MethodIterator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MethodIterator.java
index 7cadee2..5dc4b3a 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MethodIterator.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MethodIterator.java
@@ -14,22 +14,20 @@
package org.apache.tapestry5.ioc.internal.services;
-import org.apache.tapestry5.ioc.internal.services.MethodSignature;
+import java.lang.reflect.Method;
+import java.util.*;
import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newList;
import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newMap;
-import java.lang.reflect.Method;
-import java.util.*;
-
/**
* Utility used to iterate over the publically visible methods of a class or interface. The MethodIterator understands
* some complications that can occur when a class inherits the same method from multiple interfaces and with slightly
* different signatures (due to the fact that declared thrown exceptions can vary slightly for the "same" method).
- *
+ *
* @see MethodSignature#isOverridingSignatureOf(MethodSignature)
*/
-class MethodIterator
+public class MethodIterator
{
private boolean toString;
@@ -100,9 +98,9 @@ class MethodIterator
* Returns the next method (as a {@link MethodSignature}, returning null when all are exhausted. Each method
* signature is returned exactly once (even if the same method signature is defined in multiple inherited classes or
* interfaces). The method signatures returned in ascending order, according to the "natural ordering".
- *
+ *
* @throws NoSuchElementException
- * if there are no more signatures
+ * if there are no more signatures
*/
public MethodSignature next()
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MethodSignature.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MethodSignature.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MethodSignature.java
index 63ea2c2..e18a0a1 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MethodSignature.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/MethodSignature.java
@@ -14,12 +14,12 @@
package org.apache.tapestry5.ioc.internal.services;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.plastic.PlasticUtils;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
/**
* A representation of a {@link java.lang.reflect.Method}, identifying the name, return type, parameter types and
* exception types. Actual Method objects are tied to a particular class, and don't compare well with other otherwise
@@ -30,7 +30,7 @@ import org.apache.tapestry5.plastic.PlasticUtils;
* instance and static methods</em>.
*/
@SuppressWarnings("all")
-class MethodSignature
+public class MethodSignature
{
private int hashCode = -1;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
index 824f7ef..c645807 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
@@ -32,8 +32,8 @@ import java.util.Set;
* Once all interfaces are exhausted, java.lang.Object is returned (it is always returned last).
* <p/>
* Two minor tweak to normal inheritance rules: <ul> <li> Normally, the parent class of an <em>object</em> array is
- * java.lang.Object, which is odd because Foo[] is assignable to Object[]. Thus, we tweak the search so that the
- * effective super class of Foo[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>,
+ * java.lang.Object, which is odd because FooService[] is assignable to Object[]. Thus, we tweak the search so that the
+ * effective super class of FooService[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>,
* with the exception of void, whose "super class" is left at its normal value (Object.class) </ul>
* <p/>
* This class implements the {@link Iterable} interface, so it can be used directly in a for loop: <code> for (Class
@@ -144,7 +144,8 @@ public class InheritanceSearch implements Iterator<Class>, Iterable<Class>
}
/**
- * @throws UnsupportedOperationException always
+ * @throws UnsupportedOperationException
+ * always
*/
public void remove()
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/AbstractRegistrySpecification.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/AbstractRegistrySpecification.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/AbstractRegistrySpecification.groovy
new file mode 100644
index 0000000..5283641
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/AbstractRegistrySpecification.groovy
@@ -0,0 +1,33 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.Registry
+import org.apache.tapestry5.ioc.RegistryBuilder
+import spock.lang.AutoCleanup
+import spock.lang.Specification
+
+/**
+ * Base class for Spock specifications that use a new {@link Registry} for each feature method.
+ */
+abstract class AbstractRegistrySpecification extends Specification {
+
+ @AutoCleanup("shutdown")
+ protected Registry registry;
+
+ /**
+ * Constructs a new {@link Registry} using the indicated module classes.
+ * The Registry will be shutdown after each feature method.
+ *
+ * @param moduleClasses classes to include when building the Registry
+ */
+ protected final void buildRegistry(Class... moduleClasses) {
+
+ registry = new RegistryBuilder().add(moduleClasses).build()
+ }
+
+ /** Any unrecognized methods are evaluated against the registry. */
+ def methodMissing(String name, args) {
+ registry."$name"(* args)
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/AbstractSharedRegistrySpecification.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/AbstractSharedRegistrySpecification.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/AbstractSharedRegistrySpecification.groovy
new file mode 100644
index 0000000..cd4a006
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/AbstractSharedRegistrySpecification.groovy
@@ -0,0 +1,46 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.IOCUtilities
+import org.apache.tapestry5.ioc.Registry
+import spock.lang.Specification
+
+import java.lang.reflect.Method
+
+/**
+ * Uses a static, shared instance of the {@link org.apache.tapestry5.ioc.Registry}.
+ * All specifications that extend from this class will share
+ * a single instance of the Registry; The Registry is created by whatever specification is created first.
+ * Missing method invocations are forwarded to the registry instance. */
+abstract class AbstractSharedRegistrySpecification extends Specification {
+
+ static Registry registry
+
+ /** Any unrecognized methods are evaluated against the shared Registry instance. */
+ def methodMissing(String name, args) {
+ registry."$name"(* args)
+ }
+
+ /** Creates the Registry if it does not already exist. */
+ def setupSpec() {
+ if (registry == null) {
+ registry = IOCUtilities.buildDefaultRegistry()
+ }
+ }
+
+ /** Invokes {@link Registry#cleanupThread()}. */
+ def cleanupSpec() {
+ registry.cleanupThread();
+ }
+
+ // TODO: the Registry is never shutdown, since there's no notification
+ // that all tests are completing.
+
+ protected Method findMethod(Object subject, String methodName) {
+ def method = subject.class.methods.find { it.name == methodName }
+
+ assert method != null
+
+ return method
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/AdvisorsSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/AdvisorsSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/AdvisorsSpec.groovy
new file mode 100644
index 0000000..3254e5a
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/AdvisorsSpec.groovy
@@ -0,0 +1,83 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.internal.AdviseByMarkerModule
+import org.apache.tapestry5.ioc.internal.AdviseByMarkerModule2
+import org.apache.tapestry5.ioc.*
+
+class AdvisorsSpec extends AbstractRegistrySpecification {
+
+ def "advisor methods must return void"() {
+ when:
+
+ buildRegistry NonVoidAdvisorMethodModule
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message.contains "Advise method org.apache.tapestry5.ioc.NonVoidAdvisorMethodModule.adviseFoo(MethodAdviceReceiver)"
+ e.message.contains "does not return void"
+ }
+
+ def "advisor methods must take a MethodAdviceReceiver parameter"() {
+ when:
+
+ buildRegistry AdviceMethodMissingAdvisorParameterModule
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message.contains "Advise method org.apache.tapestry5.ioc.AdviceMethodMissingAdvisorParameterModule.adviseBar()"
+ e.message.contains "must take a parameter of type org.apache.tapestry5.ioc.MethodAdviceReceiver."
+ }
+
+ def "adding advice to services"() {
+ buildRegistry AdviceDemoModule
+
+ when:
+
+ def g = getService Greeter
+
+ then:
+
+ g.greeting == "ADVICE IS EASY!"
+ }
+
+ def "methods marked with @Advise are advisor methods"() {
+
+ buildRegistry GreeterModule2, AdviseByMarkerModule
+
+ when:
+
+ def green = getService "GreenGreeter", Greeter
+
+ then:
+
+ green.greeting == "gamma[beta[alpha[Green]]]"
+ }
+
+ def "@Advise with @Local only advises services in the same module"() {
+ buildRegistry GreeterModule2, AdviseByMarkerModule
+
+ when:
+
+ def red = getService "RedGreeter", Greeter
+
+ then:
+
+ red.greeting == "delta[Red]"
+ }
+
+ def "@Advise with id attribute"() {
+ buildRegistry AdviseByMarkerModule2
+
+ when:
+
+ def red = getService "RedGreeter", Greeter
+
+ then:
+
+ red.greeting == "beta[alpha[Red]]"
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/AspectInterceptorBuilderImplSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/AspectInterceptorBuilderImplSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/AspectInterceptorBuilderImplSpec.groovy
new file mode 100644
index 0000000..e543482
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/AspectInterceptorBuilderImplSpec.groovy
@@ -0,0 +1,151 @@
+package ioc.specs
+
+import org.apache.commons.lang.StringUtils
+import org.apache.tapestry5.ioc.internal.services.TextTransformer
+import org.apache.tapestry5.ioc.services.AspectDecorator
+import org.apache.tapestry5.plastic.MethodAdvice
+import org.apache.tapestry5.plastic.MethodInvocation
+import spock.lang.Shared
+
+interface Subject {
+
+ void advised();
+
+ void notAdvised();
+}
+
+interface ArraysSubject {
+
+ String[] operation(String[] inputs);
+}
+
+class AspectInterceptorBuilderImplSpec extends AbstractSharedRegistrySpecification {
+
+ @Shared
+ private AspectDecorator decorator
+
+ def setupSpec() {
+ decorator = getService AspectDecorator
+ }
+
+ def "ensure that non-advised methods are not passed through the MethodAdvice object"() {
+ Subject delegate = Mock()
+ MethodAdvice advice = Mock()
+
+ def builder = decorator.createBuilder Subject, delegate, "<Subject>"
+
+ builder.adviseMethod Subject.getMethod("advised"), advice
+
+ Subject interceptor = builder.build()
+
+ when:
+
+ interceptor.advised()
+
+ then:
+
+ 1 * advice.advise(_) >> { MethodInvocation mi ->
+ assert mi.method.name == "advised"
+ mi.proceed()
+ }
+ 1 * delegate.advised()
+ 0 * _
+
+ when:
+
+ interceptor.notAdvised()
+
+ then:
+
+ 1 * delegate.notAdvised()
+ 0 * _
+ }
+
+ def "failure when advising a method that is not in the service interface"() {
+ Subject delegate = Mock()
+ MethodAdvice advice = Mock()
+
+ def builder = decorator.createBuilder Subject, delegate, "<Subject>"
+
+ when:
+
+ builder.adviseMethod Runnable.getMethod("run"), advice
+
+ then:
+
+ IllegalArgumentException e = thrown()
+
+ e.message == "Method public abstract void java.lang.Runnable.run() is not defined for interface interface ioc.specs.Subject."
+ }
+
+ def "multiple advice for single method is processed in order"() {
+ TextTransformer delegate = Mock()
+ MethodAdvice stripFirstLetter = Mock()
+ MethodAdvice reverse = Mock()
+
+ def builder = decorator.createBuilder TextTransformer, delegate, "<TextTransformer>"
+
+ def method = TextTransformer.getMethod "transform", String
+
+ builder.adviseMethod method, stripFirstLetter
+ builder.adviseMethod method, reverse
+
+ TextTransformer advised = builder.build()
+
+ when:
+
+ def result = advised.transform "Tapestry"
+
+ then:
+
+ result == "[yrtsepa]"
+
+ 1 * stripFirstLetter.advise(_) >> { MethodInvocation mi ->
+ assert mi.getParameter(0) == "Tapestry"
+ mi.setParameter 0, mi.getParameter(0).substring(1)
+ mi.proceed()
+ }
+
+ 1 * reverse.advise(_) >> { MethodInvocation mi ->
+ assert mi.getParameter(0) == "apestry"
+ mi.setParameter 0, StringUtils.reverse(mi.getParameter(0))
+ mi.proceed()
+ }
+
+ 1 * delegate.transform(_) >> { it }
+ }
+
+ def "arrays are allowed as method parameters and return values"() {
+ ArraysSubject delegate = Mock()
+ MethodAdvice advice = Mock()
+
+ def builder = decorator.createBuilder ArraysSubject, delegate, "unused"
+ builder.adviseAllMethods advice
+
+ ArraysSubject advised = builder.build()
+
+ when:
+
+ def result = advised.operation(["Fred", "Barney"] as String[])
+
+ then:
+
+ 1 * advice.advise(_) >> { MethodInvocation it ->
+ String[] inputs = it.getParameter(0)
+
+ it.setParameter 0, inputs.collect({it.toUpperCase() }) as String[]
+
+ it.proceed()
+
+ def index = 0
+
+ it.setReturnValue it.getReturnValue().collect({ value -> "${index++}:$value" }) as String[]
+ }
+
+ 1 * delegate.operation(_) >> { it[0] }
+
+ result.class == ([] as String[]).class
+ result.asType(List) == ["0:FRED", "1:BARNEY"]
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/AutobuildSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/AutobuildSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/AutobuildSpec.groovy
new file mode 100644
index 0000000..78d46ed
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/AutobuildSpec.groovy
@@ -0,0 +1,172 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.internal.ExceptionInConstructorModule
+import org.apache.tapestry5.ioc.*
+
+class AutobuildSpec extends AbstractRegistrySpecification {
+
+ def "ensure that services defined with bind() are automatically built"() {
+ buildRegistry AutobuildModule
+
+ def sh = getService StringHolder
+
+ when:
+
+ sh.value = "Foo"
+
+ then:
+
+ sh.value == "Foo"
+ }
+
+ def "check reporting of exception in autobuilt service constructor"() {
+ buildRegistry ExceptionInConstructorModule
+
+ def pingable = getService Pingable
+
+ when:
+
+ pingable.ping()
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message.contains "Error invoking constructor"
+ e.message.contains "ExceptionInConstructorServiceImpl()"
+ e.message.contains "Yes, we have no tomatoes."
+ }
+
+ def "bind() finds the default Impl class"() {
+ buildRegistry ConventionModule
+
+ def holder = getService StringHolder
+
+ when:
+
+ // This proves we can invoke methods, meaning that an implementation was found.
+
+ holder.value = "Bar"
+
+ then:
+
+ holder.value == "Bar"
+ }
+
+ def "validate exception reporting for no default implementation found"() {
+ when:
+
+ buildRegistry ConventionModuleImplementationNotFound
+
+ then:
+
+ RuntimeException e = thrown()
+ e.message.contains "Could not find default implementation class org.apache.tapestry5.ioc.StringTransformerImpl."
+ e.message.contains "Please provide this class, or bind the service interface to a specific implementation class."
+ }
+
+ def "validate exception reporting for incorrect implementation (that does not implement service interface)"() {
+ when:
+
+ buildRegistry ConventionFailureModule
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message.contains "No service implements the interface ${Pingable.name}"
+ }
+
+ def "service builder method can use ServiceResources.autobuild()"() {
+ buildRegistry ServiceBuilderAutobuilderModule
+
+ def holder = getService StringHolder
+
+ when:
+
+ holder.value = "Foo"
+
+ then:
+
+ holder.value == "Foo"
+ }
+
+ def "ensure that Registry.autobuild() works"() {
+
+ buildRegistry()
+
+ when:
+
+ def holder = autobuild StringHolderImpl
+
+ // This test should go further and verify that injections into StringHolderImpl work.
+
+ then:
+
+ holder.class == StringHolderImpl
+
+ when:
+
+ holder.value = "Foo"
+
+ then:
+
+ holder.value == "Foo"
+ }
+
+ def "ensure that Registry.autobuild() works (with a description)"() {
+ buildRegistry()
+
+ when:
+
+ def holder = autobuild "Building StringHolderImpl", StringHolderImpl
+
+ // This test should go further and verify that injections into StringHolderImpl work.
+
+ then:
+
+ holder.class == StringHolderImpl
+ }
+
+ def "verify exception when autobuild service implementation is not valid"() {
+ buildRegistry ServiceBuilderAutobuilderModule
+
+ def pingable = getService Pingable
+
+ when:
+
+ pingable.ping()
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message.contains "Class org.apache.tapestry5.ioc.UnbuildablePingable does not contain a public constructor needed to autobuild."
+ }
+
+ def "verify exception when autobuild class has not valid constructor"() {
+ buildRegistry()
+
+ when:
+
+ autobuild UnbuildablePingable
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message.contains "Class org.apache.tapestry5.ioc.UnbuildablePingable does not contain a public constructor needed to autobuild."
+ }
+
+ def "a service build method may include a parameter with @Autobuild"() {
+ buildRegistry AutobuildInjectionModule
+
+ when:
+
+ def tx = getService StringTransformer
+
+ then:
+
+ tx.transform('Hello, ${fred}') == "Hello, flintstone"
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/BaseLocatableSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/BaseLocatableSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/BaseLocatableSpec.groovy
new file mode 100644
index 0000000..d54463c
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/BaseLocatableSpec.groovy
@@ -0,0 +1,36 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.BaseLocatable
+import org.apache.tapestry5.ioc.Locatable
+import org.apache.tapestry5.ioc.Location
+import spock.lang.Specification
+
+class LocatableFixture extends BaseLocatable {
+
+ LocatableFixture(Location location) {
+ super(location)
+ }
+}
+
+class BaseLocatableSpec extends Specification {
+
+ def "location property is readable"() {
+ Location location = Mock()
+
+ Locatable locatable = new LocatableFixture(location)
+
+ expect:
+
+ locatable.location.is location
+ }
+
+ def "location may be null"() {
+ Locatable locatable = new LocatableFixture(null);
+
+
+ expect:
+
+ locatable.location == null
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy
new file mode 100644
index 0000000..402d3a9
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy
@@ -0,0 +1,169 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory
+import org.slf4j.Logger
+import spock.lang.Shared
+import org.apache.tapestry5.ioc.internal.services.*
+
+class BridgeBuilderSpec extends AbstractSharedRegistrySpecification {
+
+ @Shared
+ PlasticProxyFactory proxyFactory;
+
+ def setupSpec() {
+ proxyFactory = getService PlasticProxyFactory
+ }
+
+ def "toString() of proxy is as expected"() {
+ Logger logger = Mock()
+ StandardFilter sf = Mock()
+ StandardService ss = Mock()
+
+ BridgeBuilder builder = new BridgeBuilder(logger, StandardService, StandardFilter, proxyFactory)
+
+ when:
+
+ def bridge = builder.instantiateBridge(ss, sf)
+
+ then:
+
+ bridge.toString() == "<PipelineBridge from org.apache.tapestry5.ioc.internal.services.StandardService to org.apache.tapestry5.ioc.internal.services.StandardFilter>"
+ }
+
+ def "standard service and interface"() {
+ Logger logger = Mock()
+ StandardFilter sf = Mock()
+ StandardService ss = Mock()
+
+ BridgeBuilder builder = new BridgeBuilder(logger, StandardService, StandardFilter, proxyFactory)
+ def bridge = builder.instantiateBridge(ss, sf)
+
+ when:
+
+ assert bridge.run(5) == 18
+
+ // 18 = 3 * (5 + 1)
+ // so the filter runs first, and passes 6 to the service
+ // seems there's an issue in Spock with chaining mocks this way
+
+ then:
+
+ 1 * sf.run(_, _) >> { i, service -> service.run(i + 1) }
+
+ 1 * ss.run(_) >> { i -> 3 * i }
+
+ 0 * _
+ }
+
+ def "when toString() is part of service interface, it is forwarded through the filter"() {
+ Logger logger = Mock()
+
+ ToStringService service = new ToStringService() {
+
+ String toString() { "Service" }
+ }
+
+ ToStringFilter filter = new ToStringFilter() {
+
+ String toString(ToStringService s) {
+ s.toString().toUpperCase()
+ }
+ }
+
+ BridgeBuilder builder = new BridgeBuilder(logger, ToStringService, ToStringFilter, proxyFactory)
+
+ when:
+
+ ToStringService bridge = builder.instantiateBridge(service, filter)
+
+ then:
+
+ bridge.toString() == "SERVICE"
+ }
+
+ def "unmatched service interface method is logged and exception thrown"() {
+ Logger logger = Mock()
+ ExtraServiceMethod next = Mock()
+ Serializable filter = Mock()
+
+ BridgeBuilder builder = new BridgeBuilder(logger, ExtraServiceMethod, Serializable, proxyFactory)
+
+ when:
+
+ ExtraServiceMethod esm = builder.instantiateBridge(next, filter)
+
+ then:
+
+ 1 * logger.error("Method void extraServiceMethod() has no match in filter interface java.io.Serializable.")
+
+ when:
+
+ esm.extraServiceMethod()
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message == "Method void extraServiceMethod() has no match in filter interface java.io.Serializable."
+ }
+
+ def "extra methods in filter interface are logged and ignored"() {
+ Logger logger = Mock()
+ Serializable next = Mock()
+ ExtraFilterMethod filter = Mock()
+
+ BridgeBuilder builder = new BridgeBuilder(logger, Serializable, ExtraFilterMethod, proxyFactory)
+
+ when:
+
+ assert builder.instantiateBridge(next, filter) != null
+
+ then:
+
+ 1 * logger.error("Method void extraFilterMethod() of filter interface org.apache.tapestry5.ioc.internal.services.ExtraFilterMethod does not have a matching method in java.io.Serializable.")
+
+ 0 * _
+ }
+
+ def "the service parameter may be a middle parameter of the filter method"() {
+ Logger logger = Mock()
+
+ MiddleFilter mf = new MiddleFilter() {
+
+ @Override
+ void execute(int count, char ch, MiddleService service, StringBuilder buffer) {
+ service.execute(count, ch, buffer)
+
+ buffer.append(' ')
+
+ service.execute(count + 1, Character.toUpperCase(ch), buffer)
+ }
+ }
+
+ MiddleService ms = new MiddleService() {
+
+ @Override
+ void execute(int count, char ch, StringBuilder buffer) {
+ count.times() { buffer.append ch }
+ }
+ }
+
+ BridgeBuilder builder = new BridgeBuilder(logger, MiddleService, MiddleFilter, proxyFactory)
+
+
+ MiddleService bridge = builder.instantiateBridge(ms, mf)
+
+ StringBuilder buffer = new StringBuilder("CODE: ")
+
+ when:
+
+
+ bridge.execute(3, 'a' as char, buffer)
+
+ then:
+
+ buffer.toString() == "CODE: aaa AAAA"
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/CaseInsensitiveMapSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/CaseInsensitiveMapSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/CaseInsensitiveMapSpec.groovy
new file mode 100644
index 0000000..c4e43f0
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/CaseInsensitiveMapSpec.groovy
@@ -0,0 +1,303 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.util.CaseInsensitiveMap
+import spock.lang.Specification
+
+class CaseInsensitiveMapSpec extends Specification {
+
+ CaseInsensitiveMap map = new CaseInsensitiveMap([fred: "flintstone", barney: "rubble", wilma: "flinstone", betty: "rubble"])
+
+ def "get() is case insensitive"() {
+ def map = new CaseInsensitiveMap()
+
+ def value = "flintstone"
+
+ when:
+
+ map.put("fred", value)
+
+ then:
+
+ map.get("fred").is(value)
+ map.get("Fred").is(value)
+ }
+
+ def "containsKey() is case insensitive"() {
+
+ expect:
+
+ map.containsKey("fred")
+ map.containsKey("Fred")
+ map.containsKey("barney")
+ map.containsKey("wilma")
+ !map.containsKey("dino")
+ }
+
+ def "remove() is case insensitive"() {
+ expect:
+
+ map.containsKey("fred")
+ !map.isEmpty()
+
+ when:
+
+ map.remove("FrED")
+
+ then:
+
+ map.keySet() == ["barney", "wilma", "betty"] as Set
+ }
+
+ def "copying Map constructor"() {
+ def standard = [fred: "flintstone", barney: "rubble", wilma: "flintstone"]
+
+ when:
+
+ def original = new CaseInsensitiveMap(standard)
+
+ then:
+
+ original == standard
+
+ when:
+
+ def copy = new CaseInsensitiveMap(original)
+
+ then:
+
+ copy == original
+ }
+
+ def "comparison of two CaseInsensitiveMaps ignores case"() {
+ def lower = new CaseInsensitiveMap([fred: "flintstone", barney: "rubble"])
+ def upper = new CaseInsensitiveMap([Fred: "flintstone", Barney: "rubble"])
+
+ expect:
+
+ upper == lower
+ }
+
+ def "put with different case replaces the old key"() {
+
+ expect:
+
+ map.keySet() == ["fred", "barney", "betty", "wilma"] as Set
+
+
+ when:
+
+ map.put("FRED", "flintstone")
+
+ then:
+
+ map.keySet() == ["FRED", "barney", "betty", "wilma"] as Set
+ }
+
+ def "get with missing key is null"() {
+ expect:
+
+ map.notFound == null
+ }
+
+ def "get with non-string key is null"() {
+ expect:
+
+ map.get(this) == null
+ }
+
+ def "expansion of the internal entry array"() {
+
+ def count = 2000
+
+ def map = new CaseInsensitiveMap()
+
+ count.times { it ->
+ assert map.put("key_$it" as String, it) == null
+ }
+
+ when:
+
+ count.times { it ->
+ assert map.get("key_$it" as String) == it
+ }
+
+ then:
+
+ map.size() == count
+ map.entrySet().size() == count
+
+ when:
+
+ map.clear()
+
+ then:
+
+ map.size() == 0
+
+ }
+
+ def "change value via entrySet()"() {
+ def map = new CaseInsensitiveMap()
+
+ map.put("fred", "flintstone")
+
+ when:
+
+ map.entrySet().each { entry -> entry.value = "murray" }
+
+ then:
+
+ map.get("fred") == "murray"
+ }
+
+ def "entrySet iterator fails fast after remove"() {
+
+ def i = map.entrySet().iterator()
+
+ i.next()
+ map.remove("betty")
+
+ when:
+
+ i.next()
+
+ then:
+
+ thrown(ConcurrentModificationException)
+ }
+
+ def "entrySet iterator fails fast after put"() {
+
+ def i = map.entrySet().iterator()
+
+ i.next()
+ map.put("zaphod", "breeblebrox")
+
+ when:
+
+ i.next()
+
+ then:
+
+ thrown(ConcurrentModificationException)
+ }
+
+ def "iterator may remove without concurrent exception"() {
+
+ def i = map.entrySet().iterator()
+
+ while (i.hasNext()) {
+ if (i.next().key == "wilma") { i.remove() }
+ }
+
+ expect:
+
+ map.keySet() == ["barney", "betty", "fred"] as Set
+ }
+
+ def "contains via entrySet"() {
+
+ def set = map.entrySet()
+
+ expect:
+
+ set.contains(newMapEntry("fred", "flintstone"))
+ set.contains(newMapEntry("Fred", "flintstone"))
+
+ !set.contains(newMapEntry("Zaphod", "Breeblebox"))
+ !set.contains(newMapEntry("fred", "murray"))
+ }
+
+ def "remove via entrySet"() {
+
+ def set = map.entrySet()
+
+ when:
+
+ assert set.remove(newMapEntry("Zaphod", "Breeblrox")) == false
+ assert set.remove(newMapEntry("fred", "murray")) == false
+
+ assert set.remove(newMapEntry("fred", "flintstone")) == true
+
+ then:
+
+ map.keySet() == ["barney", "wilma", "betty"] as Set
+ }
+
+ def newMapEntry(key, value) {
+ return new Map.Entry() {
+
+ @Override
+ Object getKey() {
+ return key
+ }
+
+ @Override
+ Object getValue() {
+ return value;
+ }
+
+ @Override
+ Object setValue(Object newValue) {
+ value = newValue
+ }
+ }
+ }
+
+ def "null is a valid key"() {
+ when:
+
+ map.put(null, "NULL")
+
+ then:
+
+ map.get(null) == "NULL"
+ }
+
+ def "clearing the entrySet clears the map"() {
+ expect:
+
+ !map.isEmpty()
+ !map.entrySet().isEmpty()
+
+ when:
+
+ map.entrySet().clear()
+
+ then:
+
+ map.isEmpty()
+ }
+
+ def "next() after last entry in entrySet is a failure"() {
+ Iterator i = map.entrySet().iterator()
+
+ while (i.hasNext()) { i.next() }
+
+ when:
+
+ i.next()
+
+ then:
+
+ thrown(NoSuchElementException)
+ }
+
+ def "serialize/deserialize copies all data"() {
+
+ def baos = new ByteArrayOutputStream()
+ def oos = new ObjectOutputStream(baos)
+
+ oos.writeObject(map)
+ oos.close()
+
+ def bais = new ByteArrayInputStream(baos.toByteArray())
+ ObjectInputStream ois = new ObjectInputStream(bais)
+
+ def copy = ois.readObject()
+
+ expect:
+
+ copy == map
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/ChainBuilderImplSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ChainBuilderImplSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ChainBuilderImplSpec.groovy
new file mode 100644
index 0000000..7638df0
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ChainBuilderImplSpec.groovy
@@ -0,0 +1,121 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.services.ChainBuilder
+
+interface ChainCommand {
+
+ void run();
+
+ int workInt(int input);
+
+ boolean workBoolean(boolean input);
+
+ double workDouble(double input);
+
+ String workString(String input);
+}
+
+class ChainBuilderImplSpec extends AbstractSharedRegistrySpecification {
+
+ ChainCommand c1 = Mock()
+ ChainCommand c2 = Mock()
+
+ ChainCommand chain = getService(ChainBuilder).build(ChainCommand, [c1, c2])
+
+ def "chaining of simple void method with no parameters"() {
+ when:
+
+ chain.run()
+
+ then:
+
+ 1 * c1.run()
+
+ then:
+
+ 1 * c2.run()
+ 0 * _
+ }
+
+ def "chaining of method with int parameter and return type"() {
+
+ when:
+
+ assert chain.workInt(7) == 99
+
+ then:
+
+ 1 * c1.workInt(7) >> 0
+
+ then:
+
+ 1 * c2.workInt(7) >> 99
+ 0 * _
+ }
+
+ def "verify that an int method that returns a non-zero value short-circuits the chain"() {
+ when:
+
+ assert chain.workInt(7) == 88
+
+ then:
+
+ 1 * c1.workInt(7) >> 88
+ 0 * _
+ }
+
+ def "verify boolean parameters, return type, and short circuiting"() {
+
+ when:
+
+ assert chain.workBoolean(true) == true
+
+ then:
+
+ 1 * c1.workBoolean(true) >> false
+
+ then:
+
+ 1 * c2.workBoolean(true) >> true
+ 0 * _
+ }
+
+ def "verify string method parameter, return type, and short circuiting"() {
+ when:
+
+ assert chain.workString("fred") == "flintstone"
+
+ then:
+
+ 1 * c1.workString("fred") >> null
+
+ then:
+
+ 1 * c2.workString("fred") >> "flintstone"
+ 0 * _
+ }
+
+ def "verify double method parameter, return type, and short circuiting"() {
+
+ when:
+
+ assert chain.workDouble(1.2d) == 3.14d
+
+ then:
+
+ 1 * c1.workDouble(1.2d) >> 0d
+
+ then:
+
+ 1 * c2.workDouble(1.2d) >> 3.14d
+ 0 * _
+ }
+
+ def "chain instance has reasonable toString()"() {
+ expect:
+
+ chain.toString() == "<Command chain of ioc.specs.ChainCommand>"
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/ClassNameLocatorImplSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ClassNameLocatorImplSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ClassNameLocatorImplSpec.groovy
new file mode 100644
index 0000000..106cb29
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ClassNameLocatorImplSpec.groovy
@@ -0,0 +1,76 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.internal.services.ClassNameLocatorImpl
+import org.apache.tapestry5.ioc.internal.services.ClasspathURLConverterImpl
+import org.apache.tapestry5.ioc.services.ClassNameLocator
+import spock.lang.Specification
+
+class ClassNameLocatorImplSpec extends Specification {
+
+ ClassNameLocator locator = new ClassNameLocatorImpl(new ClasspathURLConverterImpl());
+
+ def assertInList(classNames, packageName, String... expectedNames) {
+
+ expectedNames.each { name ->
+ String qualifiedName = "${packageName}.${name}"
+
+ assert classNames.contains(qualifiedName), "[$qualifiedName] not present in ${classNames.join(', ')}."
+ }
+ }
+
+ def assertNotInList(classNames, packageName, String... expectedNames) {
+
+ expectedNames.each { name ->
+ String qualifiedName = "${packageName}.${name}"
+
+ assert !classNames.contains(qualifiedName), "[$qualifiedName] should not be present in ${classNames.join(', ')}."
+ }
+ }
+
+ def "locate classes inside a JAR file on the classpath"() {
+
+ expect:
+
+ assertInList locator.locateClassNames("javax.inject"),
+ "javax.inject",
+ "Inject", "Named", "Singleton"
+ }
+
+ def "can locate classes inside a subpackage, inside a classpath JAR file"() {
+
+ expect:
+
+ assertInList locator.locateClassNames("org.slf4j"),
+ "org.slf4j",
+ "spi.MDCAdapter"
+ }
+
+ def "can locate classes in local folder, but exclude inner classes"() {
+
+ def packageName = "org.apache.tapestry5.ioc.services"
+
+ when:
+
+ def names = locator.locateClassNames packageName
+
+ then:
+
+ assertInList names, packageName, "SymbolSource", "TapestryIOCModule"
+
+ assertNotInList names, packageName, 'TapestryIOCMOdules$1'
+ }
+
+ def "can locate classes in subpackage of local folders"() {
+ def packageName = "org.apache.tapestry5"
+
+ when:
+
+ def names = locator.locateClassNames packageName
+
+ then:
+
+ assertInList names, packageName, "ioc.Orderable", "ioc.services.ChainBuilder"
+ assertNotInList names, packageName, 'services.TapestryIOCModule$1'
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSymbolProviderSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSymbolProviderSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSymbolProviderSpec.groovy
new file mode 100644
index 0000000..08b9cc1
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSymbolProviderSpec.groovy
@@ -0,0 +1,31 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.internal.services.ClasspathResourceSymbolProvider
+import spock.lang.Shared
+import spock.lang.Specification
+
+class ClasspathResourceSymbolProviderSpec extends Specification {
+
+ static final String PATH = "org/apache/tapestry5/ioc/internal/services/foo.properties"
+
+ @Shared
+ def provider = new ClasspathResourceSymbolProvider(PATH)
+
+ def "access properties"() {
+
+ expect:
+ provider.valueForSymbol("homer") == "simpson"
+ provider.valueForSymbol("monty") == "burns"
+ }
+
+ def "keys are case insensitive"() {
+ expect:
+ provider.valueForSymbol("HOMER") == "simpson"
+ }
+
+ def "non-existent keys should return null"() {
+ expect:
+ provider.valueForSymbol("marge") == null
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/ConcurrentBarrierSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ConcurrentBarrierSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ConcurrentBarrierSpec.groovy
new file mode 100644
index 0000000..e1e571d
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ConcurrentBarrierSpec.groovy
@@ -0,0 +1,146 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.internal.util.ConcurrentTarget
+import org.apache.tapestry5.ioc.internal.util.ConcurrentTargetWrapper
+import spock.lang.Specification
+
+class ConcurrentBarrierSpec extends Specification {
+
+ def target = new ConcurrentTarget()
+
+ static final int THREAD_COUNT = 1000
+
+ static final int THREAD_BLOCK_SIZE = 50
+
+ def run(op) {
+ def threads = []
+ def running = []
+
+ assert target.counter == 0
+
+ THREAD_COUNT.times {
+ def t = new Thread(op)
+
+ threads << t
+
+ if (threads.size() >= THREAD_BLOCK_SIZE) {
+ threads.each { it.start() }
+ running.addAll threads
+ threads.clear()
+ }
+ }
+
+ running.each { it.join() }
+ }
+
+ def "acquire write lock"() {
+
+ when:
+
+ run { target.incrementCounter() }
+
+ then:
+
+ target.counter == THREAD_COUNT
+ }
+
+ def "acquire read lock while holding write lock"() {
+
+ when:
+
+ run { target.incrementCounterHard() }
+
+ then:
+
+ target.counter == THREAD_COUNT
+ }
+
+ def "upgrade read lock to write lock"() {
+ when:
+
+ run { target.incrementIfNonNegative() }
+
+ then:
+
+ target.counter == THREAD_COUNT
+ }
+
+ def "indirection between method with read lock and method that acquires write lock"() {
+
+ when:
+
+ run { target.incrementViaRunnable() }
+
+ then:
+
+ target.counter == THREAD_COUNT
+ }
+
+ def "barriers are independent when multiple are involved"() {
+
+ when:
+
+ run(new ConcurrentTargetWrapper(target))
+
+ then:
+
+ target.counter == THREAD_COUNT
+ }
+
+ def "use tryWithWrite() to get write lock if it is available"() {
+
+ when: run {
+ def good = false
+ while (!good) { good = target.tryIncrementCounter() }
+ }
+
+ then:
+
+ target.counter == THREAD_COUNT
+ }
+
+ def "acquire read lock when inside a tryWithWrite block"() {
+
+ when:
+
+ run {
+ def good = false
+ while (!good) { good = target.tryIncrementCounterHard() }
+ }
+
+ then:
+
+ target.counter == THREAD_COUNT
+ }
+
+ def "read lock upgrades via tryWriteLock()"() {
+
+ when:
+
+ run {
+ def good = false
+ while (!good) { good = target.tryIncrementIfNonNegative() }
+ }
+
+ then:
+
+ target.counter == THREAD_COUNT
+ }
+
+ def "write lock timeout inside read lock"() {
+ when:
+
+ target.withRead {
+ try {
+ run {
+ assert target.tryIncrementIfNonNegative() == false
+ }
+ }
+ catch (InterruptedException e) { }
+ }
+
+ then:
+
+ target.counter == 0
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/ConfigurationsSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ConfigurationsSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ConfigurationsSpec.groovy
new file mode 100644
index 0000000..0594606
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ConfigurationsSpec.groovy
@@ -0,0 +1,317 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.internal.AlphabetModule
+import org.apache.tapestry5.ioc.internal.AlphabetModule2
+import org.apache.tapestry5.ioc.services.SymbolSource
+import org.apache.tapestry5.ioc.util.NonmatchingMappedConfigurationOverrideModule
+import org.apache.tapestry5.ioc.*
+
+/** Integration tests for various types of service configurations. */
+class ConfigurationsSpec extends AbstractRegistrySpecification {
+
+ def "all contributions to unordered configuration are collected"() {
+
+ buildRegistry FredModule, BarneyModule
+
+ when:
+
+ def holder = getService "UnorderedNames", NameListHolder
+
+ then:
+
+ // We don't know the actual contribution order, the impl sorts them. Just
+ // check they are all present.
+
+ holder.names == ["Beta", "Gamma", "UnorderedNames"]
+ }
+
+ def "all contributions to order configuration are collected"() {
+ buildRegistry FredModule, BarneyModule
+
+ when:
+
+ def holder = getService "OrderedNames", NameListHolder
+
+ then:
+
+ holder.names == ["BARNEY", "FRED"]
+ }
+
+ def "all contribution to mapped configuration are collected"() {
+
+ buildRegistry FredModule, BarneyModule
+
+ def sizer = getService "Sizer", Sizer
+
+ expect:
+
+ // The contributions map different Classes to strategies; this demonstrates
+ // that all contributions have been mapped and provided to Sizer service impl.
+
+ sizer.size(null) == 0
+
+ sizer.size([1, 2, 3]) == 3
+
+ sizer.size([fred: "flintstone", barney: "rubble"]) == 2
+
+ sizer.size(this) == 1
+ }
+
+ def "can contribute a class to an unordered configuration"() {
+ buildRegistry ContributeByClassModule
+
+ when:
+
+ def tx = getService "MasterStringTransformer", StringTransformer
+
+ then:
+
+ tx.transform("Tapestry") == "TAPESTRY"
+ }
+
+ def "can contribute a class to an ordered configuration"() {
+ buildRegistry ContributeByClassModule
+
+ when:
+
+ def tx = getService "StringTransformerChain", StringTransformer
+
+ then:
+
+ tx.transform("Tapestry") == "TAPESTRY"
+ }
+
+ def "can contribute class to a mapped configuration"() {
+ buildRegistry ContributeByClassModule
+
+ when:
+
+ def tx = getService "MappedStringTransformer", StringTransformer
+
+ then:
+
+ tx.transform("Tapestry") == "TAPESTRY"
+ }
+
+ def "contribution to an unknown configuration is detected as an exception"() {
+ when:
+ buildRegistry InvalidContributeDefModule
+ then:
+ IllegalArgumentException e = thrown()
+
+ e.message.contains "Contribution org.apache.tapestry5.ioc.InvalidContributeDefModule.contributeDoesNotExist(Configuration)"
+ e.message.contains "is for service 'DoesNotExist', which does not exist."
+ }
+
+ def "a value in an ordered configuration may be overridden"() {
+ buildRegistry FredModule, BarneyModule, ConfigurationOverrideModule
+
+ when:
+
+ def holder = getService "OrderedNames", NameListHolder
+
+ then:
+
+ holder.names == ["BARNEY", "WILMA", "Mr. Flintstone"]
+ }
+
+ def "an override value in an ordered configuration must match a normally contributed value"() {
+ buildRegistry FredModule, BarneyModule, FailedConfigurationOverrideModule
+
+ def holder = getService "OrderedNames", NameListHolder
+
+ when:
+
+
+ holder.names
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message.contains "Failure processing override from org.apache.tapestry5.ioc.FailedConfigurationOverrideModule.contributeOrderedNames(OrderedConfiguration)"
+ e.message.contains "Override for object 'wilma' is invalid as it does not match an existing object."
+ }
+
+ def "a contribution to an ordered configuration may only be overridden once"() {
+ buildRegistry FredModule, BarneyModule, ConfigurationOverrideModule, DuplicateConfigurationOverrideModule
+
+ def holder = getService "OrderedNames", NameListHolder
+
+ when:
+
+
+ holder.names
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message.contains "Error invoking service contribution method"
+ e.message.contains "Contribution 'fred' has already been overridden"
+ }
+
+ def "contributions to mapped configurations may be overridden"() {
+ buildRegistry FredModule, BarneyModule, ConfigurationOverrideModule
+
+ when:
+
+ def sl = getService StringLookup
+
+ then:
+
+ sl.keys() == ["barney", "betty", "fred"]
+ sl.lookup("fred") == "Mr. Flintstone"
+ }
+
+ def "mapped configuration overrides must match an existing value"() {
+ buildRegistry FredModule, BarneyModule, NonmatchingMappedConfigurationOverrideModule
+
+ def sl = getService StringLookup
+
+ when:
+
+ sl.keys()
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message.contains "Override for key alley cat (at org.apache.tapestry5.ioc.util.NonmatchingMappedConfigurationOverrideModule.contributeStringLookup(MappedConfiguration)"
+ e.message.contains "does not match an existing key"
+ }
+
+ def "a contribution to a mapped configuration may only be overridden once"() {
+ buildRegistry FredModule, BarneyModule, ConfigurationOverrideModule, DuplicateConfigurationOverrideModule
+
+ def sl = getService StringLookup
+
+ when:
+
+ sl.keys()
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message.contains "Error invoking service contribution method"
+ e.message.contains "Contribution key fred has already been overridden"
+ }
+
+ def "support for @Contribute annotation"() {
+
+ buildRegistry AlphabetModule, AlphabetModule2
+
+ when:
+
+ def greek = getService "Greek", NameListHolder
+
+ then:
+
+ greek.names == ["Alpha", "Beta", "Gamma", "Delta"]
+
+ when:
+
+ def anotherGreek = getService "AnotherGreek", NameListHolder
+
+ then:
+
+ anotherGreek.names == ["Alpha", "Beta", "Gamma", "Delta", "Epsilon"]
+
+ when:
+
+ def hebrew = getService "Hebrew", NameListHolder
+
+ then:
+
+ hebrew.names == ["Alef", "Bet", "Gimel", "Dalet", "He", "Vav"]
+
+ when:
+
+ def holder = getService "ServiceWithEmptyConfiguration", NameListHolder2
+
+ then:
+
+ holder.names.empty
+ }
+
+ def "contribute by @Contribute annotation to non-existent service"() {
+ when:
+
+ buildRegistry InvalidContributeDefModule2
+
+ then:
+
+ RuntimeException e = thrown()
+
+ ["Contribution org.apache.tapestry5.ioc.InvalidContributeDefModule2.provideConfiguration(OrderedConfiguration)",
+ "is for service 'interface org.apache.tapestry5.ioc.NameListHolder'",
+ "qualified with marker annotations [",
+ "interface org.apache.tapestry5.ioc.BlueMarker",
+ "interface org.apache.tapestry5.ioc.RedMarker",
+ "], which does not exist."].every { e.message.contains it}
+ }
+
+ def "contribute using @Contribute using invalid marker annotation is an exception"() {
+ when:
+ buildRegistry InvalidContributeDefModule3
+ then:
+ RuntimeException e = thrown()
+
+ ["Contribution org.apache.tapestry5.ioc.InvalidContributeDefModule3.provideConfiguration(OrderedConfiguration)",
+ "is for service 'interface org.apache.tapestry5.ioc.NameListHolder'",
+ "qualified with marker annotations [interface org.apache.tapestry5.ioc.BlueMarker], which does not exist."].every
+ { e.message.contains it}
+ }
+
+ def "ServiceResources are available to contribution methods"() {
+ buildRegistry InjectionCheckModule
+
+ when:
+
+ def s = getService InjectionCheck
+ def il = s.getValue "indirect-resources"
+
+ then:
+
+ s.logger.is(s.getValue("logger"))
+
+ s.logger.is il.logger
+ s.logger.is il.resources.logger
+ }
+
+
+ def "service id in contribute method is matched caselessly"() {
+ buildRegistry CaseInsensitiveContributeMethodModule
+
+ when:
+
+ def ss = getService SymbolSource
+
+ then:
+
+ ss.valueForSymbol("it") == "works"
+ }
+
+ def "contributed values may be coerced to the correct type"() {
+ buildRegistry ContributedValueCoercionModule
+
+ when:
+
+ def ss = getService SymbolSource
+
+ then:
+
+ ss.valueForSymbol("bool-true") == "true"
+ ss.valueForSymbol("bool-false") == "false"
+ ss.valueForSymbol("num-12345") == "12345"
+ }
+
+ def "@Optional contribution to an unknown service is not an error"() {
+ when:
+ buildRegistry OptionalContributionModule
+
+ then:
+ noExceptionThrown()
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy
new file mode 100644
index 0000000..e85c516
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy
@@ -0,0 +1,209 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.annotations.InjectService
+import org.apache.tapestry5.ioc.internal.ContributionDefImpl
+import org.apache.tapestry5.ioc.internal.QuietOperationTracker
+import org.apache.tapestry5.ioc.internal.UpcaseService
+import org.slf4j.Logger
+import spock.lang.Shared
+import spock.lang.Specification
+
+import java.lang.reflect.Method
+import javax.inject.Named
+
+import org.apache.tapestry5.ioc.*
+
+class ModuleFixture {
+
+ void contributeUnordered(Configuration configuration) {
+ configuration.add(ContributionDefImplSpec.toContribute);
+ }
+
+ void contributeUnorderedInjectedService(Configuration<UpcaseService> configuration,
+ @InjectService("Zap")
+ UpcaseService service) {
+ configuration.add(service);
+ }
+
+ void contributeUnorderedParameterNamedService(Configuration<UpcaseService> configuration,
+ @Named("Zap")
+ UpcaseService service) {
+ configuration.add(service);
+ }
+
+ void contributeUnorderedWrongParameter(MappedConfiguration configuration) {
+ throw new IllegalStateException("Unreachable.")
+ }
+
+ void contributeOrderedParameterInjectedService(OrderedConfiguration<UpcaseService> configuration,
+ @InjectService("Zap")
+ UpcaseService service) {
+ configuration.add("fred", service);
+ }
+
+ void contributeMappedParameterInjectedService(MappedConfiguration<String, UpcaseService> configuration,
+ @InjectService("Zap")
+ UpcaseService service) {
+ configuration.add("upcase", service);
+ }
+}
+
+
+class ContributionDefImplSpec extends Specification {
+
+ static Object toContribute
+
+ @Shared
+ OperationTracker tracker = new QuietOperationTracker()
+
+ ServiceResources resources = Mock()
+ Logger logger = Mock()
+
+ @Shared
+ ModuleBuilderSource source = new ModuleBuilderSource() {
+
+ @Override
+ Object getModuleBuilder() {
+ return new ModuleFixture()
+ }
+ }
+
+ private Method findMethod(name) {
+ return ModuleFixture.methods.find { it.name == name }
+ }
+
+ def createContributionDef(methodName) {
+ return new ContributionDefImpl("Foo", findMethod(methodName), false, null, null, null)
+ }
+
+ def "contribute to an unordered collection"() {
+
+ Configuration configuration = Mock()
+
+ toContribute = new Object()
+
+ def cd = createContributionDef "contributeUnordered"
+
+ when:
+
+ cd.contribute(source, resources, configuration)
+
+ then:
+
+ 1 * resources.logger >> logger
+ _ * resources.serviceId >> "Foo"
+ 1 * configuration.add(toContribute)
+ _ * resources.tracker >> tracker
+
+ 0 * _
+ }
+
+ def "unordered configuration injects and contributes a service via @InjectService"() {
+
+ Configuration configuration = Mock()
+ UpcaseService service = Mock()
+
+ def cd = createContributionDef "contributeUnorderedInjectedService"
+
+ when:
+
+ cd.contribute(source, resources, configuration)
+
+ then:
+
+ 1 * resources.getService("Zap", UpcaseService) >> service
+
+ 1 * resources.logger >> logger
+ _ * resources.serviceId >> "Foo"
+ 1 * configuration.add(service)
+ _ * resources.tracker >> tracker
+
+ 0 * _
+ }
+
+ def "unordered configuration injects and contributes a service via @Named"() {
+ Configuration configuration = Mock()
+ UpcaseService service = Mock()
+
+ def cd = createContributionDef "contributeUnorderedParameterNamedService"
+
+ when:
+
+ cd.contribute(source, resources, configuration)
+
+ then:
+
+ 1 * resources.getService("Zap", UpcaseService) >> service
+
+ 1 * resources.logger >> logger
+ _ * resources.serviceId >> "Foo"
+ 1 * configuration.add(service)
+ _ * resources.tracker >> tracker
+
+ }
+
+ def "contribution method configuration parameter must be correct type"() {
+ Configuration configuration = Mock()
+
+ def cd = createContributionDef "contributeUnorderedWrongParameter"
+
+ when:
+
+ cd.contribute(source, resources, configuration)
+
+ then:
+
+ _ * resources.logger >> logger
+ _ * resources.serviceId >> "Foo"
+ _ * resources.tracker >> tracker
+
+ RuntimeException e = thrown()
+
+ e.message.contains "Service 'Foo' is configured using org.apache.tapestry5.ioc.Configuration, not org.apache.tapestry5.ioc.MappedConfiguration."
+ }
+
+ def "ordered configuration injects and contributes a service via @InjectService"() {
+
+ OrderedConfiguration configuration = Mock()
+ UpcaseService service = Mock()
+
+ def cd = createContributionDef "contributeOrderedParameterInjectedService"
+
+ when:
+
+ cd.contribute(source, resources, configuration)
+
+ then:
+
+ 1 * configuration.add("fred", service)
+
+ _ * resources.getService("Zap", UpcaseService) >> service
+
+ _ * resources.logger >> logger
+ _ * resources.serviceId >> "Foo"
+ _ * resources.tracker >> tracker
+ }
+
+ def "mapped configuration injects and contributes a service via @InjectService"() {
+ MappedConfiguration configuration = Mock()
+ UpcaseService service = Mock()
+
+ def cd = createContributionDef "contributeMappedParameterInjectedService"
+
+ when:
+
+ cd.contribute(source, resources, configuration)
+
+ then:
+
+ 1 * configuration.add("upcase", service)
+
+ _ * resources.getService("Zap", UpcaseService) >> service
+
+ _ * resources.logger >> logger
+ _ * resources.serviceId >> "Foo"
+ _ * resources.tracker >> tracker
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/CronExpressionSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/CronExpressionSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/CronExpressionSpec.groovy
new file mode 100644
index 0000000..58bef3e
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/CronExpressionSpec.groovy
@@ -0,0 +1,104 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.internal.services.cron.CronExpression
+import spock.lang.Ignore
+import spock.lang.Specification
+import spock.lang.Unroll
+
+import java.text.ParseException
+
+@Unroll
+class CronExpressionSpec extends Specification {
+
+ // This allows the any of the constants defined on Calendar to be used
+ // without qualification.
+ def propertyMissing(String name) { Calendar[name] }
+
+ def "isSatisfiedBy(#year, #month, #day, #hour, #minute, #second ) should be #satisfied for expression '#expr'"() {
+
+ def cal = Calendar.getInstance();
+
+ def exp = new CronExpression(expr)
+
+ cal.set year, month, day, hour, minute, second
+
+ expect:
+
+ exp.isSatisfiedBy(cal.time) == satisfied
+
+ where:
+ expr | year | month | day | hour | minute | second | satisfied
+ "0 15 10 * * ? 2005" | 2005 | JUNE | 1 | 10 | 15 | 0 | true
+ "0 15 10 * * ? 2005" | 2006 | JUNE | 1 | 10 | 15 | 0 | false
+ "0 15 10 * * ? 2005" | 2005 | JUNE | 1 | 10 | 16 | 0 | false
+ "0 15 10 * * ? 2005" | 2005 | JUNE | 1 | 10 | 14 | 0 | false
+ "0 15 10 L-2 * ? 2010" | 2010 | OCTOBER | 29 | 10 | 15 | 0 | true
+ "0 15 10 L-2 * ? 2010" | 2010 | OCTOBER | 28 | 10 | 15 | 0 | false
+ "0 15 10 L-5W * ? 2010" | 2010 | OCTOBER | 26 | 10 | 15 | 0 | true
+ "0 15 10 L-1 * ? 2010" | 2010 | OCTOBER | 30 | 10 | 15 | 0 | true
+ "0 15 10 L-1W * ? 2010" | 2010 | OCTOBER | 29 | 10 | 15 | 0 | true
+ }
+
+ def cloneViaSerialize(obj) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream()
+
+ baos.withObjectOutputStream { it.writeObject(obj) }
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray())
+ ObjectInputStream ois = new ObjectInputStream(bais)
+
+ ois.readObject()
+ }
+
+ // This test is in the original TestNG test but failed there (making me think that the test case was probably
+ // not being run). It's clear that CronExpressions do not deserialize correctly by looking at the source!
+ @Ignore
+ def "check that CronExpressions serialize and deserialize"() {
+
+ CronExpression original = new CronExpression("19 15 10 4 Apr ? ")
+
+ when:
+
+ CronExpression cloned = cloneViaSerialize original
+
+ then:
+
+ cloned.cronExpression == original.cronExpression
+ cloned.getNextValidTimeAfter(new Date()) != null
+ }
+
+ def "Parse failure: parse of '#expr' should fail with '#err'"() {
+
+ when:
+ new CronExpression(expr)
+
+ then:
+ def e = thrown(ParseException)
+
+ assert e.message.startsWith(err)
+
+ where:
+ expr | err
+ "* * * * Foo ? " | "Invalid Month value:"
+ "* * * * Jan-Foo ? " | "Invalid Month value:"
+ "0 0 * * * *" | "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented."
+ "0 0 * 4 * *" | "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented."
+ "0 0 * * * 4" | "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented."
+ "0 43 9 1,5,29,L * ?" | "Support for specifying 'L' and 'LW' with other days of the month is not implemented"
+ "0 43 9 ? * SAT,SUN,L" | "Support for specifying 'L' with other days of the week is not implemented"
+ "0 43 9 ? * 6,7,L" | "Support for specifying 'L' with other days of the week is not implemented"
+ "0/5 * * 32W 1 ?" | "The 'W' option does not make sense with values larger than"
+ }
+
+ def "Expression '#expr' is valid"() {
+ when:
+ new CronExpression(expr)
+
+ then:
+ noExceptionThrown()
+
+ where:
+ expr << ["0 43 9 ? * 5L"]
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/CronScheduleSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/CronScheduleSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/CronScheduleSpec.groovy
new file mode 100644
index 0000000..620fa89
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/CronScheduleSpec.groovy
@@ -0,0 +1,26 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.services.cron.CronSchedule
+import org.apache.tapestry5.ioc.services.cron.PeriodicExecutor
+
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+
+class CronScheduleSpec extends AbstractSharedRegistrySpecification {
+
+ def "add a job and ensure that it executes"() {
+ def latch = new CountDownLatch(5)
+
+ def executor = getService PeriodicExecutor
+
+ executor.addJob(new CronSchedule("0/1 * * * * ?"), "Test", { latch.countDown() })
+
+ when:
+
+ latch.await(30, TimeUnit.SECONDS)
+
+ then:
+
+ latch.count == 0
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/DecoratorsSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/DecoratorsSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/DecoratorsSpec.groovy
new file mode 100644
index 0000000..457988c
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/DecoratorsSpec.groovy
@@ -0,0 +1,110 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.internal.DecorateByMarkerModule
+import org.apache.tapestry5.ioc.internal.DecorateByMarkerModule2
+import org.apache.tapestry5.ioc.*
+
+/** Integration tests for service decorators and some related behaviors. */
+class DecoratorsSpec extends AbstractRegistrySpecification {
+
+ def "verify order of service decorators"() {
+ buildRegistry FredModule, BarneyModule
+
+ def fred = getService "Fred", Runnable
+ def list = getService DecoratorList
+
+ when:
+
+ fred.run()
+
+ then:
+
+ list.names == ["gamma", "beta", "alpha"]
+ }
+
+ def "decorators receive the delegate by the specific type"() {
+
+ buildRegistry GreeterModule, SpecificDecoratorModule
+
+ when:
+
+ def g = getService "HelloGreeter", Greeter
+
+ then:
+
+ g.greeting == "HELLO"
+ }
+
+ def "a service builder method with @PreventServiceDecoration is not decorated"() {
+ buildRegistry PreventDecorationModule
+
+ when:
+
+ def st = getService StringTransformer
+
+ then:
+
+ st.transform("tapestry") == "TAPESTRY"
+ }
+
+ def "Binding a service with explicit no decorations will ensure that the implementation is not decorated"() {
+ buildRegistry PreventDecorationModule
+
+ when:
+
+ def g = getService Greeter
+
+ then:
+
+ g.greeting == "Greetings from ServiceIdGreeter."
+ }
+
+ def "@PreventServiceDecoration on a service implementation class ensures that the implementation is not decorated"() {
+ buildRegistry PreventDecorationModule
+
+ when:
+
+ def rocket = getService Rocket
+
+ then:
+
+ rocket.countdown == "3, 2, 1, Launch!"
+ }
+
+ def "@Decorate marks a module method as a decorator method"() {
+ buildRegistry GreeterModule2, DecorateByMarkerModule
+
+ when:
+
+ def green = getService "GreenGreeter", Greeter
+
+ then:
+
+ green.greeting == "Decorated by foo[Decorated by baz[Decorated by bar[Green]]]"
+ }
+
+ def "@Decorate with @Local only decorates services from the same module"() {
+ buildRegistry GreeterModule2, DecorateByMarkerModule
+
+ when:
+
+ def red = getService "RedGreeter", Greeter
+
+ then:
+
+ red.greeting == "Decorated by barney[Red]"
+ }
+
+ def "@Decorate with id attribute"() {
+ buildRegistry DecorateByMarkerModule2
+
+ when:
+
+ def green = getService "RedGreeter", Greeter
+
+ then:
+
+ green.greeting == "Decorated by beta[Decorated by alpha[Red]]"
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/a1bef869/tapestry-ioc/src/test/groovy/ioc/specs/DefaultImplementationBuilderImplSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/DefaultImplementationBuilderImplSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/DefaultImplementationBuilderImplSpec.groovy
new file mode 100644
index 0000000..95d2a2e
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/DefaultImplementationBuilderImplSpec.groovy
@@ -0,0 +1,39 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.services.DefaultImplementationBuilder
+
+
+class DefaultImplementationBuilderImplSpec extends AbstractSharedRegistrySpecification {
+
+ DefaultImplementationBuilder builder = getService(DefaultImplementationBuilder)
+
+ def "default simple interface does nothing"() {
+ Runnable r = builder.createDefaultImplementation(Runnable)
+
+ when:
+
+ r.run()
+
+ then:
+
+ assert r.toString() == "<NoOp java.lang.Runnable>"
+ }
+
+ def "when toString() is part of interface, the default returns null"() {
+ ToString ts = builder.createDefaultImplementation(ToString)
+
+ expect:
+
+ ts.toString() == null
+ }
+
+ def "built instances are cached (by type)"() {
+ Runnable r1 = builder.createDefaultImplementation(Runnable)
+ Runnable r2 = builder.createDefaultImplementation(Runnable)
+
+ expect:
+
+ r1.is r2
+ }
+
+}