/*
* $Id$
*
* Janus platform is an open-source multiagent platform.
* More details on http://www.janusproject.io
*
* Copyright (C) 2014-2015 Sebastian RODRIGUEZ, Nicolas GAUD, Stéphane GALLAND.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.janusproject.tests.kernel.bic;
import static org.junit.Assert.*;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.UUID;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import io.janusproject.kernel.bic.BehaviorsSkill;
import io.janusproject.kernel.bic.InternalEventBusCapacity;
import io.janusproject.kernel.bic.SchedulesSkill;
import io.janusproject.tests.testutils.AbstractJanusTest;
import io.sarl.core.InnerContextAccess;
import io.sarl.core.Schedules;
import io.sarl.lang.core.Address;
import io.sarl.lang.core.Agent;
import io.sarl.lang.core.AgentContext;
import io.sarl.lang.core.AgentTrait;
import io.sarl.lang.core.Behavior;
import io.sarl.lang.core.BuiltinCapacitiesProvider;
import io.sarl.lang.core.Capacities;
import io.sarl.lang.core.Capacity;
import io.sarl.lang.core.Event;
import io.sarl.lang.core.EventListener;
import io.sarl.lang.core.EventSpace;
import io.sarl.lang.core.EventSpaceSpecification;
import io.sarl.lang.core.Scope;
import io.sarl.lang.core.Skill;
import io.sarl.lang.core.SpaceID;
import io.sarl.lang.util.ClearableReference;
import io.sarl.tests.api.Nullable;
import io.sarl.util.Scopes;
/**
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
@SuppressWarnings("all")
public class BehaviorsSkillTest extends AbstractJanusTest {
@Nullable
private EventListener eventListener;
@Nullable
private InternalEventBusCapacity busCapacity;
@Nullable
private InnerContextAccess innerCapacity;
@Nullable
private SchedulesSkill schedulesCapacity;
@Nullable
private EventSpace innerSpace;
@Nullable
private Address address;
@Nullable
private BehaviorsSkill skill;
@Nullable
private Skill1 specificCapacity;
@Nullable
private TestAgent agent;
@Before
public void setUp() throws Exception {
this.eventListener = Mockito.mock(EventListener.class);
this.address = new Address(new SpaceID(UUID.randomUUID(), UUID.randomUUID(), EventSpaceSpecification.class),
UUID.randomUUID());
this.busCapacity = Mockito.mock(InternalEventBusCapacity.class);
Mockito.when(this.busCapacity.asEventListener()).thenReturn(this.eventListener);
this.innerSpace = Mockito.mock(EventSpace.class);
Mockito.when(this.innerSpace.getAddress(ArgumentMatchers.any(UUID.class))).thenReturn(this.address);
AgentContext innerContext = Mockito.mock(AgentContext.class);
Mockito.when(innerContext.getDefaultSpace()).thenReturn(this.innerSpace);
this.innerCapacity = Mockito.mock(InnerContextAccess.class);
Mockito.when(this.innerCapacity.getInnerContext()).thenReturn(innerContext);
this.schedulesCapacity = Mockito.mock(SchedulesSkill.class);
this.agent = new TestAgent(this);
this.skill = this.reflect.newInstance(BehaviorsSkill.class, this.agent, this.address);
this.specificCapacity = new Skill1(this.agent);
}
@Test
public void asEventListener() {
assertSame(this.eventListener, this.skill.asEventListener());
}
@Test
public void registerBehavior() {
Behavior b = new TestBehavior(this.agent);
b = spy(b);
assertSame(b, this.skill.registerBehavior(b));
ArgumentCaptor<Behavior> argument1 = ArgumentCaptor.forClass(Behavior.class);
ArgumentCaptor<Boolean> argument2 = ArgumentCaptor.forClass(Boolean.class);
ArgumentCaptor<Function1<? super Event, ? extends Boolean>> argument3 = ArgumentCaptor.forClass(Function1.class);
Mockito.verify(this.busCapacity).registerEventListener(argument1.capture(), argument2.capture(), argument3.capture());
assertSame(b, argument1.getValue());
assertTrue(argument2.getValue());
assertNull(argument3.getValue());
}
@Test
public void registerBehavior_null() {
Behavior b = new TestBehavior(this.agent);
b = spy(b);
assertSame(b, this.skill.registerBehavior(b, null));
ArgumentCaptor<Behavior> argument1 = ArgumentCaptor.forClass(Behavior.class);
ArgumentCaptor<Boolean> argument2 = ArgumentCaptor.forClass(Boolean.class);
ArgumentCaptor<Function1<? super Event, ? extends Boolean>> argument3 = ArgumentCaptor.forClass(Function1.class);
Mockito.verify(this.busCapacity).registerEventListener(argument1.capture(), argument2.capture(), argument3.capture());
assertSame(b, argument1.getValue());
assertTrue(argument2.getValue());
assertNull(argument3.getValue());
}
@Test
public void registerBehavior_validFilter() {
Behavior b = new TestBehavior(this.agent);
b = spy(b);
Function1<? super Event, ? extends Boolean> filter = (event) -> true;
assertSame(b, this.skill.registerBehavior(b, filter));
ArgumentCaptor<Behavior> argument1 = ArgumentCaptor.forClass(Behavior.class);
ArgumentCaptor<Boolean> argument2 = ArgumentCaptor.forClass(Boolean.class);
ArgumentCaptor<Function1<? super Event, ? extends Boolean>> argument3 = ArgumentCaptor.forClass(Function1.class);
Mockito.verify(this.busCapacity).registerEventListener(argument1.capture(), argument2.capture(), argument3.capture());
assertSame(b, argument1.getValue());
assertTrue(argument2.getValue());
assertSame(filter, argument3.getValue());
}
@Test
public void registerBehavior_invalidFilter() {
Behavior b = new TestBehavior(this.agent);
b = spy(b);
Function1<? super Event, ? extends Boolean> filter = (event) -> false;
assertSame(b, this.skill.registerBehavior(b, filter));
ArgumentCaptor<Behavior> argument1 = ArgumentCaptor.forClass(Behavior.class);
ArgumentCaptor<Boolean> argument2 = ArgumentCaptor.forClass(Boolean.class);
ArgumentCaptor<Function1<? super Event, ? extends Boolean>> argument3 = ArgumentCaptor.forClass(Function1.class);
Mockito.verify(this.busCapacity).registerEventListener(argument1.capture(), argument2.capture(), argument3.capture());
assertSame(b, argument1.getValue());
assertTrue(argument2.getValue());
assertSame(filter, argument3.getValue());
}
@Test
public void unregisterBehavior() {
Behavior b = new TestBehavior(this.agent);
b = spy(b);
this.skill.registerBehavior(b);
//
assertSame(b, this.skill.unregisterBehavior(b));
ArgumentCaptor<Behavior> argument1 = ArgumentCaptor.forClass(Behavior.class);
ArgumentCaptor<Boolean> argument2 = ArgumentCaptor.forClass(Boolean.class);
Mockito.verify(this.busCapacity, Mockito.times(1)).unregisterEventListener(argument1.capture(), argument2.capture());
assertSame(b, argument1.getValue());
assertTrue(argument2.getValue());
}
@Test
public void hasRegisteredBehavior() {
Mockito.doReturn(false).when(this.busCapacity).hasRegisteredEventListener(ArgumentMatchers.any());
assertFalse(this.skill.hasRegisteredBehavior());
//
Mockito.doReturn(true).when(this.busCapacity).hasRegisteredEventListener(ArgumentMatchers.any());
assertTrue(this.skill.hasRegisteredBehavior());
}
@Test
public void getRegisteredBehaviors() {
Mockito.doReturn(0).when(this.busCapacity).getRegisteredEventListeners(ArgumentMatchers.any(), ArgumentMatchers.any());
assertContains(this.skill.getRegisteredBehaviors());
//
Object behaviorListener = new TestBehavior(this.agent);
Mockito.doAnswer((it) -> {
((Collection) it.getArgument(1)).add(behaviorListener);
return 1;
}).when(this.busCapacity).getRegisteredEventListeners(ArgumentMatchers.any(), ArgumentMatchers.any());
assertContains(this.skill.getRegisteredBehaviors(), behaviorListener);
}
@Test
public void wake_noScope() {
Event event = mock(Event.class);
this.skill.wake(event);
ArgumentCaptor<Event> argument1 = ArgumentCaptor.forClass(Event.class);
ArgumentCaptor<Scope<Address>> argument2 = ArgumentCaptor.forClass(Scope.class);
Mockito.verify(this.innerSpace).emit(argument1.capture(), argument2.capture());
assertSame(event, argument1.getValue());
assertNull(argument2.getValue());
ArgumentCaptor<Address> argument3 = ArgumentCaptor.forClass(Address.class);
Mockito.verify(event).setSource(argument3.capture());
assertEquals(this.address, argument3.getValue());
}
@Test
public void wake_scope_all() {
Event event = mock(Event.class);
this.skill.wake(event, Scopes.allParticipants());
ArgumentCaptor<Event> argument1 = ArgumentCaptor.forClass(Event.class);
ArgumentCaptor<Scope<Address>> argument2 = ArgumentCaptor.forClass(Scope.class);
Mockito.verify(this.innerSpace).emit(argument1.capture(), argument2.capture());
assertSame(event, argument1.getValue());
assertNotNull(argument2.getValue());
assertSame(Scopes.allParticipants(), argument2.getValue());
ArgumentCaptor<Address> argument3 = ArgumentCaptor.forClass(Address.class);
Mockito.verify(event).setSource(argument3.capture());
assertEquals(this.address, argument3.getValue());
}
@Test
public void wake_scope_any() {
Event event = mock(Event.class);
SpaceID spaceID = new SpaceID(UUID.randomUUID(), UUID.randomUUID(), null);
Scope<Address> scope = Scopes.addresses(new Address(spaceID, UUID.randomUUID()));
this.skill.wake(event, scope);
ArgumentCaptor<Event> argument1 = ArgumentCaptor.forClass(Event.class);
ArgumentCaptor<Scope<Address>> argument2 = ArgumentCaptor.forClass(Scope.class);
Mockito.verify(this.innerSpace).emit(argument1.capture(), argument2.capture());
assertSame(event, argument1.getValue());
assertNotNull(argument2.getValue());
assertSame(scope, argument2.getValue());
ArgumentCaptor<Address> argument3 = ArgumentCaptor.forClass(Address.class);
Mockito.verify(event).setSource(argument3.capture());
assertEquals(this.address, argument3.getValue());
}
@Test
public void contextAwareCapacityCall() throws Exception {
TestBehavior b = new TestBehavior(this.agent);
//
b.runContextAwareCapacityCallTest();
//
assertNotNull(this.specificCapacity.caller);
assertSame(b, this.specificCapacity.caller);
}
public static interface Capacity1 extends Capacity {
void callCapacity();
public static class ContextAwareCapacityWrapper<C extends Capacity1> extends Capacity.ContextAwareCapacityWrapper<C> implements Capacity1 {
public ContextAwareCapacityWrapper(C capacity, AgentTrait caller) {
super(capacity, caller);
}
public void callCapacity() {
try {
ensureCallerInLocalThread();
this.capacity.callCapacity();
} finally {
resetCallerInLocalThread();
}
}
}
}
public static class Skill1 extends Skill implements Capacity1 {
public Object caller;
public Skill1(Agent agent) {
super(agent);
}
@Override
public void callCapacity() {
Object caller = Capacities.getCaller();
this.caller = caller;
}
}
public static class TestAgent extends Agent {
private final BehaviorsSkillTest test;
public TestAgent(BehaviorsSkillTest test) {
super(Mockito.mock(BuiltinCapacitiesProvider.class), UUID.randomUUID(), null);
this.test = test;
}
@Override
protected ClearableReference<Skill> $getSkill(Class<? extends Capacity> capacity) {
if (Capacity1.class.equals(capacity))
return new ClearableReference(this.test.specificCapacity);
if (InternalEventBusCapacity.class.equals(capacity))
return new ClearableReference(this.test.busCapacity);
if (InnerContextAccess.class.equals(capacity))
return new ClearableReference(this.test.innerCapacity);
if (Schedules.class.equals(capacity))
return new ClearableReference(this.test.schedulesCapacity);
return new ClearableReference<>(null);
}
}
public static class TestBehavior extends Behavior {
public TestBehavior(Agent owner) {
super(owner);
}
public void runContextAwareCapacityCallTest() {
Capacity1 skill = getSkill(Capacity1.class);
assertNotNull(skill);
assertInstanceOf(Capacity1.ContextAwareCapacityWrapper.class, skill);
Capacity1 original = ((Capacity1.ContextAwareCapacityWrapper<?>) skill).getDelegate();
assertInstanceOf(Skill1.class, original);
Skill1 skill1 = (Skill1) original;
skill.callCapacity();
assertSame(this, skill1.caller);
}
}
}