/*
* Copyright (C) 2011 Red Hat, Inc. and/or its affiliates.
*
* 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 org.jboss.errai.bus.common;
import static java.lang.Math.abs;
import static org.jboss.errai.bus.common.FloatUtil.DEFAULT_PRECISION;
import static org.jboss.errai.bus.common.FloatUtil.maxSignifigantDigitIndex;
import static org.jboss.errai.bus.common.FloatUtil.mostSignifigantDigitIndex;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.errai.bus.client.ErraiBus;
import org.jboss.errai.bus.client.api.ClientMessageBus;
import org.jboss.errai.common.client.api.extension.InitVotes;
import org.jboss.errai.common.client.api.tasks.ClientTaskManager;
import org.jboss.errai.common.client.api.tasks.TaskManager;
import org.jboss.errai.common.client.api.tasks.TaskManagerFactory;
import org.jboss.errai.common.client.api.tasks.TaskManagerProvider;
import org.jboss.errai.common.client.logging.LoggingHandlerConfigurator;
import org.jboss.errai.common.client.logging.handlers.ErraiSystemLogHandler;
import org.slf4j.LoggerFactory;
import com.google.gwt.core.client.GWT;
import com.google.gwt.junit.client.GWTTestCase;
/**
* Base test class for testing ErraiBus-based code. Located in the main distribution so it can be extended
* by other modules.
*/
public abstract class AbstractErraiTest extends GWTTestCase {
protected static ClientMessageBus bus;
protected static final void assertFloatArrayEquals(final float[] a, final float[] b) {
if (a == null || b == null) {
assertTrue(failMessage(a, b), a == null && b == null);
}
else if (a.length != b.length) {
fail(failMessage(a, b));
}
else {
for (int i = 0; i < a.length; i++) {
assertApproximatelyEqual(a[i], b[i]);
}
}
}
protected static final void assertFloatArrayEquals(final Float[] a, final Float[] b) {
if (a == null || b == null) {
assertTrue(failMessage(a, b), a == null && b == null);
}
else if (a.length != b.length) {
fail(failMessage(a, b));
}
else {
for (int i = 0; i < a.length; i++) {
assertApproximatelyEqual(a[i], b[i]);
}
}
}
protected static final void assertDoubleArrayEquals(final double[] a, final double[] b) {
if (a == null || b == null) {
assertTrue(failMessage(a, b), a == null && b == null);
}
else if (a.length != b.length) {
fail(failMessage(a, b));
}
else {
for (int i = 0; i < a.length; i++) {
assertApproximatelyEqual(a[i], b[i]);
}
}
}
protected static final void assertDoubleArrayEquals(final Double[] a, final Double[] b) {
if (a == null || b == null) {
assertTrue(failMessage(a, b), a == null && b == null);
}
else if (a.length != b.length) {
fail(failMessage(a, b));
}
else {
for (int i = 0; i < a.length; i++) {
assertApproximatelyEqual(a[i], b[i]);
}
}
}
protected static final void assertFloatListEquals(final List<Float> a, final List<Float> b) {
if (a == null || b == null) {
assertTrue(failMessage(a, b), a == null && b == null);
}
else if (a.size() != b.size()) {
fail(failMessage(a, b));
}
else {
for (int i = 0; i < a.size(); i++) {
assertApproximatelyEqual(a.get(i), b.get(i));
}
}
}
protected static final <K> void assertFloatMapEquals(final Map<K, Float> a, final Map<K, Float> b) {
if (a == null || b == null) {
assertSame(a, b);
return;
}
assertEquals(a.size(), b.size());
for (final Entry<K, Float> entry : a.entrySet()) {
assertTrue(b.containsKey(entry.getKey()));
final Float aVal = entry.getValue();
final Float bVal = b.get(entry.getKey());
if (aVal == null || bVal == null) {
assertSame(aVal, bVal);
}
else {
assertApproximatelyEqual(aVal, bVal);
}
}
}
protected static void assertApproximatelyEqual(final Float a, final Float b) {
if (a == null || b == null) {
assertSame(a, b);
}
else {
assertApproximatelyEqual(a.floatValue(), b.floatValue());
}
}
protected static void assertApproximatelyEqual(final float a, final float b) {
if (Float.isNaN(a) || Float.isNaN(b)) {
assertNotXor(Float.isNaN(a), Float.isNaN(b));
}
else if (Float.isInfinite(a) || Float.isInfinite(b)) {
assertNotXor(Float.POSITIVE_INFINITY == a, Float.POSITIVE_INFINITY == b);
assertNotXor(Float.NEGATIVE_INFINITY == a, Float.NEGATIVE_INFINITY == b);
}
else {
final int maxSigDigitIndex = maxSignifigantDigitIndex(a, b);
final float absoluteDifference = abs(a - b);
final int differenceSigDigitIndex = mostSignifigantDigitIndex(absoluteDifference);
assertTrue("Assertion failed: |" + a + " - " + b + "| = " + absoluteDifference,
maxSigDigitIndex > differenceSigDigitIndex
&& maxSigDigitIndex - differenceSigDigitIndex >= DEFAULT_PRECISION);
}
}
protected static void assertApproximatelyEqual(final Double a, final Double b) {
if (a == null || b == null) {
assertSame(a, b);
}
else {
assertApproximatelyEqual(a.doubleValue(), b.doubleValue());
}
}
private static void assertApproximatelyEqual(final double a, final double b) {
if (Double.isNaN(a) || Double.isNaN(b)) {
assertNotXor(Double.isNaN(a), Double.isNaN(b));
}
else if (Double.isInfinite(a) || Double.isInfinite(b)) {
assertNotXor(Double.POSITIVE_INFINITY == a, Double.POSITIVE_INFINITY == b);
assertNotXor(Double.NEGATIVE_INFINITY == a, Double.NEGATIVE_INFINITY == b);
}
else {
final int maxSigDigitIndex = maxSignifigantDigitIndex(a, b);
final double absoluteDifference = abs(a - b);
final int differenceSigDigitIndex = mostSignifigantDigitIndex(absoluteDifference);
assertTrue("Assertion failed: |" + a + " - " + b + "| = " + absoluteDifference,
maxSigDigitIndex > differenceSigDigitIndex
&& maxSigDigitIndex - differenceSigDigitIndex >= DEFAULT_PRECISION);
}
}
private static void assertNotXor(final boolean a, final boolean b) {
assertFalse(a ^ b);
}
/**
* Formats a failure message of the form "expected: <i>expect</i>; but was: <i>got</i>". Does not
* cause a test failure. You still have to call Assert.fail() if you want that.
*
* @param expect
* The expected value.
* @param got
* The actual value.
*
* @return A new String as described above.
*/
protected static String failMessage(final Object expect, final Object got) {
return "expected: " + expect + "; but was: " + got;
}
protected org.slf4j.Logger logger;
static {
System.out.println("REMEMBER! Bus tests will not succeed if: \n" +
"1. You do not run the unit tests with the flag: -Dorg.jboss.errai.bus.do_long_poll=false \n" +
"2. You do not have the main and test source directories in the runtime classpath");
}
@Override
protected void gwtSetUp() throws Exception {
// Only setup handlers for first test.
if (LoggingHandlerConfigurator.get() == null) {
GWT.log("Initializing Logging for tests.");
// Cannot use console logger in non-production compiled tests.
new LoggingHandlerConfigurator().onModuleLoad();
if (!GWT.isScript()) {
GWT.log("Tests not running as a compiled script: disabling all but system handler.");
final Handler[] handlers = Logger.getLogger("").getHandlers();
for (final Handler handler : handlers) {
handler.setLevel(Level.OFF);
}
LoggingHandlerConfigurator.get().getHandler(ErraiSystemLogHandler.class).setLevel(Level.ALL);
}
}
logger = LoggerFactory.getLogger(getClass());
bus = (ClientMessageBus) ErraiBus.get();
InitVotes.setTimeoutMillis(60000);
if (!(TaskManagerFactory.get() instanceof ClientTaskManager)) {
TaskManagerFactory.setTaskManagerProvider(new TaskManagerProvider() {
private final ClientTaskManager clientTaskManager = new ClientTaskManager();
@Override
public TaskManager get() {
return clientTaskManager;
}
});
}
logger.info("Starting InitVotes polling from gwtSetup...");
InitVotes.startInitPolling();
}
@Override
protected void gwtTearDown() throws Exception {
try {
logger.info("Stopping bus in gwtTearDown...");
bus.stop(true);
logger.info("Resetting InitVotes in gwtTearDown...");
InitVotes.reset();
} catch (final Throwable t) {
logger.error("Encountered an error in gwtTearDown.", t);
throw t;
}
}
/**
* Invokes the given Runnable after the bus has finished initializing (it's
* online and connected to the server). The test timeout is 45 seconds.
* <p/>
* You must call {@link #finishTest()} within your runnable, or the test will
* time out.
*
* @param r
* the stuff to run once the bus is online.
*/
protected void runAfterInit(final Runnable r) {
runAfterInit(45000, r);
}
/**
* Invokes the given Runnable after the bus has finished initializing (it's
* online and connected to the server).
* <p/>
* You must call {@link #finishTest()} within your runnable before the given
* timeout has elapsed, or the test will fail with a time out.
*
* @param r
* the stuff to run once the bus is online.
*/
protected void runAfterInit(final int timeoutMillis, final Runnable r) {
delayTestFinish(timeoutMillis);
InitVotes.registerOneTimeInitCallback(r);
}
}