// Copyright 2012 Google Inc. All Rights Reserved.
//
// 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.collide.client.history;
import static com.google.collide.client.history.MockPlaces.CHILD_A;
import static com.google.collide.client.history.MockPlaces.CHILD_A_NAV;
import static com.google.collide.client.history.MockPlaces.GRANDCHILD_A;
import static com.google.collide.client.history.MockPlaces.GRANDCHILD_A_NAV;
import static com.google.collide.client.history.MockPlaces.PARENT_A;
import static com.google.collide.client.history.MockPlaces.PARENT_A_NAV;
import static com.google.collide.client.history.MockPlaces.PARENT_B;
import static com.google.collide.client.history.MockPlaces.PARENT_B_NAV;
import com.google.collide.client.history.MockPlaces.MockChildPlaceA;
import com.google.collide.client.history.MockPlaces.MockParentPlaceA;
import com.google.collide.client.history.MockPlaces.MockParentPlaceB;
import com.google.collide.clientlibs.navigation.NavigationToken;
import com.google.collide.json.shared.JsonArray;
import com.google.collide.shared.util.JsonCollections;
import com.google.gwt.junit.client.GWTTestCase;
/**
* Tests our implementation of Hierarchical history as implemented in
* {@link Place}.
*/
public class PlaceTest extends GWTTestCase {
@Override
public String getModuleName() {
return "com.google.collide.client.TestCode";
}
@Override
protected void gwtSetUp() throws Exception {
super.gwtSetUp();
// Reset the Root scope, since that isn't done automatically.
RootPlace.PLACE.resetScope();
// Reset the handler invocation counts.
MockPlaces.resetCounts();
RootPlace.PLACE.registerChildHandler(PARENT_A, PARENT_A_NAV);
RootPlace.PLACE.registerChildHandler(PARENT_B, PARENT_B_NAV);
}
/**
* Tests that we can dispatch a line of {@link NavigationToken}s parsed from the
* History string
*/
public void testDispatchHistory() {
// Build up a History String of Root/ParentA/ChildA, that looks like
// "/h/mockparenta=(someString=foo)/mockchilda=(someString=foo,someNumber=42)/"
String historyString =
HistoryUtils.createHistoryString(JsonCollections.<NavigationToken>createArray(
PARENT_A.createNavigationEvent("foo"), CHILD_A.createNavigationEvent("foo", 42),
GRANDCHILD_A.createNavigationEvent()));
JsonArray<NavigationToken> historyPieces = HistoryUtils.parseHistoryString(historyString);
// Bring the state of the app in line with the History String.
RootPlace.PLACE.dispatchHistory(historyPieces);
// Examine the state of the world.
assertTrue(RootPlace.PLACE.isActive());
assertTrue(PARENT_A.isActive());
assertFalse(PARENT_B.isActive());
assertEquals(1, PARENT_A_NAV.getEnterCount());
assertEquals(0, PARENT_A_NAV.getReEnterCount());
assertEquals(0, PARENT_B_NAV.getEnterCount());
assertEquals(0, PARENT_B_NAV.getReEnterCount());
assertTrue(CHILD_A.isActive());
assertEquals(1, CHILD_A_NAV.getEnterCount());
assertEquals(0, CHILD_A_NAV.getReEnterCount());
assertTrue(GRANDCHILD_A.isActive());
assertEquals(1, GRANDCHILD_A_NAV.getEnterCount());
assertEquals(0, GRANDCHILD_A_NAV.getReEnterCount());
}
public void testMultipleHandlers() {
MockParentPlaceA.NavigationHandler nav2 = new MockParentPlaceA.NavigationHandler();
RootPlace.PLACE.registerChildHandler(PARENT_A, nav2);
MockParentPlaceA.NavigationEvent navEvent = PARENT_A.createNavigationEvent("asdf");
RootPlace.PLACE.fireChildPlaceNavigation(navEvent);
// Verify both handlers got called
assertTrue(PARENT_A.isActive());
assertEquals(1, PARENT_A_NAV.getEnterCount());
assertEquals(0, PARENT_A_NAV.getReEnterCount());
assertEquals(0, PARENT_A_NAV.getCleanupCount());
assertEquals(1, nav2.getEnterCount());
// Navigate away
MockParentPlaceB.NavigationEvent parentBNavEvent = PARENT_B.createNavigationEvent();
RootPlace.PLACE.fireChildPlaceNavigation(parentBNavEvent);
// Verify that both cleanup handlers were called
assertFalse(PARENT_A.isActive());
assertEquals(1, PARENT_A_NAV.getCleanupCount());
assertEquals(1, nav2.getCleanupCount());
}
/**
* Tests navigating to a child Place.
*/
public void testNavigateToChildPlace() {
String someString = "foo";
int someNumber = 42;
// Lets trigger a navigation to Parent B.
MockParentPlaceB.NavigationEvent parentBNavEvent = PARENT_B.createNavigationEvent();
RootPlace.PLACE.fireChildPlaceNavigation(parentBNavEvent);
// Verify we went to Parent B from Root.
assertTrue(PARENT_B.isActive());
assertEquals(1, PARENT_B_NAV.getEnterCount());
assertEquals(0, PARENT_B_NAV.getReEnterCount());
assertEquals(0, PARENT_B_NAV.getCleanupCount());
// Try to get to Child A from Parent B. We know that this should not be
// possible.
MockChildPlaceA.NavigationEvent childNavEvent =
CHILD_A.createNavigationEvent(someString, someNumber);
PARENT_B.fireChildPlaceNavigation(childNavEvent);
// We should still have not done the navigation.
assertFalse(CHILD_A.isActive());
assertEquals(0, CHILD_A_NAV.getEnterCount());
assertEquals(0, CHILD_A_NAV.getReEnterCount());
// Lets trigger a navigation to Parent A.
MockParentPlaceA.NavigationEvent parentANavEvent = PARENT_A.createNavigationEvent(someString);
RootPlace.PLACE.fireChildPlaceNavigation(parentANavEvent);
// Verify we are no longer in B and that we did not change any of the
// handler invocation counts
assertFalse(PARENT_B.isActive());
assertEquals(1, PARENT_B_NAV.getCleanupCount());
assertFalse(CHILD_A.isActive());
assertEquals(1, PARENT_B_NAV.getEnterCount());
assertEquals(0, CHILD_A_NAV.getEnterCount());
assertEquals(0, CHILD_A_NAV.getReEnterCount());
// Verify that we are in Parent A.
assertTrue(PARENT_A.isActive());
assertEquals(1, PARENT_A_NAV.getEnterCount());
// Try to get to Child A from Parent A.
PARENT_A.fireChildPlaceNavigation(childNavEvent);
// We should now be in A.
assertTrue(CHILD_A.isActive());
assertEquals(1, CHILD_A_NAV.getEnterCount());
assertEquals(0, CHILD_A_NAV.getReEnterCount());
// Verify the other Places did not get weird.
assertTrue(RootPlace.PLACE.isActive());
assertTrue(PARENT_A.isActive());
assertFalse(PARENT_B.isActive());
assertEquals(1, PARENT_A_NAV.getEnterCount());
assertEquals(0, PARENT_A_NAV.getReEnterCount());
assertEquals(1, PARENT_B_NAV.getEnterCount());
assertEquals(0, PARENT_B_NAV.getReEnterCount());
assertEquals(1, PARENT_B_NAV.getCleanupCount());
}
/**
* Tests navigating to a child Place when on a Parent place is not active.
*/
public void testNavigateToChildPlaceNotActive() {
// Try to get to Child A from Parent A when Parent A is not active.
MockChildPlaceA.NavigationEvent childNavEvent = CHILD_A.createNavigationEvent("foo", 42);
PARENT_A.fireChildPlaceNavigation(childNavEvent);
// We should have not done the navigation.
assertEquals(0, CHILD_A_NAV.getEnterCount());
assertEquals(0, CHILD_A_NAV.getReEnterCount());
}
public void testNavigateToSamePlace() {
// Lets trigger a navigation to Parent B.
MockParentPlaceA.NavigationEvent parentANavEvent = PARENT_A.createNavigationEvent("foo");
RootPlace.PLACE.fireChildPlaceNavigation(parentANavEvent);
// Verify we went to Parent B from Root.
assertTrue(PARENT_A.isActive());
assertEquals(1, PARENT_A_NAV.getEnterCount());
assertEquals(0, PARENT_A_NAV.getReEnterCount());
assertEquals(0, PARENT_A_NAV.getCleanupCount());
RootPlace.PLACE.fireChildPlaceNavigation(PARENT_A.createNavigationEvent("foo"));
// Verify that we didn't double navigate, but rather did a re-entrant
// dispatch that did not deliver any new state.
assertTrue(PARENT_A.isActive());
assertEquals(1, PARENT_A_NAV.getEnterCount());
assertEquals(1, PARENT_A_NAV.getReEnterCount());
assertFalse(PARENT_A_NAV.hadNewState());
assertEquals(0, PARENT_A_NAV.getCleanupCount());
// Now try again with different params to the event
RootPlace.PLACE.fireChildPlaceNavigation(PARENT_A.createNavigationEvent("bar"));
// Verify that we re-entrantly dispatched and had some new state.
assertTrue(PARENT_A.isActive());
assertEquals(1, PARENT_A_NAV.getEnterCount());
assertEquals(2, PARENT_A_NAV.getReEnterCount());
assertTrue(PARENT_A_NAV.hadNewState());
assertEquals(0, PARENT_A_NAV.getCleanupCount());
}
}