/**
* 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.specsupport.scenarios;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.Maps;
import org.hamcrest.Description;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.api.Action;
import org.jmock.api.Invocation;
import org.apache.isis.applib.DomainObjectContainer;
import org.apache.isis.core.unittestsupport.jmocking.JavassistImposteriser;
class DomainServiceProviderMockery implements DomainServiceProvider {
private DomainObjectContainer mockContainer = null;
private final Map<Class<?>, Object> mocks = Maps.newHashMap();
private Mockery context;
private ScenarioExecution scenarioExecution;
DomainServiceProviderMockery() {
init();
}
private void init() {
context = new Mockery() {{
setImposteriser(JavassistImposteriser.INSTANCE);
}};
mocks.clear();
}
@Override
public DomainObjectContainer getContainer() {
if(mockContainer == null) {
mockContainer = getService(DomainObjectContainer.class);
context.checking(new Expectations() {
{
allowing(mockContainer).newTransientInstance(with(Expectations.<Class<?>>anything()));
will(new Action() {
@SuppressWarnings("rawtypes")
public Object invoke(Invocation invocation) throws Throwable {
Class cls = (Class) invocation.getParameter(0);
return scenarioExecution.injectServices(cls.newInstance());
}
public void describeTo(Description description) {
description.appendText("newTransientInstance");
}
});
allowing(mockContainer).persistIfNotAlready(with(anything()));
}
});
}
return mockContainer;
}
@SuppressWarnings("unchecked")
@Override
public <T> T getService(Class<T> serviceClass) {
Object mock = mocks.get(serviceClass);
if(mock == null) {
mock = context.mock(serviceClass);
}
mocks.put(serviceClass, mock);
return (T) mock;
}
@Override
public <T> void replaceService(final T original, final T replacement) {
final Class<?> originalKey = keyFor(original);
if(originalKey == null) {
throw new IllegalArgumentException("Service to replace not found");
}
mocks.put(originalKey, replacement);
}
private Class<?> keyFor(Object original) {
final Set<Map.Entry<Class<?>, Object>> entries = mocks.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
if(entry.getValue() == original) {
return entry.getKey();
}
}
return null;
}
public Mockery mockery() {
return context;
}
DomainServiceProviderMockery init(ScenarioExecution scenarioExecution) {
this.scenarioExecution = scenarioExecution;
return this;
}
/**
* not API
*/
void assertIsSatisfied() {
mockery().assertIsSatisfied();
// discard all existing mocks and mockery, to start again.
init();
}
}