js/src/jsapi-tests/testResolveRecursion.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  */
     4 /* This Source Code Form is subject to the terms of the Mozilla Public
     5  * License, v. 2.0. If a copy of the MPL was not distributed with this
     6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     8 #include "jsapi-tests/tests.h"
    10 /*
    11  * Test that resolve hook recursion for the same object and property is
    12  * prevented.
    13  */
    15 BEGIN_TEST(testResolveRecursion)
    16 {
    17     static const JSClass my_resolve_class = {
    18         "MyResolve",
    19         JSCLASS_NEW_RESOLVE | JSCLASS_HAS_PRIVATE,
    21         JS_PropertyStub,       // add
    22         JS_DeletePropertyStub, // delete
    23         JS_PropertyStub,       // get
    24         JS_StrictPropertyStub, // set
    25         JS_EnumerateStub,
    26         (JSResolveOp) my_resolve,
    27         JS_ConvertStub
    28     };
    30     obj1 = obj2 = nullptr;
    31     JS::AddObjectRoot(cx, &obj1);
    32     JS::AddObjectRoot(cx, &obj2);
    34     obj1 = JS_NewObject(cx, &my_resolve_class, JS::NullPtr(), JS::NullPtr());
    35     CHECK(obj1);
    36     obj2 = JS_NewObject(cx, &my_resolve_class, JS::NullPtr(), JS::NullPtr());
    37     CHECK(obj2);
    38     JS_SetPrivate(obj1, this);
    39     JS_SetPrivate(obj2, this);
    41     JS::RootedValue obj1Val(cx, ObjectValue(*obj1));
    42     JS::RootedValue obj2Val(cx, ObjectValue(*obj2));
    43     CHECK(JS_DefineProperty(cx, global, "obj1", obj1Val, 0));
    44     CHECK(JS_DefineProperty(cx, global, "obj2", obj2Val, 0));
    46     resolveEntryCount = 0;
    47     resolveExitCount = 0;
    49     /* Start the essence of the test via invoking the first resolve hook. */
    50     JS::RootedValue v(cx);
    51     EVAL("obj1.x", &v);
    52     CHECK_SAME(v, JSVAL_FALSE);
    53     CHECK_EQUAL(resolveEntryCount, 4);
    54     CHECK_EQUAL(resolveExitCount, 4);
    56     obj1 = nullptr;
    57     obj2 = nullptr;
    58     JS::RemoveObjectRoot(cx, &obj1);
    59     JS::RemoveObjectRoot(cx, &obj2);
    60     return true;
    61 }
    63 JS::Heap<JSObject *> obj1;
    64 JS::Heap<JSObject *> obj2;
    65 unsigned resolveEntryCount;
    66 unsigned resolveExitCount;
    68 struct AutoIncrCounters {
    70     AutoIncrCounters(cls_testResolveRecursion *t) : t(t) {
    71         t->resolveEntryCount++;
    72     }
    74     ~AutoIncrCounters() {
    75         t->resolveExitCount++;
    76     }
    78     cls_testResolveRecursion *t;
    79 };
    81 bool
    82 doResolve(JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp)
    83 {
    84     CHECK_EQUAL(resolveExitCount, 0);
    85     AutoIncrCounters incr(this);
    86     CHECK_EQUAL(obj, obj1 || obj == obj2);
    88     CHECK(JSID_IS_STRING(id));
    90     JSFlatString *str = JS_FlattenString(cx, JSID_TO_STRING(id));
    91     CHECK(str);
    92     JS::RootedValue v(cx);
    93     if (JS_FlatStringEqualsAscii(str, "x")) {
    94         if (obj == obj1) {
    95             /* First resolve hook invocation. */
    96             CHECK_EQUAL(resolveEntryCount, 1);
    97             EVAL("obj2.y = true", &v);
    98             CHECK_SAME(v, JSVAL_TRUE);
    99             CHECK(JS_DefinePropertyById(cx, obj, id, JSVAL_FALSE, nullptr, nullptr, 0));
   100             objp.set(obj);
   101             return true;
   102         }
   103         if (obj == obj2) {
   104             CHECK_EQUAL(resolveEntryCount, 4);
   105             objp.set(nullptr);
   106             return true;
   107         }
   108     } else if (JS_FlatStringEqualsAscii(str, "y")) {
   109         if (obj == obj2) {
   110             CHECK_EQUAL(resolveEntryCount, 2);
   111             CHECK(JS_DefinePropertyById(cx, obj, id, JSVAL_NULL, nullptr, nullptr, 0));
   112             EVAL("obj1.x", &v);
   113             CHECK(JSVAL_IS_VOID(v));
   114             EVAL("obj1.y", &v);
   115             CHECK_SAME(v, JSVAL_ZERO);
   116             objp.set(obj);
   117             return true;
   118         }
   119         if (obj == obj1) {
   120             CHECK_EQUAL(resolveEntryCount, 3);
   121             EVAL("obj1.x", &v);
   122             CHECK(JSVAL_IS_VOID(v));
   123             EVAL("obj1.y", &v);
   124             CHECK(JSVAL_IS_VOID(v));
   125             EVAL("obj2.y", &v);
   126             CHECK(JSVAL_IS_NULL(v));
   127             EVAL("obj2.x", &v);
   128             CHECK(JSVAL_IS_VOID(v));
   129             EVAL("obj1.y = 0", &v);
   130             CHECK_SAME(v, JSVAL_ZERO);
   131             objp.set(obj);
   132             return true;
   133         }
   134     }
   135     CHECK(false);
   136     return false;
   137 }
   139 static bool
   140 my_resolve(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp)
   141 {
   142     return static_cast<cls_testResolveRecursion *>(JS_GetPrivate(obj))->
   143            doResolve(obj, id, objp);
   144 }
   146 END_TEST(testResolveRecursion)

mercurial