/*
* Copyright 2016 Kejun Xia
*
* 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 com.shipdream.lib.android.mvc.event.bus.internal;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class TestEventBus {
private EventBusImpl eventBus;
@Before
public void setUp() throws Exception {
eventBus = new EventBusImpl();
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowIllegalArgumentExceptionToRegisterNullSubscriber() {
eventBus.register(null);
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowIllegalArgumentExceptionToUnregisterNullSubscriber() {
eventBus.unregister(null);
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowIllegalArgumentExceptionToPostNullEvent() {
eventBus.post(null);
}
@Test
public void should_subscribers_methods_inherited_from_system_classes() {
//Arrange
class Event1{}
class Event2{}
class Event3{}
//Test java.xxx
class Subscriber extends java.io.InputStream{
public void onEvent(Event1 event1) {
}
@Override
public int read() throws IOException {
return 0;
}
}
Subscriber sub = new Subscriber();
//Action
EventBusImpl eventBus1 = new EventBusImpl();
eventBus1.register(sub);
//Assert
Assert.assertEquals(eventBus1.subscribers.size(), 1);
Assert.assertTrue(eventBus1.subscribers.keySet().contains(Event1.class));
eventBus1.unregister(sub);
Assert.assertEquals(eventBus1.subscribers.size(), 0);
//Test javax.xxx
class Subscriber2 extends javax.naming.Binding {
public Subscriber2(String name, Object obj) {
super(name, obj);
}
public void onEvent(Event1 event1) {
}
}
Subscriber2 sub2 = new Subscriber2("", "");
//Action
EventBusImpl eventBus2 = new EventBusImpl();
eventBus2.register(sub2);
//Assert
Assert.assertEquals(eventBus2.subscribers.size(), 1);
Assert.assertTrue(eventBus2.subscribers.keySet().contains(Event1.class));
eventBus2.unregister(sub2);
Assert.assertEquals(eventBus2.subscribers.size(), 0);
//Test android.xxx
class Subscriber3 extends android.Phone{
public void onEvent(Event2 event2) {
}
public void onEvent(Event3 event3) {
}
}
Subscriber3 sub3 = new Subscriber3();
EventBusImpl eventBus3 = new EventBusImpl();
eventBus3.register(sub3);
Assert.assertEquals(eventBus3.subscribers.size(), 2);
Assert.assertTrue(eventBus3.subscribers.keySet().contains(Event2.class));
Assert.assertTrue(eventBus3.subscribers.keySet().contains(Event3.class));
eventBus3.unregister(sub3);
Assert.assertEquals(eventBus3.subscribers.size(), 0);
}
@Test
public void should_throw_runtime_exception_when_posting_event_encounters_illegalAccessException() {
//Arrange
class Event1{}
//Test java.xxx
class Subscriber{
void onEvent(Event1 event1) {
throw new RuntimeException("Opps...");
}
}
Subscriber sub = new Subscriber();
//Action
EventBusImpl eventBus = new EventBusImpl();
eventBus.register(sub);
try {
eventBus.post(new Event1());
fail("Should caught InvocationTargetException");
} catch (RuntimeException e) {
Assert.assertTrue(e.getCause() instanceof InvocationTargetException);
}
}
@Test
public void shouldBeAbleToRegisterEventsForSingleSubscriber() {
//Arrange
class Event1{}
class Event2{}
class Event3{}
class Subscriber {
public void onEvent(Event1 event1) {
}
void onEvent(Event2 event2) {
}
private void onEvent(Event3 event3) {
}
}
Subscriber sub = new Subscriber();
//Action
eventBus.register(sub);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 3);
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event1.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event2.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event3.class));
}
@Test
public void shouldBeAbleToRegisterEventsForMultipleSubscribers() {
//Arrange
class Event1{}
class Event2{}
class Event3{}
class Subscriber {
public void onEvent(Event1 event1) {
}
void onEvent(Event2 event2) {
}
private void onEvent(Event3 event3) {
}
}
Subscriber sub = new Subscriber();
Subscriber sub2 = new Subscriber();
//Action
eventBus.register(sub);
eventBus.register(sub);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 3);
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event1.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event2.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event3.class));
Assert.assertEquals(eventBus.subscribers.get(Event1.class).size(), 1);
Assert.assertEquals(eventBus.subscribers.get(Event2.class).size(), 1);
Assert.assertEquals(eventBus.subscribers.get(Event3.class).size(), 1);
//Action
eventBus.register(sub2);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 3);
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event1.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event2.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event3.class));
Assert.assertEquals(eventBus.subscribers.get(Event1.class).size(), 2);
Assert.assertEquals(eventBus.subscribers.get(Event2.class).size(), 2);
Assert.assertEquals(eventBus.subscribers.get(Event3.class).size(), 2);
}
@Test
public void shouldBeAbleToUnregisterEventsForSingleSubscriber() {
//Arrange
class Event1{}
class Event2{}
class Event3{}
class Subscriber1 {
public void onEvent(Event1 event1) {
}
void onEvent(Event2 event2) {
}
private void onEvent(Event3 event3) {
}
}
Subscriber1 sub = new Subscriber1();
//Action
eventBus.register(sub);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 3);
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event1.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event2.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event3.class));
//Action
eventBus.unregister(sub);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 0);
}
@Test
public void shouldBeAbleToUnregisterEventsForMultipleSubscribers() {
//Arrange
class Event1{}
class Event2{}
class Event3{}
class Subscriber {
public void onEvent(Event1 event1) {
}
void onEvent(Event2 event2) {
}
private void onEvent(Event3 event3) {
}
}
Subscriber sub = new Subscriber();
Subscriber sub2 = new Subscriber();
//Action
eventBus.register(sub);
eventBus.register(sub);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 3);
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event1.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event2.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event3.class));
Assert.assertEquals(eventBus.subscribers.get(Event1.class).size(), 1);
Assert.assertEquals(eventBus.subscribers.get(Event2.class).size(), 1);
Assert.assertEquals(eventBus.subscribers.get(Event3.class).size(), 1);
//Action
eventBus.register(sub2);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 3);
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event1.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event2.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event3.class));
Assert.assertEquals(eventBus.subscribers.get(Event1.class).size(), 2);
Assert.assertNotNull(eventBus.subscribers.get(Event1.class).get(sub));
Assert.assertNotNull(eventBus.subscribers.get(Event1.class).get(sub2));
Assert.assertEquals(eventBus.subscribers.get(Event2.class).size(), 2);
Assert.assertNotNull(eventBus.subscribers.get(Event2.class).get(sub));
Assert.assertNotNull(eventBus.subscribers.get(Event2.class).get(sub2));
Assert.assertEquals(eventBus.subscribers.get(Event3.class).size(), 2);
Assert.assertNotNull(eventBus.subscribers.get(Event3.class).get(sub));
Assert.assertNotNull(eventBus.subscribers.get(Event3.class).get(sub2));
//Action
eventBus.unregister(sub);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 3);
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event1.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event2.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event3.class));
Assert.assertEquals(eventBus.subscribers.get(Event1.class).size(), 1);
Assert.assertTrue(!eventBus.subscribers.get(Event1.class).containsKey(sub));
Assert.assertTrue(eventBus.subscribers.get(Event1.class).containsKey(sub2));
Assert.assertNotNull(eventBus.subscribers.get(Event1.class).get(sub2));
Assert.assertEquals(eventBus.subscribers.get(Event2.class).size(), 1);
Assert.assertTrue(!eventBus.subscribers.get(Event2.class).containsKey(sub));
Assert.assertTrue(eventBus.subscribers.get(Event2.class).containsKey(sub2));
Assert.assertEquals(eventBus.subscribers.get(Event3.class).size(), 1);
Assert.assertTrue(!eventBus.subscribers.get(Event2.class).containsKey(sub));
Assert.assertTrue(eventBus.subscribers.get(Event2.class).containsKey(sub2));
//Action
eventBus.unregister(sub);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 3);
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event1.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event2.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event3.class));
Assert.assertEquals(eventBus.subscribers.get(Event1.class).size(), 1);
Assert.assertTrue(!eventBus.subscribers.get(Event1.class).containsKey(sub));
Assert.assertTrue(eventBus.subscribers.get(Event1.class).containsKey(sub2));
Assert.assertNotNull(eventBus.subscribers.get(Event1.class).get(sub2));
Assert.assertEquals(eventBus.subscribers.get(Event2.class).size(), 1);
Assert.assertTrue(!eventBus.subscribers.get(Event2.class).containsKey(sub));
Assert.assertTrue(eventBus.subscribers.get(Event2.class).containsKey(sub2));
Assert.assertEquals(eventBus.subscribers.get(Event3.class).size(), 1);
Assert.assertTrue(!eventBus.subscribers.get(Event2.class).containsKey(sub));
Assert.assertTrue(eventBus.subscribers.get(Event2.class).containsKey(sub2));
//Action
eventBus.unregister(sub2);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 0);
}
@Test
public void shouldBeAbleToRegisterEventsWithInheritedMethods() {
//Arrange
class Event1{}
class Event2{}
class Event3{}
class Event4{}
class Event5{}
class Subscriber1 {
public void onEvent(Event1 event1) {
}
void onEvent(Event2 event2) {
}
private void onEvent(Event3 event3) {
}
}
class Subscriber2 extends Subscriber1 {
protected void onEvent(Event4 event4) {
}
void onEvent(Event5 event5) {
}
public void onEvent(Event1 event1) {
}
}
Subscriber2 sub = new Subscriber2();
//Action
eventBus.register(sub);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 5);
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event1.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event2.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event3.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event4.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event5.class));
}
@Test
public void shouldBeAbleToUnregisterEventsWithInheritedMethods() {
//Arrange
class Event1{}
class Event2{}
class Event3{}
class Event4{}
class Event5{}
class Subscriber1 {
public void onEvent(Event1 event1) {
}
void onEvent(Event2 event2) {
}
private void onEvent(Event3 event3) {
}
}
class Subscriber2 extends Subscriber1 {
@Override
public void onEvent(Event1 event1) {
}
protected void onEvent(Event4 event4) {
}
void onEvent(Event5 event5) {
}
}
Subscriber2 sub = new Subscriber2();
//Action
eventBus.register(sub);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 5);
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event1.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event2.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event3.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event4.class));
Assert.assertTrue(eventBus.subscribers.keySet().contains(Event5.class));
//Action
eventBus.unregister(sub);
//Assert
Assert.assertEquals(eventBus.subscribers.size(), 0);
}
@Test
public void shouldBeAbleToReceiveEventInRegisteredSubscriberButNotAfterUnregistration() {
//Arrange
class Event1{}
class Subscriber {
public void onEvent(Event1 event) {
}
}
Subscriber sub = mock(Subscriber.class);
Subscriber sub2 = mock(Subscriber.class);
eventBus.register(sub);
eventBus.register(sub2);
Event1 event = new Event1();
//Action
eventBus.post(event);
ArgumentCaptor<Event1> msg = ArgumentCaptor.forClass(Event1.class);
//Assert
verify(sub).onEvent(msg.capture());
verify(sub2).onEvent(msg.capture());
//Arrange
reset(sub);
reset(sub2);
eventBus.unregister(sub);
//Action
eventBus.post(event);
msg = ArgumentCaptor.forClass(Event1.class);
//Assert
verify(sub, times(0)).onEvent(msg.capture());
verify(sub2).onEvent(msg.capture());
//Arrange
reset(sub);
reset(sub2);
eventBus.unregister(sub2);
//Action
eventBus.post(event);
msg = ArgumentCaptor.forClass(Event1.class);
//Assert
verify(sub, times(0)).onEvent(msg.capture());
verify(sub2, times(0)).onEvent(msg.capture());
}
@Test
public void shouldBeAbleToReceiveEventInRegisteredSubscriberButNotAfterUnregistrationForInheritedMethod() {
//Arrange
class Event1{
}
class Event2{
}
class Event3{
}
class EventHandler {
void handleEvent(Event1 event) {
}
void handleEvent(Event2 event) {
}
void handleEvent(Event3 event) {
}
}
final EventHandler handler = mock(EventHandler.class);
final EventHandler handler2 = mock(EventHandler.class);
class Subscriber {
public void onEvent(Event1 event) {
handler.handleEvent(event);
}
public void onEvent(Event2 event) {
handler.handleEvent(event);
}
}
class Subscriber2 extends Subscriber {
public void onEvent(Event1 event) {
handler2.handleEvent(event);
}
public void onEvent(Event3 event) {
handler2.handleEvent(event);
}
}
Subscriber sub = new Subscriber();
Subscriber sub2 = new Subscriber2();
eventBus.register(sub);
eventBus.register(sub2);
Event1 event = new Event1();
Event2 event2 = new Event2();
Event3 event3 = new Event3();
//Action
eventBus.post(event);
eventBus.post(event2);
eventBus.post(event3);
//Assert
verify(handler, times(1)).handleEvent(any(Event1.class));
//Time1: handled by sub
//Time2: handled by sub2 which inherited onEvent(Event2) from sub1 and call handler.handlerEvent(Event2) again
verify(handler, times(2)).handleEvent(any(Event2.class));
verify(handler2, times(1)).handleEvent(any(Event1.class));
verify(handler2, times(1)).handleEvent(any(Event3.class));
verify(handler2, times(1)).handleEvent(any(Event3.class));
//Arrange
reset(handler);
reset(handler2);
eventBus.unregister(sub);
//Action
eventBus.post(event);
eventBus.post(event2);
eventBus.post(event3);
//Assert
verify(handler, times(0)).handleEvent(any(Event1.class));
//Time1: handled by sub2 which inherited onEvent(Event2) from sub1 and call handler.handlerEvent(Event2) again
verify(handler, times(1)).handleEvent(any(Event2.class));
verify(handler2, times(1)).handleEvent(any(Event1.class));
verify(handler2, times(1)).handleEvent(any(Event3.class));
verify(handler2, times(1)).handleEvent(any(Event3.class));
//Arrange
reset(handler);
reset(handler2);
eventBus.unregister(sub2);
//Action
eventBus.post(event);
eventBus.post(event2);
eventBus.post(event3);
//Assert
verify(handler, times(0)).handleEvent(any(Event1.class));
verify(handler, times(0)).handleEvent(any(Event2.class));
verify(handler2, times(0)).handleEvent(any(Event1.class));
verify(handler2, times(0)).handleEvent(any(Event3.class));
verify(handler2, times(0)).handleEvent(any(Event3.class));
}
}