/*
* Copyright 2010 Google Inc.
*
* 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.google.gwt.activity.shared;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.UmbrellaException;
import com.google.gwt.event.shared.testing.CountingEventBus;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceChangeEvent;
import com.google.gwt.place.shared.PlaceChangeRequestEvent;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import junit.framework.TestCase;
/**
* Eponymous unit test.
*/
public class ActivityManagerTest extends TestCase {
private static class AsyncActivity extends SyncActivity {
AsyncActivity(MyView view) {
super(view);
}
@Override
public void start(AcceptsOneWidget display, EventBus eventBus) {
this.display = display;
this.bus = eventBus;
}
void finish() {
display.setWidget(view);
}
}
private static class Event extends GwtEvent<Handler> {
private static GwtEvent.Type<EventHandler> TYPE = new GwtEvent.Type<EventHandler>();
@Override
public GwtEvent.Type<Handler> getAssociatedType() {
throw new UnsupportedOperationException("Auto-generated method stub");
}
@Override
protected void dispatch(Handler handler) {
throw new UnsupportedOperationException("Auto-generated method stub");
}
}
private static class Handler implements EventHandler {
};
private static class MyDisplay implements AcceptsOneWidget {
IsWidget widget = null;
@Override
public void setWidget(IsWidget widget) {
this.widget = widget;
}
}
private static class MyPlace extends Place {
}
private static class MyView implements IsWidget {
@Override
public Widget asWidget() {
return null;
}
}
private static class SyncActivity implements Activity {
boolean canceled = false;
boolean stopped = false;
AcceptsOneWidget display;
String stopWarning;
MyView view;
EventBus bus;
SyncActivity(MyView view) {
this.view = view;
}
@Override
public String mayStop() {
return stopWarning;
}
@Override
public void onCancel() {
canceled = true;
}
@Override
public void onStop() {
stopped = true;
}
@Override
public void start(AcceptsOneWidget display, EventBus eventBus) {
this.display = display;
this.bus = eventBus;
display.setWidget(view);
}
}
private final MyPlace place1 = new MyPlace();
private final MyPlace place2 = new MyPlace();
private SyncActivity activity1 = new SyncActivity(new MyView());
private SyncActivity activity2 = new SyncActivity(new MyView());
private final MyDisplay realDisplay = new MyDisplay();
private final ActivityMapper myMap = new ActivityMapper() {
@Override
public Activity getActivity(Place place) {
if (place.equals(place1)) {
return activity1;
}
if (place.equals(place2)) {
return activity2;
}
return null;
}
};
private CountingEventBus eventBus = new CountingEventBus();
private ActivityManager manager = new ActivityManager(
myMap, eventBus);
public void testActiveEventBus() {
final AsyncActivity asyncActivity1 = new AsyncActivity(new MyView());
final AsyncActivity asyncActivity2 = new AsyncActivity(new MyView());
ActivityMapper map = new ActivityMapper() {
@Override
public Activity getActivity(Place place) {
if (place.equals(place1)) {
return asyncActivity1;
}
if (place.equals(place2)) {
return asyncActivity2;
}
return null;
}
};
manager = new ActivityManager(map, eventBus);
manager.setDisplay(realDisplay);
eventBus.fireEvent(new PlaceChangeEvent(place1));
com.google.web.bindery.event.shared.EventBus activeEventBus =
manager.getActiveEventBus();
activeEventBus.addHandler(Event.TYPE, new Handler());
assertEquals(1, eventBus.getCount(Event.TYPE));
eventBus.fireEvent(new PlaceChangeEvent(place2));
assertEquals(0, eventBus.getCount(Event.TYPE));
}
public void testAsyncDispatch() {
final AsyncActivity asyncActivity1 = new AsyncActivity(new MyView());
final AsyncActivity asyncActivity2 = new AsyncActivity(new MyView());
ActivityMapper map = new ActivityMapper() {
@Override
public Activity getActivity(Place place) {
if (place.equals(place1)) {
return asyncActivity1;
}
if (place.equals(place2)) {
return asyncActivity2;
}
return null;
}
};
manager = new ActivityManager(map, eventBus);
manager.setDisplay(realDisplay);
PlaceChangeRequestEvent event = new PlaceChangeRequestEvent(
place1);
eventBus.fireEvent(event);
assertNull(event.getWarning());
assertNull(realDisplay.widget);
assertFalse(asyncActivity1.stopped);
assertFalse(asyncActivity1.canceled);
assertNull(asyncActivity1.display);
eventBus.fireEvent(new PlaceChangeEvent(place1));
assertNull(realDisplay.widget);
assertFalse(asyncActivity1.stopped);
assertFalse(asyncActivity1.canceled);
assertNotNull(asyncActivity1.display);
asyncActivity1.finish();
assertEquals(asyncActivity1.view, realDisplay.widget);
assertFalse(asyncActivity1.stopped);
assertFalse(asyncActivity1.canceled);
event = new PlaceChangeRequestEvent(place2);
eventBus.fireEvent(event);
assertNull(event.getWarning());
assertEquals(asyncActivity1.view, realDisplay.widget);
assertFalse(asyncActivity1.stopped);
assertFalse(asyncActivity1.canceled);
assertFalse(asyncActivity2.stopped);
assertFalse(asyncActivity2.canceled);
assertNull(asyncActivity2.display);
eventBus.fireEvent(new PlaceChangeEvent(place2));
assertNull(realDisplay.widget);
assertFalse(asyncActivity1.canceled);
assertTrue(asyncActivity1.stopped);
assertFalse(asyncActivity2.stopped);
assertFalse(asyncActivity2.canceled);
assertNotNull(asyncActivity2.display);
asyncActivity2.finish();
assertEquals(asyncActivity2.view, realDisplay.widget);
}
public void testCancel() {
final AsyncActivity asyncActivity1 = new AsyncActivity(new MyView());
final AsyncActivity ayncActivity2 = new AsyncActivity(new MyView());
ActivityMapper map = new ActivityMapper() {
@Override
public Activity getActivity(Place place) {
if (place.equals(place1)) {
return asyncActivity1;
}
if (place.equals(place2)) {
return ayncActivity2;
}
return null;
}
};
manager = new ActivityManager(map, eventBus);
manager.setDisplay(realDisplay);
PlaceChangeRequestEvent event = new PlaceChangeRequestEvent(
place1);
eventBus.fireEvent(event);
assertNull(event.getWarning());
assertNull(realDisplay.widget);
assertFalse(asyncActivity1.stopped);
assertFalse(asyncActivity1.canceled);
assertNull(asyncActivity1.display);
eventBus.fireEvent(new PlaceChangeEvent(place1));
assertNull(realDisplay.widget);
assertFalse(asyncActivity1.stopped);
assertFalse(asyncActivity1.canceled);
assertNotNull(asyncActivity1.display);
event = new PlaceChangeRequestEvent(place2);
eventBus.fireEvent(event);
assertNull(event.getWarning());
assertNull(realDisplay.widget);
assertFalse(asyncActivity1.stopped);
assertFalse(asyncActivity1.canceled);
eventBus.fireEvent(new PlaceChangeEvent(place2));
assertNull(realDisplay.widget);
assertTrue(asyncActivity1.canceled);
assertFalse(asyncActivity1.stopped);
assertFalse(ayncActivity2.stopped);
assertFalse(ayncActivity2.canceled);
assertNotNull(ayncActivity2.display);
ayncActivity2.finish();
assertEquals(ayncActivity2.view, realDisplay.widget);
asyncActivity1.finish();
assertEquals(ayncActivity2.view, realDisplay.widget);
}
public void testDropHandlersOnStop() {
manager.setDisplay(realDisplay);
assertEquals(0, eventBus.getCount(Event.TYPE));
activity1 = new SyncActivity(null) {
@Override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
super.start(panel, eventBus);
bus.addHandler(Event.TYPE, new Handler());
}
@Override
public void onStop() {
super.onStop();
bus.addHandler(Event.TYPE, new Handler());
}
};
PlaceChangeEvent event = new PlaceChangeEvent(place1);
eventBus.fireEvent(event);
assertEquals(1, eventBus.getCount(Event.TYPE));
event = new PlaceChangeEvent(place2);
eventBus.fireEvent(event);
assertEquals(0, eventBus.getCount(Event.TYPE));
// Make sure we didn't nuke the ActivityManager's own handlers
assertEquals(1, eventBus.getCount(PlaceChangeEvent.TYPE));
assertEquals(1, eventBus.getCount(PlaceChangeRequestEvent.TYPE));
}
public void testEventSetupAndTeardown() {
assertEquals(0, eventBus.getCount(PlaceChangeEvent.TYPE));
assertEquals(0, eventBus.getCount(PlaceChangeRequestEvent.TYPE));
manager.setDisplay(realDisplay);
assertEquals(1, eventBus.getCount(PlaceChangeEvent.TYPE));
assertEquals(1, eventBus.getCount(PlaceChangeRequestEvent.TYPE));
manager.setDisplay(null);
assertEquals(0, eventBus.getCount(PlaceChangeEvent.TYPE));
assertEquals(0, eventBus.getCount(PlaceChangeRequestEvent.TYPE));
}
public void testExceptionsOnStartAndCancel() {
activity1 = new AsyncActivity(null) {
@Override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
super.start(panel, eventBus);
bus.addHandler(Event.TYPE, new Handler());
}
@Override
public void onCancel() {
super.onCancel();
bus.addHandler(Event.TYPE, new Handler());
throw new UnsupportedOperationException("Exception on cancel");
}
};
activity2 = new SyncActivity(null) {
@Override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
super.start(panel, eventBus);
throw new UnsupportedOperationException("Exception on start");
}
};
manager.setDisplay(realDisplay);
try {
PlaceChangeEvent event = new PlaceChangeEvent(place1);
eventBus.fireEvent(event);
assertEquals(1, eventBus.getCount(Event.TYPE));
event = new PlaceChangeEvent(place2);
eventBus.fireEvent(event);
fail("Expected exception");
} catch (UmbrellaException e) {
// EventBus throws this one
assertEquals(1, e.getCauses().size());
// And this is the one thrown by ActivityManager
UmbrellaException nested = (UmbrellaException) e.getCause();
assertEquals(2, nested.getCauses().size());
}
assertTrue(activity1.canceled);
assertNotNull(activity2.display);
assertEquals(0, eventBus.getCount(Event.TYPE));
}
public void testExceptionsOnStopAndStart() {
activity1 = new SyncActivity(null) {
@Override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
super.start(panel, eventBus);
bus.addHandler(Event.TYPE, new Handler());
}
@Override
public void onStop() {
super.onStop();
bus.addHandler(Event.TYPE, new Handler());
throw new UnsupportedOperationException("Exception on stop");
}
};
activity2 = new SyncActivity(null) {
@Override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
super.start(panel, eventBus);
throw new UnsupportedOperationException("Exception on start");
}
};
manager.setDisplay(realDisplay);
try {
PlaceChangeEvent event = new PlaceChangeEvent(place1);
eventBus.fireEvent(event);
assertEquals(1, eventBus.getCount(Event.TYPE));
event = new PlaceChangeEvent(place2);
eventBus.fireEvent(event);
fail("Expected exception");
} catch (UmbrellaException e) {
// EventBus throws this one
assertEquals(1, e.getCauses().size());
// And this is the one thrown by ActivityManager
UmbrellaException nested = (UmbrellaException) e.getCause();
assertEquals(2, nested.getCauses().size());
}
assertTrue(activity1.stopped);
assertNotNull(activity2.display);
assertEquals(0, eventBus.getCount(Event.TYPE));
}
/**
* @see http://code.google.com/p/google-web-toolkit/issues/detail?id=5375
*/
public void testNullDisplayOnPlaceChange() {
manager.setDisplay(realDisplay);
// Start an activity
manager.onPlaceChange(new PlaceChangeEvent(place1));
/*
* Now we're going to place2. During PlaceChangeEvent dispatch,
* someone kills the manager's display.
*/
manager.setDisplay(null);
// Now the place change event reaches the manager
manager.onPlaceChange(new PlaceChangeEvent(place2));
assertNull(activity2.display);
assertTrue(activity1.stopped);
}
public void testNullDisplayBeforeAsyncStart() {
final AsyncActivity asyncActivity1 = new AsyncActivity(new MyView());
final AsyncActivity asyncActivity2 = new AsyncActivity(new MyView());
ActivityMapper map = new ActivityMapper() {
@Override
public Activity getActivity(Place place) {
if (place.equals(place1)) {
return asyncActivity1;
}
if (place.equals(place2)) {
return asyncActivity2;
}
return null;
}
};
manager = new ActivityManager(map, eventBus);
manager.setDisplay(realDisplay);
// Start an activity
manager.onPlaceChange(new PlaceChangeEvent(place1));
// Kill the manager
manager.setDisplay(null);
// The activity is ready to play
asyncActivity1.finish();
// Ta da, no NPE
}
public void testRejected() {
manager.setDisplay(realDisplay);
activity1.stopWarning = "Stop fool!";
PlaceChangeRequestEvent event = new PlaceChangeRequestEvent(
place1);
eventBus.fireEvent(event);
assertNull(event.getWarning());
assertNull(realDisplay.widget);
eventBus.fireEvent(new PlaceChangeEvent(place1));
assertEquals(activity1.view, realDisplay.widget);
event = new PlaceChangeRequestEvent(place2);
eventBus.fireEvent(event);
assertEquals(activity1.stopWarning, event.getWarning());
assertEquals(activity1.view, realDisplay.widget);
assertFalse(activity1.stopped);
assertFalse(activity1.canceled);
}
public void testSyncDispatch() {
manager.setDisplay(realDisplay);
PlaceChangeRequestEvent event = new PlaceChangeRequestEvent(
place1);
eventBus.fireEvent(event);
assertNull(event.getWarning());
assertNull(realDisplay.widget);
assertFalse(activity1.stopped);
assertFalse(activity1.canceled);
eventBus.fireEvent(new PlaceChangeEvent(place1));
assertEquals(activity1.view, realDisplay.widget);
assertFalse(activity1.stopped);
assertFalse(activity1.canceled);
event = new PlaceChangeRequestEvent(place2);
eventBus.fireEvent(event);
assertNull(event.getWarning());
assertEquals(activity1.view, realDisplay.widget);
assertFalse(activity1.stopped);
assertFalse(activity1.canceled);
eventBus.fireEvent(new PlaceChangeEvent(place2));
assertEquals(activity2.view, realDisplay.widget);
assertTrue(activity1.stopped);
assertFalse(activity1.canceled);
}
/**
* Non-regression test: make sure an activity can call {@link AcceptsOneWidget#setWidget(IsWidget)} several times to switch views.
*/
public void testSetWidgetSeveralTimesPerActivity() {
class TwoViewActivity extends SyncActivity {
MyView view2;
public TwoViewActivity(MyView view1, MyView view2) {
super(view1);
this.view2 = view2;
}
void secondView() {
display.setWidget(view2);
}
void firstView() {
display.setWidget(view);
}
}
final TwoViewActivity activity = new TwoViewActivity(new MyView(), new MyView());
ActivityMapper map = new ActivityMapper() {
@Override
public Activity getActivity(Place place) {
return activity;
}
};
manager = new ActivityManager(map, eventBus);
manager.setDisplay(realDisplay);
// Start an activity
manager.onPlaceChange(new PlaceChangeEvent(place1));
assertEquals(activity.view, realDisplay.widget);
// Call setWidget on the display several times, just to make sure it's possible
activity.secondView();
assertEquals(activity.view2, realDisplay.widget);
activity.firstView();
assertEquals(activity.view, realDisplay.widget);
activity.secondView();
assertEquals(activity.view2, realDisplay.widget);
}
}