michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko; michael@0: michael@0: import java.util.LinkedList; michael@0: michael@0: import android.os.SystemClock; michael@0: michael@0: public class FennecMochitestAssert implements Assert { michael@0: private LinkedList mTestList = new LinkedList(); michael@0: michael@0: // Internal state variables to make logging match up with existing mochitests michael@0: private int mLineNumber = 0; michael@0: private int mPassed = 0; michael@0: private int mFailed = 0; michael@0: private int mTodo = 0; michael@0: michael@0: // Used to write the first line of the test file michael@0: private boolean mLogStarted = false; michael@0: michael@0: // Used to write the test-start/test-end log lines michael@0: private String mLogTestName = ""; michael@0: michael@0: // Measure the time it takes to run test case michael@0: private long mStartTime = 0; michael@0: michael@0: public FennecMochitestAssert() { michael@0: } michael@0: michael@0: /** Write information to a logfile and logcat */ michael@0: public void dumpLog(String message) { michael@0: FennecNativeDriver.log(FennecNativeDriver.LogLevel.INFO, message); michael@0: } michael@0: michael@0: /** Write information to a logfile and logcat */ michael@0: public void dumpLog(String message, Throwable t) { michael@0: FennecNativeDriver.log(FennecNativeDriver.LogLevel.INFO, message, t); michael@0: } michael@0: michael@0: /** Set the filename used for dumpLog. */ michael@0: public void setLogFile(String filename) { michael@0: FennecNativeDriver.setLogFile(filename); michael@0: michael@0: String message; michael@0: if (!mLogStarted) { michael@0: dumpLog(Integer.toString(mLineNumber++) + " INFO SimpleTest START"); michael@0: mLogStarted = true; michael@0: } michael@0: michael@0: if (mLogTestName != "") { michael@0: long diff = SystemClock.uptimeMillis() - mStartTime; michael@0: message = Integer.toString(mLineNumber++) + " INFO TEST-END | " + mLogTestName; michael@0: message += " | finished in " + diff + "ms"; michael@0: dumpLog(message); michael@0: mLogTestName = ""; michael@0: } michael@0: } michael@0: michael@0: public void setTestName(String testName) { michael@0: String[] nameParts = testName.split("\\."); michael@0: mLogTestName = nameParts[nameParts.length - 1]; michael@0: mStartTime = SystemClock.uptimeMillis(); michael@0: michael@0: dumpLog(Integer.toString(mLineNumber++) + " INFO TEST-START | " + mLogTestName); michael@0: } michael@0: michael@0: class testInfo { michael@0: public boolean mResult; michael@0: public String mName; michael@0: public String mDiag; michael@0: public boolean mTodo; michael@0: public boolean mInfo; michael@0: public testInfo(boolean r, String n, String d, boolean t, boolean i) { michael@0: mResult = r; michael@0: mName = n; michael@0: mDiag = d; michael@0: mTodo = t; michael@0: mInfo = i; michael@0: } michael@0: michael@0: } michael@0: michael@0: private void _logMochitestResult(testInfo test, String passString, String failString) { michael@0: boolean isError = true; michael@0: String resultString = failString; michael@0: if (test.mResult || test.mTodo) { michael@0: isError = false; michael@0: } michael@0: if (test.mResult) michael@0: { michael@0: resultString = passString; michael@0: } michael@0: String diag = test.mName; michael@0: if (test.mDiag != null) diag += " - " + test.mDiag; michael@0: michael@0: String message = Integer.toString(mLineNumber++) + " INFO " + resultString + " | " + mLogTestName + " | " + diag; michael@0: dumpLog(message); michael@0: michael@0: if (test.mInfo) { michael@0: // do not count TEST-INFO messages michael@0: } else if (test.mTodo) { michael@0: mTodo++; michael@0: } else if (isError) { michael@0: mFailed++; michael@0: } else { michael@0: mPassed++; michael@0: } michael@0: if (isError) { michael@0: junit.framework.Assert.fail(message); michael@0: } michael@0: } michael@0: michael@0: public void endTest() { michael@0: String message; michael@0: michael@0: if (mLogTestName != "") { michael@0: long diff = SystemClock.uptimeMillis() - mStartTime; michael@0: message = Integer.toString(mLineNumber++) + " INFO TEST-END | " + mLogTestName; michael@0: message += " | finished in " + diff + "ms"; michael@0: dumpLog(message); michael@0: mLogTestName = ""; michael@0: } michael@0: michael@0: message = Integer.toString(mLineNumber++) + " INFO TEST-START | Shutdown"; michael@0: dumpLog(message); michael@0: message = Integer.toString(mLineNumber++) + " INFO Passed: " + Integer.toString(mPassed); michael@0: dumpLog(message); michael@0: message = Integer.toString(mLineNumber++) + " INFO Failed: " + Integer.toString(mFailed); michael@0: dumpLog(message); michael@0: message = Integer.toString(mLineNumber++) + " INFO Todo: " + Integer.toString(mTodo); michael@0: dumpLog(message); michael@0: message = Integer.toString(mLineNumber++) + " INFO SimpleTest FINISHED"; michael@0: dumpLog(message); michael@0: } michael@0: michael@0: public void ok(boolean condition, String name, String diag) { michael@0: testInfo test = new testInfo(condition, name, diag, false, false); michael@0: _logMochitestResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL"); michael@0: mTestList.add(test); michael@0: } michael@0: michael@0: public void is(Object actual, Object expected, String name) { michael@0: boolean pass = checkObjectsEqual(actual, expected); michael@0: ok(pass, name, getEqualString(actual, expected, pass)); michael@0: } michael@0: michael@0: public void isnot(Object actual, Object notExpected, String name) { michael@0: boolean pass = checkObjectsNotEqual(actual, notExpected); michael@0: ok(pass, name, getNotEqualString(actual, notExpected, pass)); michael@0: } michael@0: michael@0: public void ispixel(int actual, int r, int g, int b, String name) { michael@0: int aAlpha = ((actual >> 24) & 0xFF); michael@0: int aR = ((actual >> 16) & 0xFF); michael@0: int aG = ((actual >> 8) & 0xFF); michael@0: int aB = (actual & 0xFF); michael@0: boolean pass = checkPixel(actual, r, g, b); michael@0: ok(pass, name, "Color rgba(" + aR + "," + aG + "," + aB + "," + aAlpha + ")" + (pass ? " " : " not") + " close enough to expected rgb(" + r + "," + g + "," + b + ")"); michael@0: } michael@0: michael@0: public void isnotpixel(int actual, int r, int g, int b, String name) { michael@0: int aAlpha = ((actual >> 24) & 0xFF); michael@0: int aR = ((actual >> 16) & 0xFF); michael@0: int aG = ((actual >> 8) & 0xFF); michael@0: int aB = (actual & 0xFF); michael@0: boolean pass = checkPixel(actual, r, g, b); michael@0: ok(!pass, name, "Color rgba(" + aR + "," + aG + "," + aB + "," + aAlpha + ")" + (!pass ? " is" : " is not") + " different enough from rgb(" + r + "," + g + "," + b + ")"); michael@0: } michael@0: michael@0: private boolean checkPixel(int actual, int r, int g, int b) { michael@0: // When we read GL pixels the GPU has already processed them and they michael@0: // are usually off by a little bit. For example a CSS-color pixel of color #64FFF5 michael@0: // was turned into #63FFF7 when it came out of glReadPixels. So in order to compare michael@0: // against the expected value, we use a little fuzz factor. For the alpha we just michael@0: // make sure it is always 0xFF. There is also bug 691354 which crops up every so michael@0: // often just to make our lives difficult. However the individual color components michael@0: // should never be off by more than 8. michael@0: int aAlpha = ((actual >> 24) & 0xFF); michael@0: int aR = ((actual >> 16) & 0xFF); michael@0: int aG = ((actual >> 8) & 0xFF); michael@0: int aB = (actual & 0xFF); michael@0: boolean pass = (aAlpha == 0xFF) /* alpha */ michael@0: && (Math.abs(aR - r) <= 8) /* red */ michael@0: && (Math.abs(aG - g) <= 8) /* green */ michael@0: && (Math.abs(aB - b) <= 8); /* blue */ michael@0: if (pass) { michael@0: return true; michael@0: } else { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: public void todo(boolean condition, String name, String diag) { michael@0: testInfo test = new testInfo(condition, name, diag, true, false); michael@0: _logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL"); michael@0: mTestList.add(test); michael@0: } michael@0: michael@0: public void todo_is(Object actual, Object expected, String name) { michael@0: boolean pass = checkObjectsEqual(actual, expected); michael@0: todo(pass, name, getEqualString(actual, expected, pass)); michael@0: } michael@0: michael@0: public void todo_isnot(Object actual, Object notExpected, String name) { michael@0: boolean pass = checkObjectsNotEqual(actual, notExpected); michael@0: todo(pass, name, getNotEqualString(actual, notExpected, pass)); michael@0: } michael@0: michael@0: private boolean checkObjectsEqual(Object a, Object b) { michael@0: if (a == null || b == null) { michael@0: if (a == null && b == null) { michael@0: return true; michael@0: } michael@0: return false; michael@0: } else { michael@0: return a.equals(b); michael@0: } michael@0: } michael@0: michael@0: private String getEqualString(Object a, Object b, boolean pass) { michael@0: if (pass) { michael@0: return a + " should equal " + b; michael@0: } michael@0: return "got " + a + ", expected " + b; michael@0: } michael@0: michael@0: private boolean checkObjectsNotEqual(Object a, Object b) { michael@0: if (a == null || b == null) { michael@0: if ((a == null && b != null) || (a != null && b == null)) { michael@0: return true; michael@0: } else { michael@0: return false; michael@0: } michael@0: } else { michael@0: return !a.equals(b); michael@0: } michael@0: } michael@0: michael@0: private String getNotEqualString(Object a, Object b, boolean pass) { michael@0: if(pass) { michael@0: return a + " should not equal " + b; michael@0: } michael@0: return "didn't expect " + a + ", but got it"; michael@0: } michael@0: michael@0: public void info(String name, String message) { michael@0: testInfo test = new testInfo(true, name, message, false, true); michael@0: _logMochitestResult(test, "TEST-INFO", "INFO FAILED?"); michael@0: } michael@0: }