You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/07/12 02:14:54 UTC
git commit: ISIS-463: Cucumber-JVM supporting framework classes
Updated Branches:
refs/heads/master 7fc529930 -> 78edef50a
ISIS-463: Cucumber-JVM supporting framework classes
Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/78edef50
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/78edef50
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/78edef50
Branch: refs/heads/master
Commit: 78edef50a8379030be77969105f9924aa1221334
Parents: 7fc5299
Author: Dan Haywood <da...@apache.org>
Authored: Fri Jul 12 01:05:34 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Fri Jul 12 01:05:34 2013 +0100
----------------------------------------------------------------------
.../integtestsupport/IsisSystemForTest.java | 36 +-
...enarioExecutionIntegrationScopeAbstract.java | 93 ++++++
.../CukeStepDefsIntegrationScopeAbstract.java | 75 +++++
core/pom.xml | 24 ++
core/unittestsupport/pom.xml | 17 +
.../scenarios/DomainServiceProvider.java | 24 ++
.../scenarios/ScenarioExecution.java | 215 ++++++++++++
.../scenarios/specs/CukeSpecsAbstract.java | 38 +++
.../scenarios/specs/CukeStepDefsAbstract.java | 38 +++
.../core/unittestsupport/scenarios/specs/V.java | 332 +++++++++++++++++++
.../test/java/integtests/AbstractIntegTest.java | 2 +-
11 files changed, 881 insertions(+), 13 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/isis/blob/78edef50/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IsisSystemForTest.java
----------------------------------------------------------------------
diff --git a/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IsisSystemForTest.java b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IsisSystemForTest.java
index 1f84077..63b2c68 100644
--- a/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IsisSystemForTest.java
+++ b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IsisSystemForTest.java
@@ -37,7 +37,6 @@ import org.apache.isis.applib.DomainObjectContainer;
import org.apache.isis.applib.fixtures.InstallableFixture;
import org.apache.isis.core.commons.authentication.AuthenticationSession;
import org.apache.isis.core.commons.config.IsisConfiguration;
-import org.apache.isis.core.integtestsupport.legacy.Fixture;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
import org.apache.isis.core.metamodel.adapter.oid.RootOid;
@@ -58,11 +57,12 @@ import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
import org.apache.isis.core.runtime.system.transaction.IsisTransaction.State;
import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
import org.apache.isis.core.security.authentication.AuthenticationRequestNameOnly;
+import org.apache.isis.core.unittestsupport.scenarios.DomainServiceProvider;
/**
* Wraps a plain {@link IsisSystemDefault}, and provides a number of features to assist with testing.
*/
-public class IsisSystemForTest implements org.junit.rules.TestRule {
+public class IsisSystemForTest implements org.junit.rules.TestRule, DomainServiceProvider {
public interface Listener {
@@ -123,8 +123,7 @@ public class IsisSystemForTest implements org.junit.rules.TestRule {
private IsisSystemDefault isisSystem;
private AuthenticationSession authenticationSession;
- // public visibility just to reduce noise in tests
- public DomainObjectContainer container;
+ private DomainObjectContainer container;
private final IsisConfiguration configuration;
private final PersistenceMechanismInstaller persistenceMechanismInstaller;
@@ -279,7 +278,7 @@ public class IsisSystemForTest implements org.junit.rules.TestRule {
authenticationSession = authenticationManager.authenticate(authenticationRequest);
IsisContext.openSession(authenticationSession);
- container = getContainer();
+ setContainer(getContainer());
wireAndInstallFixtures();
if(fireListeners.shouldFire()) {
@@ -301,7 +300,7 @@ public class IsisSystemForTest implements org.junit.rules.TestRule {
}
}
- private DomainObjectContainer getContainer() {
+ public DomainObjectContainer getContainer() {
return getPersistenceSession().getServicesInjector().getContainer();
}
@@ -451,14 +450,14 @@ public class IsisSystemForTest implements org.junit.rules.TestRule {
public ObjectAdapter persist(Object domainObject) {
ensureSessionInProgress();
ensureObjectIsNotPersistent(domainObject);
- container.persist(domainObject);
+ getContainer().persist(domainObject);
return adapterFor(domainObject);
}
public ObjectAdapter destroy(Object domainObject ) {
ensureSessionInProgress();
ensureObjectIsPersistent(domainObject);
- container.remove(domainObject);
+ getContainer().remove(domainObject);
return adapterFor(domainObject);
}
@@ -499,13 +498,13 @@ public class IsisSystemForTest implements org.junit.rules.TestRule {
}
private void ensureObjectIsNotPersistent(Object domainObject) {
- if(container.isPersistent(domainObject)) {
+ if(getContainer().isPersistent(domainObject)) {
throw new IllegalArgumentException("domain object is already persistent");
}
}
private void ensureObjectIsPersistent(Object domainObject) {
- if(!container.isPersistent(domainObject)) {
+ if(!getContainer().isPersistent(domainObject)) {
throw new IllegalArgumentException("domain object is not persistent");
}
}
@@ -609,11 +608,16 @@ public class IsisSystemForTest implements org.junit.rules.TestRule {
}
}
-
-
+ /* (non-Javadoc)
+ * @see org.apache.isis.core.integtestsupport.ServiceProvider#getService(java.lang.Class)
+ */
+ @Override
@SuppressWarnings("unchecked")
public <T> T getService(Class<T> serviceClass) {
+ if(serviceClass == DomainObjectContainer.class) {
+ return (T) getContainer();
+ }
List<ObjectAdapter> servicesAdapters = getPersistenceSession().getServices();
for(ObjectAdapter serviceAdapter: servicesAdapters) {
Object servicePojo = serviceAdapter.getObject();
@@ -660,6 +664,14 @@ public class IsisSystemForTest implements org.junit.rules.TestRule {
return IsisContext.getPersistenceSession();
}
+ /**
+ * @param container the container to set
+ */
+ public void setContainer(DomainObjectContainer container) {
+ this.container = container;
+
+ }
+
http://git-wip-us.apache.org/repos/asf/isis/blob/78edef50/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/ScenarioExecutionIntegrationScopeAbstract.java
----------------------------------------------------------------------
diff --git a/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/ScenarioExecutionIntegrationScopeAbstract.java b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/ScenarioExecutionIntegrationScopeAbstract.java
new file mode 100644
index 0000000..d511420
--- /dev/null
+++ b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/ScenarioExecutionIntegrationScopeAbstract.java
@@ -0,0 +1,93 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.isis.core.integtestsupport.scenarios;
+
+import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.applib.fixtures.InstallableFixture;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.core.integtestsupport.IsisSystemForTest;
+import org.apache.isis.core.unittestsupport.scenarios.ScenarioExecution;
+
+
+/**
+ * An extension of {@link ScenarioExecution} for use within (coarse grained)
+ * integration tests and Cucumber specs where there is back-end database.
+ *
+ * <p>
+ * To this end it provides the ability to
+ * {@link #install(InstallableFixture...) install arbitrary fixtures} to
+ * tear down/setup data, and also to methods to {@link #beginTran() begin}
+ * or {@link #endTran(boolean) end} transactions.
+ */
+public abstract class ScenarioExecutionIntegrationScopeAbstract extends ScenarioExecution {
+
+ protected final IsisSystemForTest isft;
+
+ public ScenarioExecutionIntegrationScopeAbstract(IsisSystemForTest isft) {
+ super(isft);
+ this.isft = isft;
+ }
+
+ // //////////////////////////////////////
+
+ /**
+ * Convenience
+ */
+ public DomainObjectContainer getContainer() {
+ return service(DomainObjectContainer.class);
+ }
+
+ /**
+ * Convenience
+ */
+ public WrapperFactory getWrapperFactory() {
+ return service(WrapperFactory.class);
+ }
+
+
+ // //////////////////////////////////////
+
+ /**
+ * Install arbitrary fixtures, eg before an integration tests or as part of a
+ * Cucumber step definitions or hook.
+ */
+ public void install(InstallableFixture... fixtures) {
+ isft.installFixtures(fixtures);
+ }
+
+ // //////////////////////////////////////
+
+ /**
+ * For Cucumber hooks to call, performing transaction management around each step.
+ */
+ public void beginTran() {
+ isft.beginTran();
+ }
+
+ /**
+ * For Cucumber hooks to call, performing transaction management around each step.
+ */
+ public void endTran(boolean ok) {
+ if(ok) {
+ isft.commitTran();
+ } else {
+ isft.abortTran();
+ }
+ }
+
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/78edef50/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/specs/CukeStepDefsIntegrationScopeAbstract.java
----------------------------------------------------------------------
diff --git a/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/specs/CukeStepDefsIntegrationScopeAbstract.java b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/specs/CukeStepDefsIntegrationScopeAbstract.java
new file mode 100644
index 0000000..42ebce2
--- /dev/null
+++ b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/specs/CukeStepDefsIntegrationScopeAbstract.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.isis.core.integtestsupport.scenarios.specs;
+
+import cucumber.api.java.After;
+import cucumber.api.java.Before;
+
+import org.apache.isis.core.integtestsupport.scenarios.ScenarioExecutionIntegrationScopeAbstract;
+import org.apache.isis.core.unittestsupport.scenarios.specs.CukeStepDefsAbstract;
+
+
+/**
+ * Base class for integration-scope Cucumber step definitions.
+ */
+public abstract class CukeStepDefsIntegrationScopeAbstract extends CukeStepDefsAbstract<ScenarioExecutionIntegrationScopeAbstract> {
+
+ public CukeStepDefsIntegrationScopeAbstract(ScenarioExecutionIntegrationScopeAbstract scenarioExecution) {
+ super(scenarioExecution);
+ }
+
+ // //////////////////////////////////////
+
+ /**
+ * Convenience method to start transaction.
+ *
+ * <p>
+ * Cukes does not allow this to be annotated with {@link Before Cucumber's Before}
+ * annotation. Subclasses should therefore override, annotate, and delegate back up:
+ *
+ * <pre>
+ * @cucumber.api.java.Before
+ * @Override
+ * public void beginTran() {
+ * super.beginTran();
+ * }
+ * </pre>
+ */
+ public void beginTran() {
+ scenarioExecution.beginTran();
+ }
+
+ /**
+ * Convenience method to start transaction.
+ *
+ * <p>
+ * Cukes does not allow this to be annotated with {@link After Cucumber's After}
+ * annotation. Subclasses should therefore override, annotate, and delegate back up:
+ *
+ * <pre>
+ * @cucumber.api.java.After
+ * @Override
+ * public void endTran(cucumber.api.Scenario sc) {
+ * super.endTran(sc);
+ * }
+ * </pre>
+ */
+ public void endTran(cucumber.api.Scenario sc) {
+ scenarioExecution.endTran(!sc.isFailed());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/78edef50/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index be42fc5..57d51c5 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -232,6 +232,13 @@
<enabled>false</enabled>
</snapshots>
</repository>
+ <repository>
+ <id>sonatype-snapshots</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
</repositories>
@@ -1389,6 +1396,23 @@ ${license.additional-notes}
</exclusions>
</dependency>
+ <!-- BDD testing -->
+ <dependency>
+ <groupId>info.cukes</groupId>
+ <artifactId>cucumber-java</artifactId>
+ <version>1.1.4-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>info.cukes</groupId>
+ <artifactId>cucumber-junit</artifactId>
+ <version>1.1.4-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>info.cukes</groupId>
+ <artifactId>cucumber-picocontainer</artifactId>
+ <version>1.1.4-SNAPSHOT</version>
+ </dependency>
+
<dependency>
<groupId>org.picocontainer</groupId>
<artifactId>picocontainer</artifactId>
http://git-wip-us.apache.org/repos/asf/isis/blob/78edef50/core/unittestsupport/pom.xml
----------------------------------------------------------------------
diff --git a/core/unittestsupport/pom.xml b/core/unittestsupport/pom.xml
index b329cb4..893b3a1 100644
--- a/core/unittestsupport/pom.xml
+++ b/core/unittestsupport/pom.xml
@@ -94,6 +94,23 @@
</dependency>
<dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>info.cukes</groupId>
+ <artifactId>cucumber-java</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>info.cukes</groupId>
+ <artifactId>cucumber-picocontainer</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>info.cukes</groupId>
+ <artifactId>cucumber-junit</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>javax.jdo</groupId>
<artifactId>jdo-api</artifactId>
<version>3.0.1</version>
http://git-wip-us.apache.org/repos/asf/isis/blob/78edef50/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/DomainServiceProvider.java
----------------------------------------------------------------------
diff --git a/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/DomainServiceProvider.java b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/DomainServiceProvider.java
new file mode 100644
index 0000000..cbfaa72
--- /dev/null
+++ b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/DomainServiceProvider.java
@@ -0,0 +1,24 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.isis.core.unittestsupport.scenarios;
+
+
+public interface DomainServiceProvider {
+
+ public abstract <T> T getService(Class<T> serviceClass);
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/78edef50/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/ScenarioExecution.java
----------------------------------------------------------------------
diff --git a/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/ScenarioExecution.java b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/ScenarioExecution.java
new file mode 100644
index 0000000..004d52f
--- /dev/null
+++ b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/ScenarioExecution.java
@@ -0,0 +1,215 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.isis.core.unittestsupport.scenarios;
+
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+
+/**
+ * Represents the currently executing scenario, allowing information to be shared
+ * between Cucumber step definitions (for unit- or integration- scoped), and also for
+ * integration tests.
+ *
+ * <p>
+ * Two types of information are available:
+ * <ul>
+ * <li>First, there are the domain services, provided using the {@link #service(Class) method}.
+ * If running at unit-scope, then these will most likely be mocked services (and not all services
+ * will necessarily be available). If running at integration-scope, then these will most likely
+ * be real instances, eg wired to the backend database.</li>
+ * <li>Second, there is a map of identified objects. This is predominantly for Cucumber
+ * step definitions (either unit- or integration-scoped), such that information can be passed
+ * between steps in a decoupled fashion.
+ * </ul>
+ *
+ * <p>
+ * When instantiated, this object binds itself to the current thread (using a {@link ThreadLocal}).
+ *
+ * <p>
+ * Subclasses may tailor the world for specific types of tests; for example the
+ * <tt>IntegrationScenarioExecution</tt> provides additional support for fixtures and
+ * transaction management, used both by integration-scoped specs and by integration tests.
+ */
+public class ScenarioExecution {
+
+ private static ThreadLocal<ScenarioExecution> current = new ThreadLocal<ScenarioExecution>();
+
+ public static ScenarioExecution current() {
+ final ScenarioExecution world = current.get();
+ if(world == null) {
+ throw new IllegalStateException("Scenario has not yet been instantiated by Cukes");
+ }
+ return world;
+ }
+
+
+ // //////////////////////////////////////
+
+ protected final DomainServiceProvider dsp;
+
+ /**
+ * For instantiation by Cucumber-JVM only.
+ */
+ public ScenarioExecution(final DomainServiceProvider dsp) {
+ this.dsp = dsp;
+ current.set(this);
+ }
+
+ public <T> T service(Class<T> cls) {
+ final T service = dsp.getService(cls);
+ if(service == null) {
+ throw new IllegalStateException(
+ "No service of type "
+ + cls.getSimpleName()
+ + " available");
+ }
+ return service;
+ }
+
+
+ // //////////////////////////////////////
+
+ /**
+ * Key for objects stored by steps in the scenario.
+ *
+ * <p>
+ * Objects can be identified in a variety of manners:
+ * <ul>
+ * <li>a fully qualified object provides both its type and a (unique) id; for example 'lease OXF-TOPMODEL-001'</li>
+ * <li>a named object provides only its id; for example 'OXF-TOPMODEL-001'</li>
+ * <li>a typed object provides only its type; for example 'the lease'.</li>
+ * </ul>
+ *
+ * <p>
+ * Because of the second rule, the id should be unique in and of itself.
+ *
+ * <p>
+ * The expectation is that scenarios will use the first form (fully qualified) the first time that an
+ * object is introduced within a scenario. Thereafter either of the other forms may be used.
+ * In the case of a typed object (eg "the lease"), the most recently "touched" object of that type
+ * is returned.
+ */
+ public static class VariableId {
+ private final String type;
+ private final String id;
+ public VariableId(String type, String id) {
+ this.type = type;
+ this.id = id;
+ }
+
+ /**
+ * eg 'lease'
+ */
+ public String getType() {
+ return type;
+ }
+ /**
+ * eg 'OXF-TOPMODEL-001'
+ */
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ VariableId other = (VariableId) obj;
+ if (id == null) {
+ if (other.id != null)
+ return false;
+ } else if (!id.equals(other.id))
+ return false;
+ if (type == null) {
+ if (other.type != null)
+ return false;
+ } else if (!type.equals(other.type))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "VariableId [type=" + type + ", id=" + id + "]";
+ }
+ }
+
+ private final Map<VariableId, Object> objectByVariableId = Maps.newLinkedHashMap();
+ private final Map<String, Object> objectsById = Maps.newLinkedHashMap();
+
+ private final Map<String, Object> mostRecent = Maps.newHashMap();
+
+ public void put(String type, String id, Object value) {
+ objectByVariableId.put(new VariableId(type, id), value);
+ mostRecent.put(type, value);
+ }
+
+ /**
+ * Retrieve an object previously used in the scenario.
+ *
+ * <p>
+ * Must specify type and/or id.
+ *
+ * @see VariableId - for rules on what constitutes an identifier.
+ */
+ public Object get(String type, String id) {
+ if(type != null && id != null) {
+ final VariableId variableId = new VariableId(type,id);
+ final Object value = objectByVariableId.get(variableId);
+ if(value != null) {
+ mostRecent.put(type, value);
+ return value;
+ }
+ throw new IllegalStateException("No such " + variableId);
+ }
+ if(type != null && id == null) {
+ return mostRecent.get(type);
+ }
+ if(type == null && id != null) {
+ final Object value = objectsById.get(id);
+ if(value != null) {
+ mostRecent.put(type, value);
+ }
+ return value;
+ }
+ throw new IllegalArgumentException("Must specify type and/or id");
+ }
+
+ /**
+ * As {@link #get(String, String)}, but downcasting to the provided class.
+ */
+ @SuppressWarnings("unchecked")
+ public <X> X get(String type, String id, Class<X> cls) {
+ return (X) get(type, id);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/78edef50/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/CukeSpecsAbstract.java
----------------------------------------------------------------------
diff --git a/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/CukeSpecsAbstract.java b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/CukeSpecsAbstract.java
new file mode 100644
index 0000000..57b4dcd
--- /dev/null
+++ b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/CukeSpecsAbstract.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.isis.core.unittestsupport.scenarios.specs;
+
+import cucumber.api.junit.Cucumber;
+
+import org.junit.runner.RunWith;
+
+/**
+ * Base class for all Cucumber specs run at unit-scope; runs the spec as a JUnit test.
+ */
+@RunWith(Cucumber.class)
+@Cucumber.Options(
+ format = {
+ "html:target/cucumber-html-report"
+ // addHook causes an exception to be thrown if this reporter is registered...
+ // ,"json-pretty:target/cucumber-json-report.json"
+ },
+ strict = true,
+ tags = { "~@backlog" })
+public abstract class CukeSpecsAbstract {
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/78edef50/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/CukeStepDefsAbstract.java
----------------------------------------------------------------------
diff --git a/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/CukeStepDefsAbstract.java b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/CukeStepDefsAbstract.java
new file mode 100644
index 0000000..0a0693e
--- /dev/null
+++ b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/CukeStepDefsAbstract.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.isis.core.unittestsupport.scenarios.specs;
+
+import org.apache.isis.core.unittestsupport.scenarios.ScenarioExecution;
+
+/**
+ * Base class for unit-scope Cucumber step definitions.
+ *
+ * <p>
+ * Simply declares that an instance of (a concrete subclass of)
+ * {@link ScenarioExecution} must be instantiated by the Cucumber-JVM
+ * runtime and injected into the step definitions.
+ */
+public abstract class CukeStepDefsAbstract<T extends ScenarioExecution> {
+
+ protected final T scenarioExecution;
+
+ public CukeStepDefsAbstract(T scenarioExecution) {
+ this.scenarioExecution = scenarioExecution;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/78edef50/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/V.java
----------------------------------------------------------------------
diff --git a/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/V.java b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/V.java
new file mode 100644
index 0000000..a4691f8
--- /dev/null
+++ b/core/unittestsupport/src/main/java/org/apache/isis/core/unittestsupport/scenarios/specs/V.java
@@ -0,0 +1,332 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.isis.core.unittestsupport.scenarios.specs;
+
+import cucumber.api.Transformer;
+
+import org.joda.time.format.DateTimeFormat;
+
+/**
+ * A set of converters for built-in value types; for use in Cucumber step definitions.
+ */
+public class V {
+
+ private V() {
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link java.lang.Byte}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class Byte extends Transformer<java.lang.Byte> {
+
+ @Override
+ public java.lang.Byte transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : java.lang.Byte.parseByte(value);
+ }
+
+ public static java.lang.Byte as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new Byte().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link java.lang.Short}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class Short extends Transformer<java.lang.Short> {
+
+ @Override
+ public java.lang.Short transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : java.lang.Short.parseShort(value);
+ }
+
+ public static java.lang.Short as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new Short().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link java.lang.Integer}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class Integer extends Transformer<java.lang.Integer> {
+
+ @Override
+ public java.lang.Integer transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : java.lang.Integer.parseInt(value);
+ }
+
+ public static java.lang.Integer as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new Integer().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link java.lang.Long}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class Long extends Transformer<java.lang.Long> {
+
+ @Override
+ public java.lang.Long transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : java.lang.Long.parseLong(value);
+ }
+
+ public static java.lang.Long as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new Long().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link java.lang.Float}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class Float extends Transformer<java.lang.Float> {
+
+ @Override
+ public java.lang.Float transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : java.lang.Float.parseFloat(value);
+ }
+
+ public static java.lang.Float as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new Float().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link java.lang.Double}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class Double extends Transformer<java.lang.Double> {
+
+ @Override
+ public java.lang.Double transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : java.lang.Double.parseDouble(value);
+ }
+
+ public static java.lang.Double as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new Double().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link java.lang.BigInteger}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class BigInteger extends Transformer<java.math.BigInteger> {
+
+ @Override
+ public java.math.BigInteger transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : new java.math.BigInteger(value);
+ }
+
+ public static java.math.BigInteger as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new BigInteger().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link java.lang.BigDecimal}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class BigDecimal extends Transformer<java.math.BigDecimal> {
+
+ @Override
+ public java.math.BigDecimal transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : new java.math.BigDecimal(value);
+ }
+
+ public static java.math.BigDecimal as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new BigDecimal().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link java.lang.Character}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class Character extends Transformer<java.lang.Character> {
+
+ @Override
+ public java.lang.Character transform(java.lang.String value) {
+ return value == null || "null".equals(value) || value.length() <1
+ ? null
+ : value.charAt(0);
+ }
+
+ public static java.lang.Character as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new Character().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link java.lang.String}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class String extends Transformer<java.lang.String> {
+
+ @Override
+ public java.lang.String transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : value;
+ }
+
+ public static java.lang.String as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new String().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link org.joda.time.LocalDate}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class LyyyyMMdd extends Transformer<org.joda.time.LocalDate> {
+
+ @Override
+ public org.joda.time.LocalDate transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : DateTimeFormat.forPattern("yyyy-MM-dd").parseLocalDate(value);
+ }
+
+ public static org.joda.time.LocalDate as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new LyyyyMMdd().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link org.joda.time.DateTime}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class yyyyMMddHHmmss extends Transformer<org.joda.time.DateTime> {
+
+ @Override
+ public org.joda.time.DateTime transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime(value);
+ }
+
+ public static org.joda.time.DateTime as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new yyyyMMddHHmmss().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link org.joda.time.DateTime}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class yyyyMMddHHmm extends Transformer<org.joda.time.DateTime> {
+
+ @Override
+ public org.joda.time.DateTime transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : DateTimeFormat.forPattern("yyyy-MM-dd HH:mm").parseDateTime(value);
+ }
+
+ public static org.joda.time.DateTime as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new yyyyMMddHHmmss().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link org.joda.time.LocalDateTime}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class LyyyyMMddHHmm extends Transformer<org.joda.time.LocalDateTime> {
+
+ @Override
+ public org.joda.time.LocalDateTime transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : DateTimeFormat.forPattern("yyyy-MM-dd HH:mm").parseLocalDateTime(value);
+ }
+
+ public static org.joda.time.DateTime as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new yyyyMMddHHmmss().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+ /**
+ * Converts {@link java.lang.String}s to {@link org.joda.time.LocalDateTime}, but also recognizing the
+ * keyword 'null'.
+ */
+ public static class LyyyyMMddHHmmss extends Transformer<org.joda.time.LocalDateTime> {
+
+ @Override
+ public org.joda.time.LocalDateTime transform(java.lang.String value) {
+ return value == null || "null".equals(value)
+ ? null
+ : DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseLocalDateTime(value);
+ }
+
+ public static org.joda.time.DateTime as(Object value) {
+ return value != null && value instanceof java.lang.String
+ ? new yyyyMMddHHmmss().transform((java.lang.String) value)
+ : null;
+ }
+ }
+
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/78edef50/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integtests/AbstractIntegTest.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integtests/AbstractIntegTest.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integtests/AbstractIntegTest.java
index 5565c0a..7b3e098 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integtests/AbstractIntegTest.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integtests/AbstractIntegTest.java
@@ -73,7 +73,7 @@ public abstract class AbstractIntegTest {
public void init() {
toDoItems = getIsft().getService(ToDoItemsJdo.class);
wrapperFactory = getIsft().getService(WrapperFactoryDefault.class);
- container = getIsft().container;
+ container = getIsft().getContainer();
}
protected <T> T wrap(T obj) {