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: #include "js/Class.h" michael@0: #include "jsapi-tests/tests.h" michael@0: michael@0: static int iterCount = 0; michael@0: michael@0: static bool michael@0: IterNext(JSContext *cx, unsigned argc, jsval *vp) michael@0: { michael@0: JS::CallArgs args = JS::CallArgsFromVp(argc, vp); michael@0: if (iterCount++ == 100) michael@0: return JS_ThrowStopIteration(cx); michael@0: args.rval().setInt32(iterCount); michael@0: return true; michael@0: } michael@0: michael@0: static JSObject * michael@0: IterHook(JSContext *cx, JS::HandleObject obj, bool keysonly) michael@0: { michael@0: JS::RootedObject iterObj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); michael@0: if (!iterObj) michael@0: return nullptr; michael@0: if (!JS_DefineFunction(cx, iterObj, "next", IterNext, 0, 0)) michael@0: return nullptr; michael@0: return iterObj; michael@0: } michael@0: michael@0: const js::Class HasCustomIterClass = { michael@0: "HasCustomIter", michael@0: 0, michael@0: JS_PropertyStub, michael@0: JS_DeletePropertyStub, michael@0: JS_PropertyStub, michael@0: JS_StrictPropertyStub, michael@0: JS_EnumerateStub, michael@0: JS_ResolveStub, michael@0: JS_ConvertStub, michael@0: nullptr, michael@0: nullptr, /* call */ michael@0: nullptr, /* hasInstance */ michael@0: nullptr, /* construct */ michael@0: nullptr, /* mark */ michael@0: JS_NULL_CLASS_SPEC, michael@0: { michael@0: nullptr, /* outerObject */ michael@0: nullptr, /* innerObject */ michael@0: IterHook, michael@0: false /* isWrappedNative */ michael@0: } michael@0: }; michael@0: michael@0: static bool michael@0: IterClassConstructor(JSContext *cx, unsigned argc, jsval *vp) michael@0: { michael@0: JS::CallArgs args = JS::CallArgsFromVp(argc, vp); michael@0: JSObject *obj = JS_NewObjectForConstructor(cx, Jsvalify(&HasCustomIterClass), args); michael@0: if (!obj) michael@0: return false; michael@0: args.rval().setObject(*obj); michael@0: return true; michael@0: } michael@0: michael@0: BEGIN_TEST(testCustomIterator_bug612523) michael@0: { michael@0: CHECK(JS_InitClass(cx, global, js::NullPtr(), Jsvalify(&HasCustomIterClass), michael@0: IterClassConstructor, 0, nullptr, nullptr, nullptr, nullptr)); michael@0: michael@0: JS::RootedValue result(cx); michael@0: EVAL("var o = new HasCustomIter(); \n" michael@0: "var j = 0; \n" michael@0: "for (var i in o) { ++j; }; \n" michael@0: "j;", &result); michael@0: michael@0: CHECK(JSVAL_IS_INT(result)); michael@0: CHECK_EQUAL(JSVAL_TO_INT(result), 100); michael@0: CHECK_EQUAL(iterCount, 101); michael@0: michael@0: return true; michael@0: } michael@0: END_TEST(testCustomIterator_bug612523)