From e6d01f0701a6004ad1a5bd20b5c7a03bb362059d Mon Sep 17 00:00:00 2001 From: Matt Basta Date: Mon, 14 Oct 2013 13:18:51 -0700 Subject: [PATCH] Minor refactoring, fixes for emscripted apps --- appvalidator/constants.py | 1 + appvalidator/csp.py | 2 +- appvalidator/errorbundle/basebundle.py | 19 ++++++++---- .../testcases/javascript/spidermonkey.py | 30 +++++++++---------- .../testcases/javascript/traverser.py | 14 ++++----- appvalidator/testcases/scripting.py | 19 ++++++++++-- jsmain.py | 11 ++++--- tests/js/js_helper.py | 4 +-- 8 files changed, 60 insertions(+), 40 deletions(-) diff --git a/appvalidator/constants.py b/appvalidator/constants.py index 889a9c8..fcd1b1c 100644 --- a/appvalidator/constants.py +++ b/appvalidator/constants.py @@ -9,6 +9,7 @@ PACKAGE_ANY = 0 PACKAGE_WEBAPP = 8 PACKAGE_PACKAGED_WEBAPP = 9 +JS_DEBUG = False SPIDERMONKEY_INSTALLATION = os.environ.get("SPIDERMONKEY_INSTALLATION") DEFAULT_WEBAPP_MRKT_URLS = ["https://marketplace.firefox.com", diff --git a/appvalidator/csp.py b/appvalidator/csp.py index 00913fe..5b2a4a5 100644 --- a/appvalidator/csp.py +++ b/appvalidator/csp.py @@ -1,5 +1,5 @@ -CSP_INFO = "https://developer.mozilla.org/en-US/docs/Security/CSP" +CSP_INFO = "https://developer.mozilla.org/Apps/CSP" MESSAGE_TITLE = "CSP Violation Detected" MESSAGE_GENERAL_DESC = ("You can find more information about what is and is " diff --git a/appvalidator/errorbundle/basebundle.py b/appvalidator/errorbundle/basebundle.py index 8552d0a..5be8e0f 100644 --- a/appvalidator/errorbundle/basebundle.py +++ b/appvalidator/errorbundle/basebundle.py @@ -38,6 +38,7 @@ class BaseErrorBundle(object): def _message(type_, message_type): def wrap(self, *args, **kwargs): + arg_len = len(args) message = { "uid": uuid.uuid4().hex, "id": kwargs.get("err_id") or args[0], @@ -45,18 +46,26 @@ class BaseErrorBundle(object): kwargs.get(message_type) or args[1]), "description": unicodehelper.decode( kwargs.get("description", args[2] if - len(args) > 2 else None)), + arg_len > 2 else None)), # Filename is never None. "file": kwargs.get("filename", - args[3] if len(args) > 3 else ""), + args[3] if arg_len > 3 else ""), "line": kwargs.get("line", - args[4] if len(args) > 4 else None), + args[4] if arg_len > 4 else None), "column": kwargs.get("column", - args[5] if len(args) > 5 else None), + args[5] if arg_len > 5 else None), "tier": kwargs.get("tier", self.tier), "context": None, } + destination = getattr(self, type_) + # Don't show duplicate messages. + if any(x["id"] == message["id"] and + x["file"] == message["file"] and + x["line"] == message["line"] and + x["column"] == message["column"] for x in destination): + return self + context = kwargs.get("context") if context is not None: if isinstance(context, tuple): @@ -66,7 +75,7 @@ class BaseErrorBundle(object): line=message["line"], column=message["column"]) # Append the message to the right stack. - getattr(self, type_).append(message) + destination.append(message) # If instant mode is turned on, output the message immediately. if self.instant: diff --git a/appvalidator/testcases/javascript/spidermonkey.py b/appvalidator/testcases/javascript/spidermonkey.py index 7aa1b9a..d32b15e 100644 --- a/appvalidator/testcases/javascript/spidermonkey.py +++ b/appvalidator/testcases/javascript/spidermonkey.py @@ -65,6 +65,19 @@ class JSReflectException(Exception): self.line = int(line_num) return self +BOOTSTRAP_SCRIPT = """ +var stdin = JSON.parse(readline()); +try{ + print(JSON.stringify(Reflect.parse(stdin))); +} catch(e) { + print(JSON.stringify({ + "error":true, + "error_message":e.toString(), + "line_number":e.lineNumber + })); +}""" +BOOTSTRAP_SCRIPT = re.sub("\n +", "", BOOTSTRAP_SCRIPT) + def _get_tree(code, shell=SPIDERMONKEY_INSTALLATION): """Return an AST tree of the JS passed in `code`.""" @@ -72,25 +85,12 @@ def _get_tree(code, shell=SPIDERMONKEY_INSTALLATION): if not code: return None - code = json.dumps(JS_ESCAPE.sub("u", unicodehelper.decode(code))) - - data = """ - var stdin = JSON.parse(readline()); - try{ - print(JSON.stringify(Reflect.parse(stdin))); - } catch(e) { - print(JSON.stringify({ - "error":true, - "error_message":e.toString(), - "line_number":e.lineNumber - })); - }""" - - cmd = [shell, "-e", data] + cmd = [shell, "-e", BOOTSTRAP_SCRIPT] shell_obj = subprocess.Popen( cmd, shell=False, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) + code = json.dumps(JS_ESCAPE.sub("u", unicodehelper.decode(code))) data, stderr = shell_obj.communicate(code) if stderr: diff --git a/appvalidator/testcases/javascript/traverser.py b/appvalidator/testcases/javascript/traverser.py index 1785fbc..2db7962 100644 --- a/appvalidator/testcases/javascript/traverser.py +++ b/appvalidator/testcases/javascript/traverser.py @@ -1,14 +1,12 @@ import re import types +from appvalidator.constants import JS_DEBUG from .jstypes import * from .nodedefinitions import DEFINITIONS from .predefinedentities import GLOBAL_ENTITIES -DEBUG = False - - class Traverser(object): """Traverses the AST Tree and determines problems with a chunk of JS.""" @@ -34,12 +32,12 @@ class Traverser(object): self.debug_level = 0 # If we're not debugging, don't waste more cycles than we need to. - if not DEBUG: + if not JS_DEBUG: self._debug = lambda *args, **kwargs: None def _debug(self, data, indent=0): """Write a message to the console if debugging is enabled.""" - if DEBUG: + if JS_DEBUG: output = data if isinstance(data, JSObject) or isinstance(data, JSContext): output = data.output() @@ -49,7 +47,7 @@ class Traverser(object): output.encode("ascii", "replace")) def run(self, data): - if DEBUG: + if JS_DEBUG: x = open("/tmp/output.js", "w") x.write(unicode(data)) x.close() @@ -71,7 +69,7 @@ class Traverser(object): if self.contexts: # If we're in debug mode, save a copy of the global context for # analysis during unit tests. - if DEBUG: + if JS_DEBUG: self.err.final_context = self.contexts[0] def traverse_node(self, node): @@ -114,7 +112,7 @@ class Traverser(object): if action is not None: action_result = action(self, node) - if DEBUG: + if JS_DEBUG: self._debug("ACTION>>%s (%s)" % (repr(action_result), node["type"])) if action_result is None: diff --git a/appvalidator/testcases/scripting.py b/appvalidator/testcases/scripting.py index b4160b5..bbabcb0 100644 --- a/appvalidator/testcases/scripting.py +++ b/appvalidator/testcases/scripting.py @@ -16,9 +16,22 @@ def test_js_file(err, filename, data, line=0, context=None): before_tier = err.tier err.set_tier(3) - tree = get_tree(data, err, filename, - err and err.get_resource("SPIDERMONKEY") or - SPIDERMONKEY_INSTALLATION) + tree = None + try: + tree = get_tree(data, err, filename, + err and err.get_resource("SPIDERMONKEY") or + SPIDERMONKEY_INSTALLATION) + except RuntimeError as exc: + warning ="JS: Unknown runtime error" + if "out of memory" in str(exc): + warning = "JS: Out of memory exception" + err.warning( + err_id=("js", "parse", "runtimeerror"), + warning=warning, + description="An error was encountered while trying to validate a " + "JS file.", + filename=filename) + if not tree: err.metadata["ran_js_tests"] = "no;missing ast" if err is not None: diff --git a/jsmain.py b/jsmain.py index 03f476b..809b573 100755 --- a/jsmain.py +++ b/jsmain.py @@ -1,16 +1,15 @@ #!/usr/bin/env python import sys -import os +import appvalidator.testcases.scripting as scripting +import appvalidator.testcases.javascript.traverser from appvalidator.constants import SPIDERMONKEY_INSTALLATION from appvalidator.errorbundle import ErrorBundle from appvalidator.errorbundle.outputhandlers.shellcolors import OutputHandler -import appvalidator.testcases.scripting as scripting -import appvalidator.testcases.javascript.traverser from appvalidator.testcases.javascript.predefinedentities import GLOBAL_ENTITIES -import appvalidator.testcases.javascript.spidermonkey as spidermonkey -appvalidator.testcases.javascript.traverser.DEBUG = True +from appvalidator.testcases.scripting import get_tree +appvalidator.testcases.javascript.traverser.JS_DEBUG = True if __name__ == '__main__': err = ErrorBundle(instant=True) @@ -69,7 +68,7 @@ if __name__ == '__main__': print actions[vars[0]](wrap) continue - tree = spidermonkey.get_tree(line, err, shell=SPIDERMONKEY_INSTALLATION) + tree = get_tree(line, err, shell=SPIDERMONKEY_INSTALLATION) if tree is None: continue tree = tree["body"] diff --git a/tests/js/js_helper.py b/tests/js/js_helper.py index a52942a..98bf7f7 100644 --- a/tests/js/js_helper.py +++ b/tests/js/js_helper.py @@ -9,10 +9,10 @@ from ..helper import MockXPI from appvalidator.constants import SPIDERMONKEY_INSTALLATION from appvalidator.errorbundle import ErrorBundle from appvalidator.errorbundle.outputhandlers.shellcolors import OutputHandler +import appvalidator import appvalidator.testcases.content -import appvalidator.testcases.scripting as scripting -scripting.traverser.DEBUG = True +appvalidator.testcases.javascript.traverser.JS_DEBUG = True def uses_js(func):