/*
* 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.cedarsolutions.client.gwt.custom.table;
import java.util.Set;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
/**
* Base class for testing {@link Cell}.
*
* @param <T> the cell type
*/
public abstract class CellTestBase<T> extends GWTTestCase {
/**
* A mock cell used for testing.
*
* @param <T> the cell type
*/
static class MockCell<T> extends AbstractCell<T> {
private final boolean isSelectable;
private Context lastContext;
private T lastEventValue;
private Element lastParentElement;
private final T updateValue;
public MockCell(boolean isSelectable, T updateValue,
String... consumedEvents) {
super(consumedEvents);
this.isSelectable = isSelectable;
this.updateValue = updateValue;
}
public void assertLastEventValue(T expected) {
assertEquals(expected, lastEventValue);
}
public void assertLastParentElement(Element expected) {
assertEquals(expected, lastParentElement);
}
@Override
public boolean dependsOnSelection() {
return isSelectable;
}
public Context getLastContext() {
return lastContext;
}
@Override
public boolean handlesSelection() {
return isSelectable;
}
@Override
public void onBrowserEvent(Context context, Element parent, T value,
NativeEvent event, ValueUpdater<T> valueUpdater) {
lastContext = context;
lastParentElement = parent;
lastEventValue = value;
if (valueUpdater != null) {
valueUpdater.update(updateValue);
}
}
@Override
public void render(Context context, T value, SafeHtmlBuilder sb) {
lastContext = context;
if (value != null) {
sb.appendEscaped(String.valueOf(value));
}
}
}
/**
* A mock {@link ValueUpdater} used for testing.
*/
class MockValueUpdater implements ValueUpdater<T> {
private T lastValue;
public void assertLastValue(T expected) {
assertEquals(expected, lastValue);
lastValue = null;
}
public void update(T value) {
assertNull(lastValue);
assertNotNull(value);
this.lastValue = value;
}
}
/**
* The default row value key used for all tests.
*/
protected static final Object DEFAULT_KEY = new Object();
// Modified for CedarCommon
@Override
public String getModuleName() {
return "com.cedarsolutions.CedarCommon";
}
public void testDependsOnSelection() {
assertEquals(dependsOnSelection(), createCell().dependsOnSelection());
}
public void testGetConsumedEvents() {
Set<String> consumedEvents = createCell().getConsumedEvents();
String[] expected = getConsumedEvents();
if (consumedEvents == null && expected == null) {
return;
}
assertEquals(expected.length, consumedEvents.size());
for (String typeName : expected) {
assertTrue(consumedEvents.contains(typeName));
}
}
public void testHandlesSelection() {
// None of the provided cells handle selection.
assertFalse(createCell().handlesSelection());
}
/**
* Test rendering the cell with a valid value and no view data.
*/
public void testRender() {
Cell<T> cell = createCell();
T value = createCellValue();
SafeHtmlBuilder sb = new SafeHtmlBuilder();
Context context = new Context(0, 0, null);
cell.render(context, value, sb);
assertEquals(getExpectedInnerHtml(), sb.toSafeHtml().asString());
}
/**
* Test rendering the cell with a negative index is handled.
*/
public void testRenderNegativeIndex() {
Cell<T> cell = createCell();
T value = createCellValue();
SafeHtmlBuilder sb = new SafeHtmlBuilder();
Context context = new Context(-1, -1, null);
cell.render(context, value, sb);
assertEquals(getExpectedInnerHtml(), sb.toSafeHtml().asString());
}
/**
* Test rendering the cell with a null value and no view data.
*/
public void testRenderNull() {
Cell<T> cell = createCell();
SafeHtmlBuilder sb = new SafeHtmlBuilder();
Context context = new Context(0, 0, null);
cell.render(context, null, sb);
assertEquals(getExpectedInnerHtmlNull(), sb.toSafeHtml().asString());
}
/**
* Create a new cell to test.
*
* @return the new cell
*/
protected abstract Cell<T> createCell();
/**
* Create a value to test.
*
* @return the cell value
*/
protected abstract T createCellValue();
/**
* Does the cell type depend on selection? Default to false.
*
* @return true expected value of dependsOnSelection
*/
protected abstract boolean dependsOnSelection();
/**
* Get the expected events that the cell should consume.
*
* @return the consumed events.
*/
protected abstract String[] getConsumedEvents();
/**
* Get the expected inner HTML value of the rendered cell.
*
* @return the expected string
*/
protected abstract String getExpectedInnerHtml();
/**
* Get the expected inner HTML value of the rendered cell when null is passed
* as the cell value.
*
* @return the expected string
*/
protected abstract String getExpectedInnerHtmlNull();
/**
* Test
* {@link Cell#onBrowserEvent(Element, Object, Object, NativeEvent, ValueUpdater)}
* with the specified conditions.
*
* @param startHtml the innerHTML of the cell before the test starts
* @param event the event to fire
* @param value the cell value
* @param expectedValue the expected value passed to the value updater, or
* null if none expected
* @return the parent element
*/
protected Element testOnBrowserEvent(String startHtml, NativeEvent event, final T value,
T expectedValue) {
return testOnBrowserEvent(createCell(), startHtml, event, value, expectedValue, true);
}
/**
* Test
* {@link Cell#onBrowserEvent(Element, Object, Object, NativeEvent, ValueUpdater)}
* with the specified conditions.
*
* @param cell the cell to use
* @param startHtml the innerHTML of the cell before the test starts
* @param event the event to fire
* @param value the cell value
* @param expectedValue the expected value passed to the value updater, or
* null if none expected
* @param dispatchToFirstChild true to dispatch to the first child of the
* rendered parent element, if one is available
* @return the parent element
*/
protected Element testOnBrowserEvent(final Cell<T> cell, String startHtml, NativeEvent event,
final T value, T expectedValue, boolean dispatchToFirstChild) {
// Setup the parent element.
final com.google.gwt.user.client.Element parent = Document.get().createDivElement().cast();
parent.setInnerHTML(startHtml);
Document.get().getBody().appendChild(parent);
// If the element has a child, use it as the event target.
Element target = parent;
if (dispatchToFirstChild) {
Element child = parent.getFirstChildElement();
target = (child == null) ? parent : child;
}
// Pass the event to the cell.
final MockValueUpdater valueUpdater = new MockValueUpdater();
Event.setEventListener(parent, new EventListener() {
public void onBrowserEvent(Event event) {
try {
DOM.setEventListener(parent, null);
Context context = new Context(0, 0, DEFAULT_KEY);
cell.onBrowserEvent(context, parent, value, event, valueUpdater);
parent.removeFromParent();
} catch (Exception e) {
// We are in an event loop, so events may not propagate out to JUnit.
fail("An exception occured while handling the event: " + e.getMessage());
}
}
});
Event.sinkEvents(target, Event.getTypeInt(event.getType()));
target.dispatchEvent(event);
assertNull(DOM.getEventListener(parent));
// Check the expected value and view data.
valueUpdater.assertLastValue(expectedValue);
return parent;
}
}