Bug 996313 - Add boolean for ending test on assertion failure in JavascriptMessageParser. r=nalexander
authorMichael Comella <michael.l.comella@gmail.com>
Thu, 24 Apr 2014 12:23:20 -0700
changeset 180531 96eefe2070206a8da2d18063f23089b07957cf94
parent 180530 4e1172fa51ea4994152f5b711ad09eaecf9f536e
child 180532 542f5fb83cece04982f8beea8f6919b285da3e89
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersnalexander
bugs996313
milestone31.0a1
Bug 996313 - Add boolean for ending test on assertion failure in JavascriptMessageParser. r=nalexander
mobile/android/base/tests/JavascriptTest.java
mobile/android/base/tests/helpers/JavascriptBridge.java
mobile/android/base/tests/helpers/JavascriptMessageParser.java
--- a/mobile/android/base/tests/JavascriptTest.java
+++ b/mobile/android/base/tests/JavascriptTest.java
@@ -32,17 +32,18 @@ public class JavascriptTest extends Base
             mActions.expectGeckoEvent(EVENT_TYPE);
         mAsserter.dumpLog("Registered listener for " + EVENT_TYPE);
 
         final String url = getAbsoluteUrl(StringHelper.ROBOCOP_JS_HARNESS_URL +
                                           "?path=" + javascriptUrl);
         mAsserter.dumpLog("Loading JavaScript test from " + url);
         loadUrl(url);
 
-        final JavascriptMessageParser testMessageParser = new JavascriptMessageParser(mAsserter);
+        final JavascriptMessageParser testMessageParser =
+                new JavascriptMessageParser(mAsserter, false);
         try {
             while (!testMessageParser.isTestFinished()) {
                 if (Log.isLoggable(LOGTAG, Log.VERBOSE)) {
                     Log.v(LOGTAG, "Waiting for " + EVENT_TYPE);
                 }
                 String data = expecter.blockForEventData();
                 if (Log.isLoggable(LOGTAG, Log.VERBOSE)) {
                     Log.v(LOGTAG, "Got event with data '" + data + "'");
--- a/mobile/android/base/tests/helpers/JavascriptBridge.java
+++ b/mobile/android/base/tests/helpers/JavascriptBridge.java
@@ -105,18 +105,20 @@ public final class JavascriptBridge {
     /* package */ static void init(final UITestContext context) {
         sActions = context.getActions();
         sAsserter = context.getAsserter();
     }
 
     public JavascriptBridge(final Object target) {
         mTarget = target;
         mMethods = target.getClass().getMethods();
-        mLogParser = new JavascriptMessageParser(sAsserter);
         mExpecter = sActions.expectGeckoEvent(EVENT_TYPE);
+        // The JS here is unrelated to a test harness, so we
+        // have our message parser end on assertion failure.
+        mLogParser = new JavascriptMessageParser(sAsserter, true);
     }
 
     /**
      * Synchronously calls a method in Javascript.
      *
      * @param method Name of the method to call
      * @param args Arguments to pass to the Javascript method; must be a list of
      *             values allowed by JSONObject.
--- a/mobile/android/base/tests/helpers/JavascriptMessageParser.java
+++ b/mobile/android/base/tests/helpers/JavascriptMessageParser.java
@@ -29,19 +29,32 @@ public final class JavascriptMessagePars
     private static final Pattern testMessagePattern =
         Pattern.compile("TEST-([A-Z\\-]+) \\| (.*?) \\| (.*)", Pattern.DOTALL);
 
     private final Assert asserter;
     // Used to help print stack traces neatly.
     private String lastTestName = "";
     // Have we seen a message saying the test is finished?
     private boolean testFinishedMessageSeen = false;
+    private final boolean endOnAssertionFailure;
 
-    public JavascriptMessageParser(final Assert asserter) {
+    /**
+     * Constructs a message parser for test result messages sent from JavaScript. When seeing an
+     * assertion failure, the message parser can use the given {@link org.mozilla.gecko.Assert}
+     * instance to immediately end the test (typically if the underlying JS framework is not able
+     * to end the test itself) or to swallow the Errors - this functionality is determined by the
+     * <code>endOnAssertionFailure</code> parameter.
+     *
+     * @param asserter The Assert instance to which test results should be passed.
+     * @param endOnAssertionFailure
+     *        true if the test should end if we see a JS assertion failure, false otherwise.
+     */
+    public JavascriptMessageParser(final Assert asserter, final boolean endOnAssertionFailure) {
         this.asserter = asserter;
+        this.endOnAssertionFailure = endOnAssertionFailure;
     }
 
     public boolean isTestFinished() {
         return testFinishedMessageSeen;
     }
 
     public void logMessage(final String str) {
         final Matcher m = testMessagePattern.matcher(str.trim());
@@ -56,18 +69,25 @@ public final class JavascriptMessagePars
                 testFinishedMessageSeen = testFinishedMessageSeen ||
                                           "exiting test".equals(message);
             } else if ("PASS".equals(type)) {
                 asserter.ok(true, name, message);
             } else if ("UNEXPECTED-FAIL".equals(type)) {
                 try {
                     asserter.ok(false, name, message);
                 } catch (AssertionFailedError e) {
-                    // Swallow this exception.  We want to see all the
-                    // Javascript failures, not die on the very first one!
+                    // Above, we call the assert, allowing it to log.
+                    // Now we can end the test, if applicable.
+                    if (this.endOnAssertionFailure) {
+                        throw e;
+                    }
+                    // Otherwise, swallow the Error. The JS framework we're
+                    // logging messages from is likely capable of ending tests
+                    // when it needs to, and we want to see all of its failures,
+                    // not just the first one!
                 }
             } else if ("KNOWN-FAIL".equals(type)) {
                 asserter.todo(false, name, message);
             } else if ("UNEXPECTED-PASS".equals(type)) {
                 asserter.todo(true, name, message);
             }
 
             lastTestName = name;