LCOV - app.info - js/src/jsapi-tests/testDebugger.cpp

LCOV - code coverage report
| Current view: | directory - js/src/jsapi-tests - testDebugger.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 153 | 152 | 99.3 %
| Date: | 2012-04-07 | Functions: | 55 | 45 | 81.8 %

           1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=8 sw=4 et tw=99:
           3                 :  */
           4                 :
           5                 : #include "tests.h"
           6                 : #include "jsdbgapi.h"
           7                 : #include "jscntxt.h"
           8                 :
           9                 : static int callCount[2] = {0, 0};
          10                 :
          11                 : static void *
          12              40 : callCountHook(JSContext *cx, JSStackFrame *fp, JSBool before, JSBool *ok, void *closure)
          13                 : {
          14              40 :     callCount[before]++;
          15                 :
          16                 :     jsval thisv;
          17              40 :     JS_GetFrameThis(cx, fp, &thisv);  // assert if fp is incomplete
          18                 :
          19              40 :     return cx;  // any non-null value causes the hook to be called again after
          20                 : }
          21                 :
          22               4 : BEGIN_TEST(testDebugger_bug519719)
          23                 : {
          24               1 :     CHECK(JS_SetDebugMode(cx, JS_TRUE));
          25               1 :     JS_SetCallHook(rt, callCountHook, NULL);
          26               1 :     EXEC("function call(fn) { fn(0); }\n"
          27                 :          "function f(g) { for (var i = 0; i < 9; i++) call(g); }\n"
          28                 :          "f(Math.sin);\n"    // record loop, starting in f
          29                 :          "f(Math.cos);\n");  // side exit in f -> call
          30               1 :     CHECK_EQUAL(callCount[0], 20);
          31               1 :     CHECK_EQUAL(callCount[1], 20);
          32               1 :     return true;
          33                 : }
          34               1 : END_TEST(testDebugger_bug519719)
          35                 :
          36                 : static void *
          37              10 : nonStrictThisHook(JSContext *cx, JSStackFrame *fp, JSBool before, JSBool *ok, void *closure)
          38                 : {
          39              10 :     if (before) {
          40              10 :         bool *allWrapped = (bool *) closure;
          41                 :         jsval thisv;
          42              10 :         JS_GetFrameThis(cx, fp, &thisv);
          43              10 :         *allWrapped = *allWrapped && !JSVAL_IS_PRIMITIVE(thisv);
          44                 :     }
          45              10 :     return NULL;
          46                 : }
          47                 :
          48               4 : BEGIN_TEST(testDebugger_getThisNonStrict)
          49                 : {
          50               1 :     bool allWrapped = true;
          51               1 :     CHECK(JS_SetDebugMode(cx, JS_TRUE));
          52               1 :     JS_SetCallHook(rt, nonStrictThisHook, (void *) &allWrapped);
          53               1 :     EXEC("function nonstrict() { }\n"
          54                 :          "Boolean.prototype.nonstrict = nonstrict;\n"
          55                 :          "String.prototype.nonstrict = nonstrict;\n"
          56                 :          "Number.prototype.nonstrict = nonstrict;\n"
          57                 :          "Object.prototype.nonstrict = nonstrict;\n"
          58                 :          "nonstrict.call(true);\n"
          59                 :          "true.nonstrict();\n"
          60                 :          "nonstrict.call('');\n"
          61                 :          "''.nonstrict();\n"
          62                 :          "nonstrict.call(42);\n"
          63                 :          "(42).nonstrict();\n"
          64                 :          // The below don't really get 'wrapped', but it's okay.
          65                 :          "nonstrict.call(undefined);\n"
          66                 :          "nonstrict.call(null);\n"
          67                 :          "nonstrict.call({});\n"
          68                 :          "({}).nonstrict();\n");
          69               1 :     CHECK(allWrapped);
          70               1 :     return true;
          71                 : }
          72               1 : END_TEST(testDebugger_getThisNonStrict)
          73                 :
          74                 : static void *
          75               8 : strictThisHook(JSContext *cx, JSStackFrame *fp, JSBool before, JSBool *ok, void *closure)
          76                 : {
          77               8 :     if (before) {
          78               8 :         bool *anyWrapped = (bool *) closure;
          79                 :         jsval thisv;
          80               8 :         JS_GetFrameThis(cx, fp, &thisv);
          81               8 :         *anyWrapped = *anyWrapped || !JSVAL_IS_PRIMITIVE(thisv);
          82                 :     }
          83               8 :     return NULL;
          84                 : }
          85                 :
          86               4 : BEGIN_TEST(testDebugger_getThisStrict)
          87                 : {
          88               1 :     bool anyWrapped = false;
          89               1 :     CHECK(JS_SetDebugMode(cx, JS_TRUE));
          90               1 :     JS_SetCallHook(rt, strictThisHook, (void *) &anyWrapped);
          91               1 :     EXEC("function strict() { 'use strict'; }\n"
          92                 :          "Boolean.prototype.strict = strict;\n"
          93                 :          "String.prototype.strict = strict;\n"
          94                 :          "Number.prototype.strict = strict;\n"
          95                 :          "strict.call(true);\n"
          96                 :          "true.strict();\n"
          97                 :          "strict.call('');\n"
          98                 :          "''.strict();\n"
          99                 :          "strict.call(42);\n"
         100                 :          "(42).strict();\n"
         101                 :          "strict.call(undefined);\n"
         102                 :          "strict.call(null);\n");
         103               1 :     CHECK(!anyWrapped);
         104               1 :     return true;
         105                 : }
         106               1 : END_TEST(testDebugger_getThisStrict)
         107                 :
         108                 : bool called = false;
         109                 :
         110                 : static JSTrapStatus
         111              20 : ThrowHook(JSContext *cx, JSScript *, jsbytecode *, jsval *rval, void *closure)
         112                 : {
         113              20 :     JS_ASSERT(!closure);
         114              20 :     called = true;
         115                 :
         116              20 :     JSObject *global = JS_GetGlobalForScopeChain(cx);
         117                 :
         118              20 :     char text[] = "new Error()";
         119                 :     jsval _;
         120              20 :     JS_EvaluateScript(cx, global, text, strlen(text), "", 0, &_);
         121                 :
         122              20 :     return JSTRAP_CONTINUE;
         123                 : }
         124                 :
         125               4 : BEGIN_TEST(testDebugger_throwHook)
         126                 : {
         127               1 :     uint32_t newopts = JS_GetOptions(cx) | JSOPTION_METHODJIT | JSOPTION_METHODJIT_ALWAYS;
         128               1 :     uint32_t oldopts = JS_SetOptions(cx, newopts);
         129                 :
         130               1 :     CHECK(JS_SetThrowHook(rt, ThrowHook, NULL));
         131               1 :     EXEC("function foo() { throw 3 };\n"
         132                 :          "for (var i = 0; i < 10; ++i) { \n"
         133                 :          "  var x = <tag></tag>;\n"
         134                 :          "  try {\n"
         135                 :          "    foo(); \n"
         136                 :          "  } catch(e) {}\n"
         137                 :          "}\n");
         138               1 :     CHECK(called);
         139               1 :     CHECK(JS_SetThrowHook(rt, NULL, NULL));
         140               1 :     JS_SetOptions(cx, oldopts);
         141               1 :     return true;
         142                 : }
         143               1 : END_TEST(testDebugger_throwHook)
         144                 :
         145               4 : BEGIN_TEST(testDebugger_debuggerObjectVsDebugMode)
         146                 : {
         147               1 :     CHECK(JS_DefineDebuggerObject(cx, global));
         148               1 :     JSObject *debuggee = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL);
         149               1 :     CHECK(debuggee);
         150                 :
         151                 :     {
         152               2 :         JSAutoEnterCompartment ae;
         153               1 :         CHECK(ae.enter(cx, debuggee));
         154               1 :         CHECK(JS_SetDebugMode(cx, true));
         155               1 :         CHECK(JS_InitStandardClasses(cx, debuggee));
         156                 :     }
         157                 :
         158               1 :     JSObject *debuggeeWrapper = debuggee;
         159               1 :     CHECK(JS_WrapObject(cx, &debuggeeWrapper));
         160               1 :     jsval v = OBJECT_TO_JSVAL(debuggeeWrapper);
         161               1 :     CHECK(JS_SetProperty(cx, global, "debuggee", &v));
         162                 :
         163               1 :     EVAL("var dbg = new Debugger(debuggee);\n"
         164                 :          "var hits = 0;\n"
         165                 :          "dbg.onDebuggerStatement = function () { hits++; };\n"
         166                 :          "debuggee.eval('debugger;');\n"
         167                 :          "hits;\n",
         168                 :          &v);
         169               1 :     CHECK_SAME(v, JSVAL_ONE);
         170                 :
         171                 :     {
         172               2 :         JSAutoEnterCompartment ae;
         173               1 :         CHECK(ae.enter(cx, debuggee));
         174               1 :         CHECK(JS_SetDebugMode(cx, false));
         175                 :     }
         176                 :
         177               1 :     EVAL("debuggee.eval('debugger; debugger; debugger;');\n"
         178                 :          "hits;\n",
         179                 :          &v);
         180               1 :     CHECK_SAME(v, INT_TO_JSVAL(4));
         181                 :
         182               1 :     return true;
         183                 : }
         184               1 : END_TEST(testDebugger_debuggerObjectVsDebugMode)
         185                 :
         186               4 : BEGIN_TEST(testDebugger_newScriptHook)
         187                 : {
         188                 :     // Test that top-level indirect eval fires the newScript hook.
         189               1 :     CHECK(JS_DefineDebuggerObject(cx, global));
         190                 :     JSObject *g1, *g2;
         191               1 :     g1 = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL);
         192               1 :     CHECK(g1);
         193                 :     {
         194               2 :         JSAutoEnterCompartment ae;
         195               1 :         CHECK(ae.enter(cx, g1));
         196               1 :         CHECK(JS_InitStandardClasses(cx, g1));
         197               1 :         g2 = JS_NewGlobalObject(cx, getGlobalClass());
         198               1 :         CHECK(g2);
         199               1 :         CHECK(JS_InitStandardClasses(cx, g2));
         200                 :     }
         201                 :
         202               1 :     JSObject *g1Wrapper = g1;
         203               1 :     CHECK(JS_WrapObject(cx, &g1Wrapper));
         204               1 :     jsval v = OBJECT_TO_JSVAL(g1Wrapper);
         205               1 :     CHECK(JS_SetProperty(cx, global, "g1", &v));
         206                 :
         207               1 :     JSObject *g2Wrapper = g2;
         208               1 :     CHECK(JS_WrapObject(cx, &g2Wrapper));
         209               1 :     v = OBJECT_TO_JSVAL(g2Wrapper);
         210               1 :     CHECK(JS_SetProperty(cx, global, "g2", &v));
         211                 :
         212               1 :     EXEC("var dbg = Debugger(g1);\n"
         213                 :          "var hits = 0;\n"
         214                 :          "dbg.onNewScript = function (s) {\n"
         215                 :          "    hits += Number(s instanceof Debugger.Script);\n"
         216                 :          "};\n");
         217                 :
         218                 :     // Since g1 is a debuggee and g2 is not, g1.eval should trigger newScript
         219                 :     // and g2.eval should not, regardless of what scope object we use to enter
         220                 :     // the compartment.
         221                 :     //
         222                 :     // (Not all scripts are permanently associated with specific global
         223                 :     // objects, but eval scripts are, so we deliver them only to debuggers that
         224                 :     // are watching that particular global.)
         225                 :     //
         226               1 :     bool ok = true;
         227               1 :     ok = ok && testIndirectEval(g1, g1, "Math.abs(0)", 1);
         228               1 :     ok = ok && testIndirectEval(g2, g1, "Math.abs(1)", 1);
         229               1 :     ok = ok && testIndirectEval(g1, g2, "Math.abs(-1)", 0);
         230               1 :     ok = ok && testIndirectEval(g2, g2, "Math.abs(-2)", 0);
         231               1 :     return ok;
         232                 : }
         233                 :
         234               4 : bool testIndirectEval(JSObject *scope, JSObject *g, const char *code, int expectedHits)
         235                 : {
         236               4 :     EXEC("hits = 0;");
         237                 :
         238                 :     {
         239               8 :         JSAutoEnterCompartment ae;
         240               4 :         CHECK(ae.enter(cx, scope));
         241               4 :         JSString *codestr = JS_NewStringCopyZ(cx, code);
         242               4 :         CHECK(codestr);
         243               4 :         jsval argv[1] = { STRING_TO_JSVAL(codestr) };
         244                 :         jsval v;
         245               4 :         CHECK(JS_CallFunctionName(cx, g, "eval", 1, argv, &v));
         246                 :     }
         247                 :
         248                 :     jsval hitsv;
         249               4 :     EVAL("hits", &hitsv);
         250               4 :     CHECK_SAME(hitsv, INT_TO_JSVAL(expectedHits));
         251               4 :     return true;
         252                 : }
         253               1 : END_TEST(testDebugger_newScriptHook)
         254                 :
         255               4 : BEGIN_TEST(testDebugger_singleStepThrow)
         256                 :     {
         257               1 :         CHECK(JS_SetDebugModeForCompartment(cx, cx->compartment, true));
         258               1 :         CHECK(JS_SetInterrupt(rt, onStep, NULL));
         259                 :
         260               1 :         uint32_t opts = JS_GetOptions(cx);
         261               1 :         opts |= JSOPTION_METHODJIT | JSOPTION_METHODJIT_ALWAYS;
         262               1 :         JS_SetOptions(cx, opts);
         263                 :
         264               1 :         CHECK(JS_DefineFunction(cx, global, "setStepMode", setStepMode, 0, 0));
         265               1 :         EXEC("var e;\n"
         266                 :              "setStepMode();\n"
         267                 :              "function f() { throw 0; }\n"
         268                 :              "try { f(); }\n"
         269                 :              "catch (x) { e = x; }\n");
         270               1 :         return true;
         271                 :     }
         272                 :
         273                 :     static JSBool
         274               1 :     setStepMode(JSContext *cx, unsigned argc, jsval *vp)
         275                 :     {
         276                 :         JSScript *script;
         277               1 :         JS_DescribeScriptedCaller(cx, &script, NULL);
         278               1 :         JS_ASSERT(script);
         279                 :
         280               1 :         if (!JS_SetSingleStepMode(cx, script, true))
         281               0 :             return false;
         282               1 :         JS_SET_RVAL(cx, vp, JSVAL_VOID);
         283               1 :         return true;
         284                 :     }
         285                 :
         286                 :     static JSTrapStatus
         287              17 :     onStep(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure)
         288                 :     {
         289              17 :         return JSTRAP_CONTINUE;
         290                 :     }
         291               1 : END_TEST(testDebugger_singleStepThrow)
         292                 :
         293               4 : BEGIN_TEST(testDebugger_emptyObjectPropertyIterator)
         294                 : {
         295               1 :     JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
         296               1 :     JSScopeProperty *prop = NULL;
         297               1 :     CHECK(!JS_PropertyIterator(obj, &prop));
         298               1 :     CHECK(!prop);
         299                 :
         300               1 :     return true;
         301                 : }
         302               1 : END_TEST(testDebugger_emptyObjectPropertyIterator)
         303                 :
         304               4 : BEGIN_TEST(testDebugger_nonEmptyObjectPropertyIterator)
         305                 : {
         306                 :     jsval v;
         307               1 :     EVAL("({a: 15})", &v);
         308               1 :     JSObject *obj = JSVAL_TO_OBJECT(v);
         309               1 :     JSScopeProperty *prop = NULL;
         310               1 :     CHECK(JS_PropertyIterator(obj, &prop));
         311                 :     JSPropertyDesc desc;
         312               1 :     CHECK(JS_GetPropertyDesc(cx, obj, prop, &desc));
         313               1 :     CHECK_EQUAL(JSVAL_IS_INT(desc.value), true);
         314               1 :     CHECK_EQUAL(JSVAL_TO_INT(desc.value), 15);
         315               1 :     CHECK(!JS_PropertyIterator(obj, &prop));
         316               1 :     CHECK(!prop);
         317                 :
         318               1 :     return true;
         319                 : }
         320               3 : END_TEST(testDebugger_nonEmptyObjectPropertyIterator)

Generated by: LCOV version 1.7