From cad810f21b803229eb11403f9209855525a25d57 Mon Sep 17 00:00:00 2001 From: Steve Block Date: Fri, 6 May 2011 11:45:16 +0100 Subject: Merge WebKit at r75315: Initial merge by git. Change-Id: I570314b346ce101c935ed22a626b48c2af266b84 --- Source/JavaScriptCore/API/tests/JSNode.c | 196 ++++ Source/JavaScriptCore/API/tests/JSNode.h | 37 + Source/JavaScriptCore/API/tests/JSNodeList.c | 123 +++ Source/JavaScriptCore/API/tests/JSNodeList.h | 34 + Source/JavaScriptCore/API/tests/Node.c | 85 ++ Source/JavaScriptCore/API/tests/Node.h | 50 + Source/JavaScriptCore/API/tests/NodeList.c | 81 ++ Source/JavaScriptCore/API/tests/NodeList.h | 42 + Source/JavaScriptCore/API/tests/minidom.c | 126 +++ Source/JavaScriptCore/API/tests/minidom.html | 9 + Source/JavaScriptCore/API/tests/minidom.js | 110 ++ Source/JavaScriptCore/API/tests/testapi.c | 1458 ++++++++++++++++++++++++++ Source/JavaScriptCore/API/tests/testapi.js | 251 +++++ 13 files changed, 2602 insertions(+) create mode 100644 Source/JavaScriptCore/API/tests/JSNode.c create mode 100644 Source/JavaScriptCore/API/tests/JSNode.h create mode 100644 Source/JavaScriptCore/API/tests/JSNodeList.c create mode 100644 Source/JavaScriptCore/API/tests/JSNodeList.h create mode 100644 Source/JavaScriptCore/API/tests/Node.c create mode 100644 Source/JavaScriptCore/API/tests/Node.h create mode 100644 Source/JavaScriptCore/API/tests/NodeList.c create mode 100644 Source/JavaScriptCore/API/tests/NodeList.h create mode 100644 Source/JavaScriptCore/API/tests/minidom.c create mode 100644 Source/JavaScriptCore/API/tests/minidom.html create mode 100644 Source/JavaScriptCore/API/tests/minidom.js create mode 100644 Source/JavaScriptCore/API/tests/testapi.c create mode 100644 Source/JavaScriptCore/API/tests/testapi.js (limited to 'Source/JavaScriptCore/API/tests') diff --git a/Source/JavaScriptCore/API/tests/JSNode.c b/Source/JavaScriptCore/API/tests/JSNode.c new file mode 100644 index 0000000..d9ac0a9 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/JSNode.c @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "JSNode.h" +#include "JSNodeList.h" +#include "JSObjectRef.h" +#include "JSStringRef.h" +#include "JSValueRef.h" +#include "Node.h" +#include "NodeList.h" +#include "UnusedParam.h" +#include + +static JSValueRef JSNode_appendChild(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(function); + + /* Example of throwing a type error for invalid values */ + if (!JSValueIsObjectOfClass(context, thisObject, JSNode_class(context))) { + JSStringRef message = JSStringCreateWithUTF8CString("TypeError: appendChild can only be called on nodes"); + *exception = JSValueMakeString(context, message); + JSStringRelease(message); + } else if (argumentCount < 1 || !JSValueIsObjectOfClass(context, arguments[0], JSNode_class(context))) { + JSStringRef message = JSStringCreateWithUTF8CString("TypeError: first argument to appendChild must be a node"); + *exception = JSValueMakeString(context, message); + JSStringRelease(message); + } else { + Node* node = JSObjectGetPrivate(thisObject); + Node* child = JSObjectGetPrivate(JSValueToObject(context, arguments[0], NULL)); + + Node_appendChild(node, child); + } + + return JSValueMakeUndefined(context); +} + +static JSValueRef JSNode_removeChild(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(function); + + /* Example of ignoring invalid values */ + if (argumentCount > 0) { + if (JSValueIsObjectOfClass(context, thisObject, JSNode_class(context))) { + if (JSValueIsObjectOfClass(context, arguments[0], JSNode_class(context))) { + Node* node = JSObjectGetPrivate(thisObject); + Node* child = JSObjectGetPrivate(JSValueToObject(context, arguments[0], exception)); + + Node_removeChild(node, child); + } + } + } + + return JSValueMakeUndefined(context); +} + +static JSValueRef JSNode_replaceChild(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(function); + + if (argumentCount > 1) { + if (JSValueIsObjectOfClass(context, thisObject, JSNode_class(context))) { + if (JSValueIsObjectOfClass(context, arguments[0], JSNode_class(context))) { + if (JSValueIsObjectOfClass(context, arguments[1], JSNode_class(context))) { + Node* node = JSObjectGetPrivate(thisObject); + Node* newChild = JSObjectGetPrivate(JSValueToObject(context, arguments[0], exception)); + Node* oldChild = JSObjectGetPrivate(JSValueToObject(context, arguments[1], exception)); + + Node_replaceChild(node, newChild, oldChild); + } + } + } + } + + return JSValueMakeUndefined(context); +} + +static JSStaticFunction JSNode_staticFunctions[] = { + { "appendChild", JSNode_appendChild, kJSPropertyAttributeDontDelete }, + { "removeChild", JSNode_removeChild, kJSPropertyAttributeDontDelete }, + { "replaceChild", JSNode_replaceChild, kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } +}; + +static JSValueRef JSNode_getNodeType(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + UNUSED_PARAM(propertyName); + UNUSED_PARAM(exception); + + Node* node = JSObjectGetPrivate(object); + if (node) { + JSStringRef nodeType = JSStringCreateWithUTF8CString(node->nodeType); + JSValueRef value = JSValueMakeString(context, nodeType); + JSStringRelease(nodeType); + return value; + } + + return NULL; +} + +static JSValueRef JSNode_getChildNodes(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + UNUSED_PARAM(propertyName); + UNUSED_PARAM(exception); + + Node* node = JSObjectGetPrivate(thisObject); + ASSERT(node); + return JSNodeList_new(context, NodeList_new(node)); +} + +static JSValueRef JSNode_getFirstChild(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + UNUSED_PARAM(object); + UNUSED_PARAM(propertyName); + UNUSED_PARAM(exception); + + return JSValueMakeUndefined(context); +} + +static JSStaticValue JSNode_staticValues[] = { + { "nodeType", JSNode_getNodeType, NULL, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly }, + { "childNodes", JSNode_getChildNodes, NULL, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly }, + { "firstChild", JSNode_getFirstChild, NULL, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly }, + { 0, 0, 0, 0 } +}; + +static void JSNode_initialize(JSContextRef context, JSObjectRef object) +{ + UNUSED_PARAM(context); + + Node* node = JSObjectGetPrivate(object); + ASSERT(node); + + Node_ref(node); +} + +static void JSNode_finalize(JSObjectRef object) +{ + Node* node = JSObjectGetPrivate(object); + ASSERT(node); + + Node_deref(node); +} + +JSClassRef JSNode_class(JSContextRef context) +{ + UNUSED_PARAM(context); + + static JSClassRef jsClass; + if (!jsClass) { + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.staticValues = JSNode_staticValues; + definition.staticFunctions = JSNode_staticFunctions; + definition.initialize = JSNode_initialize; + definition.finalize = JSNode_finalize; + + jsClass = JSClassCreate(&definition); + } + return jsClass; +} + +JSObjectRef JSNode_new(JSContextRef context, Node* node) +{ + return JSObjectMake(context, JSNode_class(context), node); +} + +JSObjectRef JSNode_construct(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(object); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + UNUSED_PARAM(exception); + + return JSNode_new(context, Node_new()); +} diff --git a/Source/JavaScriptCore/API/tests/JSNode.h b/Source/JavaScriptCore/API/tests/JSNode.h new file mode 100644 index 0000000..7725733 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/JSNode.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSNode_h +#define JSNode_h + +#include "JSBase.h" +#include "Node.h" +#include + +extern JSObjectRef JSNode_new(JSContextRef context, Node* node); +extern JSClassRef JSNode_class(JSContextRef context); +extern JSObjectRef JSNode_construct(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); + +#endif /* JSNode_h */ diff --git a/Source/JavaScriptCore/API/tests/JSNodeList.c b/Source/JavaScriptCore/API/tests/JSNodeList.c new file mode 100644 index 0000000..bc4a8ad --- /dev/null +++ b/Source/JavaScriptCore/API/tests/JSNodeList.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "JSNode.h" +#include "JSNodeList.h" +#include "JSObjectRef.h" +#include "JSValueRef.h" +#include "UnusedParam.h" +#include + +static JSValueRef JSNodeList_item(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(object); + + if (argumentCount > 0) { + NodeList* nodeList = JSObjectGetPrivate(thisObject); + ASSERT(nodeList); + Node* node = NodeList_item(nodeList, (unsigned)JSValueToNumber(context, arguments[0], exception)); + if (node) + return JSNode_new(context, node); + } + + return JSValueMakeUndefined(context); +} + +static JSStaticFunction JSNodeList_staticFunctions[] = { + { "item", JSNodeList_item, kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } +}; + +static JSValueRef JSNodeList_length(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + UNUSED_PARAM(propertyName); + UNUSED_PARAM(exception); + + NodeList* nodeList = JSObjectGetPrivate(thisObject); + ASSERT(nodeList); + return JSValueMakeNumber(context, NodeList_length(nodeList)); +} + +static JSStaticValue JSNodeList_staticValues[] = { + { "length", JSNodeList_length, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0, 0 } +}; + +static JSValueRef JSNodeList_getProperty(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) +{ + NodeList* nodeList = JSObjectGetPrivate(thisObject); + ASSERT(nodeList); + double index = JSValueToNumber(context, JSValueMakeString(context, propertyName), exception); + unsigned uindex = (unsigned)index; + if (uindex == index) { /* false for NaN */ + Node* node = NodeList_item(nodeList, uindex); + if (node) + return JSNode_new(context, node); + } + + return NULL; +} + +static void JSNodeList_initialize(JSContextRef context, JSObjectRef thisObject) +{ + UNUSED_PARAM(context); + + NodeList* nodeList = JSObjectGetPrivate(thisObject); + ASSERT(nodeList); + + NodeList_ref(nodeList); +} + +static void JSNodeList_finalize(JSObjectRef thisObject) +{ + NodeList* nodeList = JSObjectGetPrivate(thisObject); + ASSERT(nodeList); + + NodeList_deref(nodeList); +} + +static JSClassRef JSNodeList_class(JSContextRef context) +{ + UNUSED_PARAM(context); + + static JSClassRef jsClass; + if (!jsClass) { + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.staticValues = JSNodeList_staticValues; + definition.staticFunctions = JSNodeList_staticFunctions; + definition.getProperty = JSNodeList_getProperty; + definition.initialize = JSNodeList_initialize; + definition.finalize = JSNodeList_finalize; + + jsClass = JSClassCreate(&definition); + } + + return jsClass; +} + +JSObjectRef JSNodeList_new(JSContextRef context, NodeList* nodeList) +{ + return JSObjectMake(context, JSNodeList_class(context), nodeList); +} diff --git a/Source/JavaScriptCore/API/tests/JSNodeList.h b/Source/JavaScriptCore/API/tests/JSNodeList.h new file mode 100644 index 0000000..f930914 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/JSNodeList.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSNodeList_h +#define JSNodeList_h + +#include "JSBase.h" +#include "NodeList.h" + +extern JSObjectRef JSNodeList_new(JSContextRef, NodeList*); + +#endif /* JSNodeList_h */ diff --git a/Source/JavaScriptCore/API/tests/Node.c b/Source/JavaScriptCore/API/tests/Node.c new file mode 100644 index 0000000..913da0a --- /dev/null +++ b/Source/JavaScriptCore/API/tests/Node.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Node.h" +#include +#include + +Node* Node_new(void) +{ + Node* node = (Node*)malloc(sizeof(Node)); + node->refCount = 0; + node->nodeType = "Node"; + node->childNodesTail = NULL; + + return node; +} + +void Node_appendChild(Node* node, Node* child) +{ + Node_ref(child); + NodeLink* nodeLink = (NodeLink*)malloc(sizeof(NodeLink)); + nodeLink->node = child; + nodeLink->prev = node->childNodesTail; + node->childNodesTail = nodeLink; +} + +void Node_removeChild(Node* node, Node* child) +{ + /* Linear search from tail -- good enough for our purposes here */ + NodeLink* current; + NodeLink** currentHandle; + for (currentHandle = &node->childNodesTail, current = *currentHandle; current; currentHandle = ¤t->prev, current = *currentHandle) { + if (current->node == child) { + Node_deref(current->node); + *currentHandle = current->prev; + free(current); + break; + } + } +} + +void Node_replaceChild(Node* node, Node* newChild, Node* oldChild) +{ + /* Linear search from tail -- good enough for our purposes here */ + NodeLink* current; + for (current = node->childNodesTail; current; current = current->prev) { + if (current->node == oldChild) { + Node_deref(current->node); + current->node = newChild; + } + } +} + +void Node_ref(Node* node) +{ + ++node->refCount; +} + +void Node_deref(Node* node) +{ + if (--node->refCount == 0) + free(node); +} diff --git a/Source/JavaScriptCore/API/tests/Node.h b/Source/JavaScriptCore/API/tests/Node.h new file mode 100644 index 0000000..e9250b3 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/Node.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Node_h +#define Node_h + +typedef struct __Node Node; +typedef struct __NodeLink NodeLink; + +struct __NodeLink { + Node* node; + NodeLink* prev; +}; + +struct __Node { + unsigned refCount; + const char* nodeType; + NodeLink* childNodesTail; +}; + +extern Node* Node_new(void); +extern void Node_ref(Node* node); +extern void Node_deref(Node* node); +extern void Node_appendChild(Node* node, Node* child); +extern void Node_removeChild(Node* node, Node* child); +extern void Node_replaceChild(Node* node, Node* newChild, Node* oldChild); + +#endif /* Node_h */ diff --git a/Source/JavaScriptCore/API/tests/NodeList.c b/Source/JavaScriptCore/API/tests/NodeList.c new file mode 100644 index 0000000..ae4c170 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/NodeList.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "NodeList.h" + +#include + +extern NodeList* NodeList_new(Node* parentNode) +{ + Node_ref(parentNode); + + NodeList* nodeList = (NodeList*)malloc(sizeof(NodeList)); + nodeList->parentNode = parentNode; + nodeList->refCount = 0; + return nodeList; +} + +extern unsigned NodeList_length(NodeList* nodeList) +{ + /* Linear count from tail -- good enough for our purposes here */ + unsigned i = 0; + NodeLink* n = nodeList->parentNode->childNodesTail; + while (n) { + n = n->prev; + ++i; + } + + return i; +} + +extern Node* NodeList_item(NodeList* nodeList, unsigned index) +{ + unsigned length = NodeList_length(nodeList); + if (index >= length) + return NULL; + + /* Linear search from tail -- good enough for our purposes here */ + NodeLink* n = nodeList->parentNode->childNodesTail; + unsigned i = 0; + unsigned count = length - 1 - index; + while (i < count) { + ++i; + n = n->prev; + } + return n->node; +} + +extern void NodeList_ref(NodeList* nodeList) +{ + ++nodeList->refCount; +} + +extern void NodeList_deref(NodeList* nodeList) +{ + if (--nodeList->refCount == 0) { + Node_deref(nodeList->parentNode); + free(nodeList); + } +} diff --git a/Source/JavaScriptCore/API/tests/NodeList.h b/Source/JavaScriptCore/API/tests/NodeList.h new file mode 100644 index 0000000..25b95bf --- /dev/null +++ b/Source/JavaScriptCore/API/tests/NodeList.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NodeList_h +#define NodeList_h + +#include "Node.h" + +typedef struct { + unsigned refCount; + Node* parentNode; +} NodeList; + +extern NodeList* NodeList_new(Node* parentNode); +extern unsigned NodeList_length(NodeList*); +extern Node* NodeList_item(NodeList*, unsigned); +extern void NodeList_ref(NodeList*); +extern void NodeList_deref(NodeList*); + +#endif /* NodeList_h */ diff --git a/Source/JavaScriptCore/API/tests/minidom.c b/Source/JavaScriptCore/API/tests/minidom.c new file mode 100644 index 0000000..43ae2c1 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/minidom.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007 Alp Toker + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "JSContextRef.h" +#include "JSNode.h" +#include "JSObjectRef.h" +#include "JSStringRef.h" +#include +#include +#include +#include + +static char* createStringWithContentsOfFile(const char* fileName); +static JSValueRef print(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); + +int main(int argc, char* argv[]) +{ + const char *scriptPath = "minidom.js"; + if (argc > 1) { + scriptPath = argv[1]; + } + + JSGlobalContextRef context = JSGlobalContextCreateInGroup(NULL, NULL); + JSObjectRef globalObject = JSContextGetGlobalObject(context); + + JSStringRef printIString = JSStringCreateWithUTF8CString("print"); + JSObjectSetProperty(context, globalObject, printIString, JSObjectMakeFunctionWithCallback(context, printIString, print), kJSPropertyAttributeNone, NULL); + JSStringRelease(printIString); + + JSStringRef node = JSStringCreateWithUTF8CString("Node"); + JSObjectSetProperty(context, globalObject, node, JSObjectMakeConstructor(context, JSNode_class(context), JSNode_construct), kJSPropertyAttributeNone, NULL); + JSStringRelease(node); + + char* scriptUTF8 = createStringWithContentsOfFile(scriptPath); + JSStringRef script = JSStringCreateWithUTF8CString(scriptUTF8); + JSValueRef exception; + JSValueRef result = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); + if (result) + printf("PASS: Test script executed successfully.\n"); + else { + printf("FAIL: Test script threw exception:\n"); + JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL); + size_t exceptionUTF8Size = JSStringGetMaximumUTF8CStringSize(exceptionIString); + char* exceptionUTF8 = (char*)malloc(exceptionUTF8Size); + JSStringGetUTF8CString(exceptionIString, exceptionUTF8, exceptionUTF8Size); + printf("%s\n", exceptionUTF8); + free(exceptionUTF8); + JSStringRelease(exceptionIString); + } + JSStringRelease(script); + free(scriptUTF8); + + globalObject = 0; + JSGlobalContextRelease(context); + printf("PASS: Program exited normally.\n"); + return 0; +} + +static JSValueRef print(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(object); + UNUSED_PARAM(thisObject); + + if (argumentCount > 0) { + JSStringRef string = JSValueToStringCopy(context, arguments[0], exception); + size_t numChars = JSStringGetMaximumUTF8CStringSize(string); + char stringUTF8[numChars]; + JSStringGetUTF8CString(string, stringUTF8, numChars); + printf("%s\n", stringUTF8); + } + + return JSValueMakeUndefined(context); +} + +static char* createStringWithContentsOfFile(const char* fileName) +{ + char* buffer; + + size_t buffer_size = 0; + size_t buffer_capacity = 1024; + buffer = (char*)malloc(buffer_capacity); + + FILE* f = fopen(fileName, "r"); + if (!f) { + fprintf(stderr, "Could not open file: %s\n", fileName); + return 0; + } + + while (!feof(f) && !ferror(f)) { + buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f); + if (buffer_size == buffer_capacity) { /* guarantees space for trailing '\0' */ + buffer_capacity *= 2; + buffer = (char*)realloc(buffer, buffer_capacity); + ASSERT(buffer); + } + + ASSERT(buffer_size < buffer_capacity); + } + fclose(f); + buffer[buffer_size] = '\0'; + + return buffer; +} diff --git a/Source/JavaScriptCore/API/tests/minidom.html b/Source/JavaScriptCore/API/tests/minidom.html new file mode 100644 index 0000000..7ea4747 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/minidom.html @@ -0,0 +1,9 @@ + + + + + + +

+
+
diff --git a/Source/JavaScriptCore/API/tests/minidom.js b/Source/JavaScriptCore/API/tests/minidom.js
new file mode 100644
index 0000000..4808960
--- /dev/null
+++ b/Source/JavaScriptCore/API/tests/minidom.js
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+function shouldBe(a, b)
+{
+    var evalA;
+    try {
+        evalA = eval(a);
+    } catch(e) {
+        evalA = e;
+    }
+    
+    if (evalA == b || isNaN(evalA) && typeof evalA == 'number' && isNaN(b) && typeof b == 'number')
+        print("PASS: " + a + " should be " + b + " and is.", "green");
+    else
+        print("__FAIL__: " + a + " should be " + b + " but instead is " + evalA + ".", "red");
+}
+
+function test()
+{
+    print("Node is " + Node);
+    for (var p in Node)
+        print(p + ": " + Node[p]);
+    
+    node = new Node();
+    print("node is " + node);
+    for (var p in node)
+        print(p + ": " + node[p]);
+
+    child1 = new Node();
+    child2 = new Node();
+    child3 = new Node();
+    
+    node.appendChild(child1);
+    node.appendChild(child2);
+
+    var childNodes = node.childNodes;
+    
+    for (var i = 0; i < childNodes.length + 1; i++) {
+        print("item " + i + ": " + childNodes.item(i));
+    }
+    
+    for (var i = 0; i < childNodes.length + 1; i++) {
+        print(i + ": " + childNodes[i]);
+    }
+
+    node.removeChild(child1);
+    node.replaceChild(child3, child2);
+    
+    for (var i = 0; i < childNodes.length + 1; i++) {
+        print("item " + i + ": " + childNodes.item(i));
+    }
+
+    for (var i = 0; i < childNodes.length + 1; i++) {
+        print(i + ": " + childNodes[i]);
+    }
+
+    try {
+        node.appendChild(null);
+    } catch(e) {
+        print("caught: " + e);
+    }
+    
+    try {
+        var o = new Object();
+        o.appendChild = node.appendChild;
+        o.appendChild(node);
+    } catch(e) {
+        print("caught: " + e);
+    }
+    
+    try {
+        node.appendChild();
+    } catch(e) {
+        print("caught: " + e);
+    }
+    
+    oldNodeType = node.nodeType;
+    node.nodeType = 1;
+    shouldBe("node.nodeType", oldNodeType);
+    
+    shouldBe("node instanceof Node", true);
+    shouldBe("new Object() instanceof Node", false);
+    
+    print(Node);
+}
+
+test();
diff --git a/Source/JavaScriptCore/API/tests/testapi.c b/Source/JavaScriptCore/API/tests/testapi.c
new file mode 100644
index 0000000..1ecfc7e
--- /dev/null
+++ b/Source/JavaScriptCore/API/tests/testapi.c
@@ -0,0 +1,1458 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "JavaScriptCore.h"
+#include "JSBasePrivate.h"
+#include "JSContextRefPrivate.h"
+#include "JSObjectRefPrivate.h"
+#include 
+#define ASSERT_DISABLED 0
+#include 
+#include 
+
+#if COMPILER(MSVC)
+
+#include 
+
+static double nan(const char*)
+{
+    return std::numeric_limits::quiet_NaN();
+}
+
+#endif
+
+static JSGlobalContextRef context;
+static int failed;
+static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue)
+{
+    if (JSValueToBoolean(context, value) != expectedValue) {
+        fprintf(stderr, "assertEqualsAsBoolean failed: %p, %d\n", value, expectedValue);
+        failed = 1;
+    }
+}
+
+static void assertEqualsAsNumber(JSValueRef value, double expectedValue)
+{
+    double number = JSValueToNumber(context, value, NULL);
+
+    // FIXME  - On i386 the isnan(double) macro tries to map to the isnan(float) function,
+    // causing a build break with -Wshorten-64-to-32 enabled.  The issue is known by the appropriate team.
+    // After that's resolved, we can remove these casts
+    if (number != expectedValue && !(isnan((float)number) && isnan((float)expectedValue))) {
+        fprintf(stderr, "assertEqualsAsNumber failed: %p, %lf\n", value, expectedValue);
+        failed = 1;
+    }
+}
+
+static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue)
+{
+    JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
+
+    size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString);
+    char* jsBuffer = (char*)malloc(jsSize);
+    JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize);
+    
+    unsigned i;
+    for (i = 0; jsBuffer[i]; i++) {
+        if (jsBuffer[i] != expectedValue[i]) {
+            fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]);
+            failed = 1;
+        }
+    }
+
+    if (jsSize < strlen(jsBuffer) + 1) {
+        fprintf(stderr, "assertEqualsAsUTF8String failed: jsSize was too small\n");
+        failed = 1;
+    }
+
+    free(jsBuffer);
+    JSStringRelease(valueAsString);
+}
+
+static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedValue)
+{
+    JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
+
+    size_t jsLength = JSStringGetLength(valueAsString);
+    const JSChar* jsBuffer = JSStringGetCharactersPtr(valueAsString);
+
+    CFStringRef expectedValueAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, 
+                                                                    expectedValue,
+                                                                    kCFStringEncodingUTF8);    
+    CFIndex cfLength = CFStringGetLength(expectedValueAsCFString);
+    UniChar* cfBuffer = (UniChar*)malloc(cfLength * sizeof(UniChar));
+    CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer);
+    CFRelease(expectedValueAsCFString);
+
+    if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0) {
+        fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n");
+        failed = 1;
+    }
+    
+    if (jsLength != (size_t)cfLength) {
+        fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength);
+        failed = 1;
+    }
+
+    free(cfBuffer);
+    JSStringRelease(valueAsString);
+}
+
+static bool timeZoneIsPST()
+{
+    char timeZoneName[70];
+    struct tm gtm;
+    memset(>m, 0, sizeof(gtm));
+    strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m);
+
+    return 0 == strcmp("PST", timeZoneName);
+}
+
+static JSValueRef jsGlobalValue; // non-stack value for testing JSValueProtect()
+
+/* MyObject pseudo-class */
+
+static bool MyObject_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(object);
+
+    if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")
+        || JSStringIsEqualToUTF8CString(propertyName, "cantFind")
+        || JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")
+        || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")
+        || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")
+        || JSStringIsEqualToUTF8CString(propertyName, "0")) {
+        return true;
+    }
+    
+    return false;
+}
+
+static JSValueRef MyObject_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(object);
+    
+    if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")) {
+        return JSValueMakeNumber(context, 1);
+    }
+    
+    if (JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")) {
+        return JSValueMakeNumber(context, 1);
+    }
+
+    if (JSStringIsEqualToUTF8CString(propertyName, "cantFind")) {
+        return JSValueMakeUndefined(context);
+    }
+    
+    if (JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")) {
+        return 0;
+    }
+
+    if (JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")) {
+        return JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
+    }
+
+    if (JSStringIsEqualToUTF8CString(propertyName, "0")) {
+        *exception = JSValueMakeNumber(context, 1);
+        return JSValueMakeNumber(context, 1);
+    }
+    
+    return JSValueMakeNull(context);
+}
+
+static bool MyObject_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(value);
+    UNUSED_PARAM(exception);
+
+    if (JSStringIsEqualToUTF8CString(propertyName, "cantSet"))
+        return true; // pretend we set the property in order to swallow it
+    
+    if (JSStringIsEqualToUTF8CString(propertyName, "throwOnSet")) {
+        JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
+    }
+    
+    return false;
+}
+
+static bool MyObject_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(object);
+    
+    if (JSStringIsEqualToUTF8CString(propertyName, "cantDelete"))
+        return true;
+    
+    if (JSStringIsEqualToUTF8CString(propertyName, "throwOnDelete")) {
+        JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
+        return false;
+    }
+
+    return false;
+}
+
+static void MyObject_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(object);
+    
+    JSStringRef propertyName;
+    
+    propertyName = JSStringCreateWithUTF8CString("alwaysOne");
+    JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
+    JSStringRelease(propertyName);
+    
+    propertyName = JSStringCreateWithUTF8CString("myPropertyName");
+    JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
+    JSStringRelease(propertyName);
+}
+
+static JSValueRef MyObject_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(thisObject);
+    UNUSED_PARAM(exception);
+
+    if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnCall")) {
+        JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
+        return JSValueMakeUndefined(context);
+    }
+
+    if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
+        return JSValueMakeNumber(context, 1);
+    
+    return JSValueMakeUndefined(context);
+}
+
+static JSObjectRef MyObject_callAsConstructor(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(object);
+
+    if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnConstruct")) {
+        JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
+        return object;
+    }
+
+    if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
+        return JSValueToObject(context, JSValueMakeNumber(context, 1), exception);
+    
+    return JSValueToObject(context, JSValueMakeNumber(context, 0), exception);
+}
+
+static bool MyObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(constructor);
+
+    if (JSValueIsString(context, possibleValue) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, possibleValue, 0), "throwOnHasInstance")) {
+        JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), constructor, JSStringCreateWithUTF8CString("test script"), 1, exception);
+        return false;
+    }
+
+    JSStringRef numberString = JSStringCreateWithUTF8CString("Number");
+    JSObjectRef numberConstructor = JSValueToObject(context, JSObjectGetProperty(context, JSContextGetGlobalObject(context), numberString, exception), exception);
+    JSStringRelease(numberString);
+
+    return JSValueIsInstanceOfConstructor(context, possibleValue, numberConstructor, exception);
+}
+
+static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
+{
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(exception);
+    
+    switch (type) {
+    case kJSTypeNumber:
+        return JSValueMakeNumber(context, 1);
+    case kJSTypeString:
+        {
+            JSStringRef string = JSStringCreateWithUTF8CString("MyObjectAsString");
+            JSValueRef result = JSValueMakeString(context, string);
+            JSStringRelease(string);
+            return result;
+        }
+    default:
+        break;
+    }
+
+    // string conversion -- forward to default object class
+    return JSValueMakeNull(context);
+}
+
+static JSStaticValue evilStaticValues[] = {
+    { "nullGetSet", 0, 0, kJSPropertyAttributeNone },
+    { 0, 0, 0, 0 }
+};
+
+static JSStaticFunction evilStaticFunctions[] = {
+    { "nullCall", 0, kJSPropertyAttributeNone },
+    { 0, 0, 0 }
+};
+
+JSClassDefinition MyObject_definition = {
+    0,
+    kJSClassAttributeNone,
+    
+    "MyObject",
+    NULL,
+    
+    evilStaticValues,
+    evilStaticFunctions,
+    
+    NULL,
+    NULL,
+    MyObject_hasProperty,
+    MyObject_getProperty,
+    MyObject_setProperty,
+    MyObject_deleteProperty,
+    MyObject_getPropertyNames,
+    MyObject_callAsFunction,
+    MyObject_callAsConstructor,
+    MyObject_hasInstance,
+    MyObject_convertToType,
+};
+
+static JSClassRef MyObject_class(JSContextRef context)
+{
+    UNUSED_PARAM(context);
+
+    static JSClassRef jsClass;
+    if (!jsClass)
+        jsClass = JSClassCreate(&MyObject_definition);
+    
+    return jsClass;
+}
+
+static bool EvilExceptionObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(constructor);
+    
+    JSStringRef hasInstanceName = JSStringCreateWithUTF8CString("hasInstance");
+    JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception);
+    JSStringRelease(hasInstanceName);
+    if (!hasInstance)
+        return false;
+    JSObjectRef function = JSValueToObject(context, hasInstance, exception);
+    JSValueRef result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception);
+    return result && JSValueToBoolean(context, result);
+}
+
+static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
+{
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(exception);
+    JSStringRef funcName;
+    switch (type) {
+    case kJSTypeNumber:
+        funcName = JSStringCreateWithUTF8CString("toNumber");
+        break;
+    case kJSTypeString:
+        funcName = JSStringCreateWithUTF8CString("toStringExplicit");
+        break;
+    default:
+        return JSValueMakeNull(context);
+        break;
+    }
+    
+    JSValueRef func = JSObjectGetProperty(context, object, funcName, exception);
+    JSStringRelease(funcName);    
+    JSObjectRef function = JSValueToObject(context, func, exception);
+    if (!function)
+        return JSValueMakeNull(context);
+    JSValueRef value = JSObjectCallAsFunction(context, function, object, 0, NULL, exception);
+    if (!value) {
+        JSStringRef errorString = JSStringCreateWithUTF8CString("convertToType failed"); 
+        JSValueRef errorStringRef = JSValueMakeString(context, errorString);
+        JSStringRelease(errorString);
+        return errorStringRef;
+    }
+    return value;
+}
+
+JSClassDefinition EvilExceptionObject_definition = {
+    0,
+    kJSClassAttributeNone,
+
+    "EvilExceptionObject",
+    NULL,
+
+    NULL,
+    NULL,
+
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    EvilExceptionObject_hasInstance,
+    EvilExceptionObject_convertToType,
+};
+
+static JSClassRef EvilExceptionObject_class(JSContextRef context)
+{
+    UNUSED_PARAM(context);
+    
+    static JSClassRef jsClass;
+    if (!jsClass)
+        jsClass = JSClassCreate(&EvilExceptionObject_definition);
+    
+    return jsClass;
+}
+
+JSClassDefinition EmptyObject_definition = {
+    0,
+    kJSClassAttributeNone,
+    
+    NULL,
+    NULL,
+    
+    NULL,
+    NULL,
+    
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+};
+
+static JSClassRef EmptyObject_class(JSContextRef context)
+{
+    UNUSED_PARAM(context);
+    
+    static JSClassRef jsClass;
+    if (!jsClass)
+        jsClass = JSClassCreate(&EmptyObject_definition);
+    
+    return jsClass;
+}
+
+
+static JSValueRef Base_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
+{
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(propertyName);
+    UNUSED_PARAM(exception);
+
+    return JSValueMakeNumber(ctx, 1); // distinguish base get form derived get
+}
+
+static bool Base_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
+{
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(propertyName);
+    UNUSED_PARAM(value);
+
+    *exception = JSValueMakeNumber(ctx, 1); // distinguish base set from derived set
+    return true;
+}
+
+static JSValueRef Base_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    UNUSED_PARAM(function);
+    UNUSED_PARAM(thisObject);
+    UNUSED_PARAM(argumentCount);
+    UNUSED_PARAM(arguments);
+    UNUSED_PARAM(exception);
+    
+    return JSValueMakeNumber(ctx, 1); // distinguish base call from derived call
+}
+
+static JSStaticFunction Base_staticFunctions[] = {
+    { "baseProtoDup", NULL, kJSPropertyAttributeNone },
+    { "baseProto", Base_callAsFunction, kJSPropertyAttributeNone },
+    { 0, 0, 0 }
+};
+
+static JSStaticValue Base_staticValues[] = {
+    { "baseDup", Base_get, Base_set, kJSPropertyAttributeNone },
+    { "baseOnly", Base_get, Base_set, kJSPropertyAttributeNone },
+    { 0, 0, 0, 0 }
+};
+
+static bool TestInitializeFinalize;
+static void Base_initialize(JSContextRef context, JSObjectRef object)
+{
+    UNUSED_PARAM(context);
+
+    if (TestInitializeFinalize) {
+        ASSERT((void*)1 == JSObjectGetPrivate(object));
+        JSObjectSetPrivate(object, (void*)2);
+    }
+}
+
+static unsigned Base_didFinalize;
+static void Base_finalize(JSObjectRef object)
+{
+    UNUSED_PARAM(object);
+    if (TestInitializeFinalize) {
+        ASSERT((void*)4 == JSObjectGetPrivate(object));
+        Base_didFinalize = true;
+    }
+}
+
+static JSClassRef Base_class(JSContextRef context)
+{
+    UNUSED_PARAM(context);
+
+    static JSClassRef jsClass;
+    if (!jsClass) {
+        JSClassDefinition definition = kJSClassDefinitionEmpty;
+        definition.staticValues = Base_staticValues;
+        definition.staticFunctions = Base_staticFunctions;
+        definition.initialize = Base_initialize;
+        definition.finalize = Base_finalize;
+        jsClass = JSClassCreate(&definition);
+    }
+    return jsClass;
+}
+
+static JSValueRef Derived_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
+{
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(propertyName);
+    UNUSED_PARAM(exception);
+
+    return JSValueMakeNumber(ctx, 2); // distinguish base get form derived get
+}
+
+static bool Derived_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
+{
+    UNUSED_PARAM(ctx);
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(propertyName);
+    UNUSED_PARAM(value);
+
+    *exception = JSValueMakeNumber(ctx, 2); // distinguish base set from derived set
+    return true;
+}
+
+static JSValueRef Derived_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    UNUSED_PARAM(function);
+    UNUSED_PARAM(thisObject);
+    UNUSED_PARAM(argumentCount);
+    UNUSED_PARAM(arguments);
+    UNUSED_PARAM(exception);
+    
+    return JSValueMakeNumber(ctx, 2); // distinguish base call from derived call
+}
+
+static JSStaticFunction Derived_staticFunctions[] = {
+    { "protoOnly", Derived_callAsFunction, kJSPropertyAttributeNone },
+    { "protoDup", NULL, kJSPropertyAttributeNone },
+    { "baseProtoDup", Derived_callAsFunction, kJSPropertyAttributeNone },
+    { 0, 0, 0 }
+};
+
+static JSStaticValue Derived_staticValues[] = {
+    { "derivedOnly", Derived_get, Derived_set, kJSPropertyAttributeNone },
+    { "protoDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
+    { "baseDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
+    { 0, 0, 0, 0 }
+};
+
+static void Derived_initialize(JSContextRef context, JSObjectRef object)
+{
+    UNUSED_PARAM(context);
+
+    if (TestInitializeFinalize) {
+        ASSERT((void*)2 == JSObjectGetPrivate(object));
+        JSObjectSetPrivate(object, (void*)3);
+    }
+}
+
+static void Derived_finalize(JSObjectRef object)
+{
+    if (TestInitializeFinalize) {
+        ASSERT((void*)3 == JSObjectGetPrivate(object));
+        JSObjectSetPrivate(object, (void*)4);
+    }
+}
+
+static JSClassRef Derived_class(JSContextRef context)
+{
+    static JSClassRef jsClass;
+    if (!jsClass) {
+        JSClassDefinition definition = kJSClassDefinitionEmpty;
+        definition.parentClass = Base_class(context);
+        definition.staticValues = Derived_staticValues;
+        definition.staticFunctions = Derived_staticFunctions;
+        definition.initialize = Derived_initialize;
+        definition.finalize = Derived_finalize;
+        jsClass = JSClassCreate(&definition);
+    }
+    return jsClass;
+}
+
+static JSClassRef Derived2_class(JSContextRef context)
+{
+    static JSClassRef jsClass;
+    if (!jsClass) {
+        JSClassDefinition definition = kJSClassDefinitionEmpty;
+        definition.parentClass = Derived_class(context);
+        jsClass = JSClassCreate(&definition);
+    }
+    return jsClass;
+}
+
+static JSValueRef print_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    UNUSED_PARAM(functionObject);
+    UNUSED_PARAM(thisObject);
+    UNUSED_PARAM(exception);
+
+    ASSERT(JSContextGetGlobalContext(ctx) == context);
+    
+    if (argumentCount > 0) {
+        JSStringRef string = JSValueToStringCopy(ctx, arguments[0], NULL);
+        size_t sizeUTF8 = JSStringGetMaximumUTF8CStringSize(string);
+        char* stringUTF8 = (char*)malloc(sizeUTF8);
+        JSStringGetUTF8CString(string, stringUTF8, sizeUTF8);
+        printf("%s\n", stringUTF8);
+        free(stringUTF8);
+        JSStringRelease(string);
+    }
+    
+    return JSValueMakeUndefined(ctx);
+}
+
+static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    UNUSED_PARAM(constructorObject);
+    UNUSED_PARAM(exception);
+    
+    JSObjectRef result = JSObjectMake(context, NULL, NULL);
+    if (argumentCount > 0) {
+        JSStringRef value = JSStringCreateWithUTF8CString("value");
+        JSObjectSetProperty(context, result, value, arguments[0], kJSPropertyAttributeNone, NULL);
+        JSStringRelease(value);
+    }
+    
+    return result;
+}
+
+
+static void globalObject_initialize(JSContextRef context, JSObjectRef object)
+{
+    UNUSED_PARAM(object);
+    // Ensure that an execution context is passed in
+    ASSERT(context);
+
+    // Ensure that the global object is set to the object that we were passed
+    JSObjectRef globalObject = JSContextGetGlobalObject(context);
+    ASSERT(globalObject);
+    ASSERT(object == globalObject);
+
+    // Ensure that the standard global properties have been set on the global object
+    JSStringRef array = JSStringCreateWithUTF8CString("Array");
+    JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
+    JSStringRelease(array);
+
+    UNUSED_PARAM(arrayConstructor);
+    ASSERT(arrayConstructor);
+}
+
+static JSValueRef globalObject_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
+{
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(propertyName);
+    UNUSED_PARAM(exception);
+
+    return JSValueMakeNumber(ctx, 3);
+}
+
+static bool globalObject_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
+{
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(propertyName);
+    UNUSED_PARAM(value);
+
+    *exception = JSValueMakeNumber(ctx, 3);
+    return true;
+}
+
+static JSValueRef globalObject_call(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    UNUSED_PARAM(function);
+    UNUSED_PARAM(thisObject);
+    UNUSED_PARAM(argumentCount);
+    UNUSED_PARAM(arguments);
+    UNUSED_PARAM(exception);
+
+    return JSValueMakeNumber(ctx, 3);
+}
+
+static JSValueRef functionGC(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    UNUSED_PARAM(function);
+    UNUSED_PARAM(thisObject);
+    UNUSED_PARAM(argumentCount);
+    UNUSED_PARAM(arguments);
+    UNUSED_PARAM(exception);
+    JSGarbageCollect(context);
+    return JSValueMakeUndefined(context);
+}
+
+static JSStaticValue globalObject_staticValues[] = {
+    { "globalStaticValue", globalObject_get, globalObject_set, kJSPropertyAttributeNone },
+    { 0, 0, 0, 0 }
+};
+
+static JSStaticFunction globalObject_staticFunctions[] = {
+    { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone },
+    { "gc", functionGC, kJSPropertyAttributeNone },
+    { 0, 0, 0 }
+};
+
+static char* createStringWithContentsOfFile(const char* fileName);
+
+static void testInitializeFinalize()
+{
+    JSObjectRef o = JSObjectMake(context, Derived_class(context), (void*)1);
+    UNUSED_PARAM(o);
+    ASSERT(JSObjectGetPrivate(o) == (void*)3);
+}
+
+static JSValueRef jsNumberValue =  NULL;
+
+static JSObjectRef aHeapRef = NULL;
+
+static void makeGlobalNumberValue(JSContextRef context) {
+    JSValueRef v = JSValueMakeNumber(context, 420);
+    JSValueProtect(context, v);
+    jsNumberValue = v;
+    v = NULL;
+}
+
+static bool assertTrue(bool value, const char* message)
+{
+    if (!value) {
+        if (message)
+            fprintf(stderr, "assertTrue failed: '%s'\n", message);
+        else
+            fprintf(stderr, "assertTrue failed.\n");
+        failed = 1;
+    }
+    return value;
+}
+
+static bool checkForCycleInPrototypeChain()
+{
+    bool result = true;
+    JSGlobalContextRef context = JSGlobalContextCreate(0);
+    JSObjectRef object1 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
+    JSObjectRef object2 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
+    JSObjectRef object3 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
+
+    JSObjectSetPrototype(context, object1, JSValueMakeNull(context));
+    ASSERT(JSValueIsNull(context, JSObjectGetPrototype(context, object1)));
+
+    // object1 -> object1
+    JSObjectSetPrototype(context, object1, object1);
+    result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to assign self as a prototype");
+
+    // object1 -> object2 -> object1
+    JSObjectSetPrototype(context, object2, object1);
+    ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object1));
+    JSObjectSetPrototype(context, object1, object2);
+    result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to close a prototype chain cycle");
+
+    // object1 -> object2 -> object3 -> object1
+    JSObjectSetPrototype(context, object2, object3);
+    ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object3));
+    JSObjectSetPrototype(context, object1, object2);
+    ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object1), object2));
+    JSObjectSetPrototype(context, object3, object1);
+    result &= assertTrue(!JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object3), object1), "It is possible to close a prototype chain cycle");
+
+    JSValueRef exception;
+    JSStringRef code = JSStringCreateWithUTF8CString("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o");
+    JSStringRef file = JSStringCreateWithUTF8CString("");
+    result &= assertTrue(!JSEvaluateScript(context, code, /* thisObject*/ 0, file, 1, &exception)
+                         , "An exception should be thrown");
+
+    JSStringRelease(code);
+    JSStringRelease(file);
+    JSGlobalContextRelease(context);
+    return result;
+}
+
+int main(int argc, char* argv[])
+{
+    const char *scriptPath = "testapi.js";
+    if (argc > 1) {
+        scriptPath = argv[1];
+    }
+    
+    // Test garbage collection with a fresh context
+    context = JSGlobalContextCreateInGroup(NULL, NULL);
+    TestInitializeFinalize = true;
+    testInitializeFinalize();
+    JSGlobalContextRelease(context);
+    TestInitializeFinalize = false;
+
+    ASSERT(Base_didFinalize);
+
+    JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty;
+    globalObjectClassDefinition.initialize = globalObject_initialize;
+    globalObjectClassDefinition.staticValues = globalObject_staticValues;
+    globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions;
+    globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
+    JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition);
+    context = JSGlobalContextCreateInGroup(NULL, globalObjectClass);
+
+    JSGlobalContextRetain(context);
+    JSGlobalContextRelease(context);
+    ASSERT(JSContextGetGlobalContext(context) == context);
+    
+    JSReportExtraMemoryCost(context, 0);
+    JSReportExtraMemoryCost(context, 1);
+    JSReportExtraMemoryCost(context, 1024);
+
+    JSObjectRef globalObject = JSContextGetGlobalObject(context);
+    ASSERT(JSValueIsObject(context, globalObject));
+    
+    JSValueRef jsUndefined = JSValueMakeUndefined(context);
+    JSValueRef jsNull = JSValueMakeNull(context);
+    JSValueRef jsTrue = JSValueMakeBoolean(context, true);
+    JSValueRef jsFalse = JSValueMakeBoolean(context, false);
+    JSValueRef jsZero = JSValueMakeNumber(context, 0);
+    JSValueRef jsOne = JSValueMakeNumber(context, 1);
+    JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0);
+    JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, NULL);
+    JSObjectSetPrototype(context, jsObjectNoProto, JSValueMakeNull(context));
+
+    // FIXME: test funny utf8 characters
+    JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString("");
+    JSValueRef jsEmptyString = JSValueMakeString(context, jsEmptyIString);
+    
+    JSStringRef jsOneIString = JSStringCreateWithUTF8CString("1");
+    JSValueRef jsOneString = JSValueMakeString(context, jsOneIString);
+
+    UniChar singleUniChar = 65; // Capital A
+    CFMutableStringRef cfString = 
+        CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault,
+                                                          &singleUniChar,
+                                                          1,
+                                                          1,
+                                                          kCFAllocatorNull);
+
+    JSStringRef jsCFIString = JSStringCreateWithCFString(cfString);
+    JSValueRef jsCFString = JSValueMakeString(context, jsCFIString);
+    
+    CFStringRef cfEmptyString = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8);
+    
+    JSStringRef jsCFEmptyIString = JSStringCreateWithCFString(cfEmptyString);
+    JSValueRef jsCFEmptyString = JSValueMakeString(context, jsCFEmptyIString);
+
+    CFIndex cfStringLength = CFStringGetLength(cfString);
+    UniChar* buffer = (UniChar*)malloc(cfStringLength * sizeof(UniChar));
+    CFStringGetCharacters(cfString, 
+                          CFRangeMake(0, cfStringLength), 
+                          buffer);
+    JSStringRef jsCFIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, cfStringLength);
+    JSValueRef jsCFStringWithCharacters = JSValueMakeString(context, jsCFIStringWithCharacters);
+    
+    JSStringRef jsCFEmptyIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, CFStringGetLength(cfEmptyString));
+    free(buffer);
+    JSValueRef jsCFEmptyStringWithCharacters = JSValueMakeString(context, jsCFEmptyIStringWithCharacters);
+
+    ASSERT(JSValueGetType(context, jsUndefined) == kJSTypeUndefined);
+    ASSERT(JSValueGetType(context, jsNull) == kJSTypeNull);
+    ASSERT(JSValueGetType(context, jsTrue) == kJSTypeBoolean);
+    ASSERT(JSValueGetType(context, jsFalse) == kJSTypeBoolean);
+    ASSERT(JSValueGetType(context, jsZero) == kJSTypeNumber);
+    ASSERT(JSValueGetType(context, jsOne) == kJSTypeNumber);
+    ASSERT(JSValueGetType(context, jsOneThird) == kJSTypeNumber);
+    ASSERT(JSValueGetType(context, jsEmptyString) == kJSTypeString);
+    ASSERT(JSValueGetType(context, jsOneString) == kJSTypeString);
+    ASSERT(JSValueGetType(context, jsCFString) == kJSTypeString);
+    ASSERT(JSValueGetType(context, jsCFStringWithCharacters) == kJSTypeString);
+    ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString);
+    ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);
+
+    JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
+    JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
+    JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
+    JSStringRelease(myObjectIString);
+    
+    JSObjectRef EvilExceptionObject = JSObjectMake(context, EvilExceptionObject_class(context), NULL);
+    JSStringRef EvilExceptionObjectIString = JSStringCreateWithUTF8CString("EvilExceptionObject");
+    JSObjectSetProperty(context, globalObject, EvilExceptionObjectIString, EvilExceptionObject, kJSPropertyAttributeNone, NULL);
+    JSStringRelease(EvilExceptionObjectIString);
+    
+    JSObjectRef EmptyObject = JSObjectMake(context, EmptyObject_class(context), NULL);
+    JSStringRef EmptyObjectIString = JSStringCreateWithUTF8CString("EmptyObject");
+    JSObjectSetProperty(context, globalObject, EmptyObjectIString, EmptyObject, kJSPropertyAttributeNone, NULL);
+    JSStringRelease(EmptyObjectIString);
+    
+    JSStringRef lengthStr = JSStringCreateWithUTF8CString("length");
+    JSObjectRef aStackRef = JSObjectMakeArray(context, 0, 0, 0);
+    aHeapRef = aStackRef;
+    JSObjectSetProperty(context, aHeapRef, lengthStr, JSValueMakeNumber(context, 10), 0, 0);
+    JSStringRef privatePropertyName = JSStringCreateWithUTF8CString("privateProperty");
+    if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, aHeapRef)) {
+        printf("FAIL: Could not set private property.\n");
+        failed = 1;
+    } else
+        printf("PASS: Set private property.\n");
+    aStackRef = 0;
+    if (JSObjectSetPrivateProperty(context, aHeapRef, privatePropertyName, aHeapRef)) {
+        printf("FAIL: JSObjectSetPrivateProperty should fail on non-API objects.\n");
+        failed = 1;
+    } else
+        printf("PASS: Did not allow JSObjectSetPrivateProperty on a non-API object.\n");
+    if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName) != aHeapRef) {
+        printf("FAIL: Could not retrieve private property.\n");
+        failed = 1;
+    } else
+        printf("PASS: Retrieved private property.\n");
+    if (JSObjectGetPrivateProperty(context, aHeapRef, privatePropertyName)) {
+        printf("FAIL: JSObjectGetPrivateProperty should return NULL when called on a non-API object.\n");
+        failed = 1;
+    } else
+        printf("PASS: JSObjectGetPrivateProperty return NULL.\n");
+
+    if (JSObjectGetProperty(context, myObject, privatePropertyName, 0) == aHeapRef) {
+        printf("FAIL: Accessed private property through ordinary property lookup.\n");
+        failed = 1;
+    } else
+        printf("PASS: Cannot access private property through ordinary property lookup.\n");
+
+    JSGarbageCollect(context);
+
+    for (int i = 0; i < 10000; i++)
+        JSObjectMake(context, 0, 0);
+
+    aHeapRef = JSValueToObject(context, JSObjectGetPrivateProperty(context, myObject, privatePropertyName), 0);
+    if (JSValueToNumber(context, JSObjectGetProperty(context, aHeapRef, lengthStr, 0), 0) != 10) {
+        printf("FAIL: Private property has been collected.\n");
+        failed = 1;
+    } else
+        printf("PASS: Private property does not appear to have been collected.\n");
+    JSStringRelease(lengthStr);
+
+    if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, 0)) {
+        printf("FAIL: Could not set private property to NULL.\n");
+        failed = 1;
+    } else
+        printf("PASS: Set private property to NULL.\n");
+    if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName)) {
+        printf("FAIL: Could not retrieve private property.\n");
+        failed = 1;
+    } else
+        printf("PASS: Retrieved private property.\n");
+
+    JSStringRef validJSON = JSStringCreateWithUTF8CString("{\"aProperty\":true}");
+    JSValueRef jsonObject = JSValueMakeFromJSONString(context, validJSON);
+    JSStringRelease(validJSON);
+    if (!JSValueIsObject(context, jsonObject)) {
+        printf("FAIL: Did not parse valid JSON correctly\n");
+        failed = 1;
+    } else
+        printf("PASS: Parsed valid JSON string.\n");
+    JSStringRef propertyName = JSStringCreateWithUTF8CString("aProperty");
+    assertEqualsAsBoolean(JSObjectGetProperty(context, JSValueToObject(context, jsonObject, 0), propertyName, 0), true);
+    JSStringRelease(propertyName);
+    JSStringRef invalidJSON = JSStringCreateWithUTF8CString("fail!");
+    if (JSValueMakeFromJSONString(context, invalidJSON)) {
+        printf("FAIL: Should return null for invalid JSON data\n");
+        failed = 1;
+    } else
+        printf("PASS: Correctly returned null for invalid JSON data.\n");
+    JSValueRef exception;
+    JSStringRef str = JSValueCreateJSONString(context, jsonObject, 0, 0);
+    if (!JSStringIsEqualToUTF8CString(str, "{\"aProperty\":true}")) {
+        printf("FAIL: Did not correctly serialise with indent of 0.\n");
+        failed = 1;
+    } else
+        printf("PASS: Correctly serialised with indent of 0.\n");
+    JSStringRelease(str);
+
+    str = JSValueCreateJSONString(context, jsonObject, 4, 0);
+    if (!JSStringIsEqualToUTF8CString(str, "{\n    \"aProperty\": true\n}")) {
+        printf("FAIL: Did not correctly serialise with indent of 4.\n");
+        failed = 1;
+    } else
+        printf("PASS: Correctly serialised with indent of 4.\n");
+    JSStringRelease(str);
+    JSStringRef src = JSStringCreateWithUTF8CString("({get a(){ throw '';}})");
+    JSValueRef unstringifiableObj = JSEvaluateScript(context, src, NULL, NULL, 1, NULL);
+    
+    str = JSValueCreateJSONString(context, unstringifiableObj, 4, 0);
+    if (str) {
+        printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
+        JSStringRelease(str);
+        failed = 1;
+    } else
+        printf("PASS: returned null when attempting to serialize unserializable value.\n");
+    
+    str = JSValueCreateJSONString(context, unstringifiableObj, 4, &exception);
+    if (str) {
+        printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
+        JSStringRelease(str);
+        failed = 1;
+    } else
+        printf("PASS: returned null when attempting to serialize unserializable value.\n");
+    if (!exception) {
+        printf("FAIL: Did not set exception on serialisation error\n");
+        failed = 1;
+    } else
+        printf("PASS: set exception on serialisation error\n");
+    // Conversions that throw exceptions
+    exception = NULL;
+    ASSERT(NULL == JSValueToObject(context, jsNull, &exception));
+    ASSERT(exception);
+    
+    exception = NULL;
+    // FIXME  - On i386 the isnan(double) macro tries to map to the isnan(float) function,
+    // causing a build break with -Wshorten-64-to-32 enabled.  The issue is known by the appropriate team.
+    // After that's resolved, we can remove these casts
+    ASSERT(isnan((float)JSValueToNumber(context, jsObjectNoProto, &exception)));
+    ASSERT(exception);
+
+    exception = NULL;
+    ASSERT(!JSValueToStringCopy(context, jsObjectNoProto, &exception));
+    ASSERT(exception);
+    
+    ASSERT(JSValueToBoolean(context, myObject));
+    
+    exception = NULL;
+    ASSERT(!JSValueIsEqual(context, jsObjectNoProto, JSValueMakeNumber(context, 1), &exception));
+    ASSERT(exception);
+    
+    exception = NULL;
+    JSObjectGetPropertyAtIndex(context, myObject, 0, &exception);
+    ASSERT(1 == JSValueToNumber(context, exception, NULL));
+
+    assertEqualsAsBoolean(jsUndefined, false);
+    assertEqualsAsBoolean(jsNull, false);
+    assertEqualsAsBoolean(jsTrue, true);
+    assertEqualsAsBoolean(jsFalse, false);
+    assertEqualsAsBoolean(jsZero, false);
+    assertEqualsAsBoolean(jsOne, true);
+    assertEqualsAsBoolean(jsOneThird, true);
+    assertEqualsAsBoolean(jsEmptyString, false);
+    assertEqualsAsBoolean(jsOneString, true);
+    assertEqualsAsBoolean(jsCFString, true);
+    assertEqualsAsBoolean(jsCFStringWithCharacters, true);
+    assertEqualsAsBoolean(jsCFEmptyString, false);
+    assertEqualsAsBoolean(jsCFEmptyStringWithCharacters, false);
+    
+    assertEqualsAsNumber(jsUndefined, nan(""));
+    assertEqualsAsNumber(jsNull, 0);
+    assertEqualsAsNumber(jsTrue, 1);
+    assertEqualsAsNumber(jsFalse, 0);
+    assertEqualsAsNumber(jsZero, 0);
+    assertEqualsAsNumber(jsOne, 1);
+    assertEqualsAsNumber(jsOneThird, 1.0 / 3.0);
+    assertEqualsAsNumber(jsEmptyString, 0);
+    assertEqualsAsNumber(jsOneString, 1);
+    assertEqualsAsNumber(jsCFString, nan(""));
+    assertEqualsAsNumber(jsCFStringWithCharacters, nan(""));
+    assertEqualsAsNumber(jsCFEmptyString, 0);
+    assertEqualsAsNumber(jsCFEmptyStringWithCharacters, 0);
+    ASSERT(sizeof(JSChar) == sizeof(UniChar));
+    
+    assertEqualsAsCharactersPtr(jsUndefined, "undefined");
+    assertEqualsAsCharactersPtr(jsNull, "null");
+    assertEqualsAsCharactersPtr(jsTrue, "true");
+    assertEqualsAsCharactersPtr(jsFalse, "false");
+    assertEqualsAsCharactersPtr(jsZero, "0");
+    assertEqualsAsCharactersPtr(jsOne, "1");
+    assertEqualsAsCharactersPtr(jsOneThird, "0.3333333333333333");
+    assertEqualsAsCharactersPtr(jsEmptyString, "");
+    assertEqualsAsCharactersPtr(jsOneString, "1");
+    assertEqualsAsCharactersPtr(jsCFString, "A");
+    assertEqualsAsCharactersPtr(jsCFStringWithCharacters, "A");
+    assertEqualsAsCharactersPtr(jsCFEmptyString, "");
+    assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters, "");
+    
+    assertEqualsAsUTF8String(jsUndefined, "undefined");
+    assertEqualsAsUTF8String(jsNull, "null");
+    assertEqualsAsUTF8String(jsTrue, "true");
+    assertEqualsAsUTF8String(jsFalse, "false");
+    assertEqualsAsUTF8String(jsZero, "0");
+    assertEqualsAsUTF8String(jsOne, "1");
+    assertEqualsAsUTF8String(jsOneThird, "0.3333333333333333");
+    assertEqualsAsUTF8String(jsEmptyString, "");
+    assertEqualsAsUTF8String(jsOneString, "1");
+    assertEqualsAsUTF8String(jsCFString, "A");
+    assertEqualsAsUTF8String(jsCFStringWithCharacters, "A");
+    assertEqualsAsUTF8String(jsCFEmptyString, "");
+    assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters, "");
+    
+    ASSERT(JSValueIsStrictEqual(context, jsTrue, jsTrue));
+    ASSERT(!JSValueIsStrictEqual(context, jsOne, jsOneString));
+
+    ASSERT(JSValueIsEqual(context, jsOne, jsOneString, NULL));
+    ASSERT(!JSValueIsEqual(context, jsTrue, jsFalse, NULL));
+    
+    CFStringRef cfJSString = JSStringCopyCFString(kCFAllocatorDefault, jsCFIString);
+    CFStringRef cfJSEmptyString = JSStringCopyCFString(kCFAllocatorDefault, jsCFEmptyIString);
+    ASSERT(CFEqual(cfJSString, cfString));
+    ASSERT(CFEqual(cfJSEmptyString, cfEmptyString));
+    CFRelease(cfJSString);
+    CFRelease(cfJSEmptyString);
+
+    CFRelease(cfString);
+    CFRelease(cfEmptyString);
+    
+    jsGlobalValue = JSObjectMake(context, NULL, NULL);
+    makeGlobalNumberValue(context);
+    JSValueProtect(context, jsGlobalValue);
+    JSGarbageCollect(context);
+    ASSERT(JSValueIsObject(context, jsGlobalValue));
+    JSValueUnprotect(context, jsGlobalValue);
+    JSValueUnprotect(context, jsNumberValue);
+
+    JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;");
+    JSStringRef badSyntax = JSStringCreateWithUTF8CString("x := 1;");
+    ASSERT(JSCheckScriptSyntax(context, goodSyntax, NULL, 0, NULL));
+    ASSERT(!JSCheckScriptSyntax(context, badSyntax, NULL, 0, NULL));
+
+    JSValueRef result;
+    JSValueRef v;
+    JSObjectRef o;
+    JSStringRef string;
+
+    result = JSEvaluateScript(context, goodSyntax, NULL, NULL, 1, NULL);
+    ASSERT(result);
+    ASSERT(JSValueIsEqual(context, result, jsOne, NULL));
+
+    exception = NULL;
+    result = JSEvaluateScript(context, badSyntax, NULL, NULL, 1, &exception);
+    ASSERT(!result);
+    ASSERT(JSValueIsObject(context, exception));
+    
+    JSStringRef array = JSStringCreateWithUTF8CString("Array");
+    JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
+    JSStringRelease(array);
+    result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL);
+    ASSERT(result);
+    ASSERT(JSValueIsObject(context, result));
+    ASSERT(JSValueIsInstanceOfConstructor(context, result, arrayConstructor, NULL));
+    ASSERT(!JSValueIsInstanceOfConstructor(context, JSValueMakeNull(context), arrayConstructor, NULL));
+
+    o = JSValueToObject(context, result, NULL);
+    exception = NULL;
+    ASSERT(JSValueIsUndefined(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception)));
+    ASSERT(!exception);
+    
+    JSObjectSetPropertyAtIndex(context, o, 0, JSValueMakeNumber(context, 1), &exception);
+    ASSERT(!exception);
+    
+    exception = NULL;
+    ASSERT(1 == JSValueToNumber(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception), &exception));
+    ASSERT(!exception);
+
+    JSStringRef functionBody;
+    JSObjectRef function;
+    
+    exception = NULL;
+    functionBody = JSStringCreateWithUTF8CString("rreturn Array;");
+    JSStringRef line = JSStringCreateWithUTF8CString("line");
+    ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception));
+    ASSERT(JSValueIsObject(context, exception));
+    v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL);
+    assertEqualsAsNumber(v, 1);
+    JSStringRelease(functionBody);
+    JSStringRelease(line);
+
+    exception = NULL;
+    functionBody = JSStringCreateWithUTF8CString("return Array;");
+    function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception);
+    JSStringRelease(functionBody);
+    ASSERT(!exception);
+    ASSERT(JSObjectIsFunction(context, function));
+    v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
+    ASSERT(v);
+    ASSERT(JSValueIsEqual(context, v, arrayConstructor, NULL));
+    
+    exception = NULL;
+    function = JSObjectMakeFunction(context, NULL, 0, NULL, jsEmptyIString, NULL, 0, &exception);
+    ASSERT(!exception);
+    v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, &exception);
+    ASSERT(v && !exception);
+    ASSERT(JSValueIsUndefined(context, v));
+    
+    exception = NULL;
+    v = NULL;
+    JSStringRef foo = JSStringCreateWithUTF8CString("foo");
+    JSStringRef argumentNames[] = { foo };
+    functionBody = JSStringCreateWithUTF8CString("return foo;");
+    function = JSObjectMakeFunction(context, foo, 1, argumentNames, functionBody, NULL, 1, &exception);
+    ASSERT(function && !exception);
+    JSValueRef arguments[] = { JSValueMakeNumber(context, 2) };
+    v = JSObjectCallAsFunction(context, function, NULL, 1, arguments, &exception);
+    JSStringRelease(foo);
+    JSStringRelease(functionBody);
+    
+    string = JSValueToStringCopy(context, function, NULL);
+    assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) { return foo;\n}");
+    JSStringRelease(string);
+
+    JSStringRef print = JSStringCreateWithUTF8CString("print");
+    JSObjectRef printFunction = JSObjectMakeFunctionWithCallback(context, print, print_callAsFunction);
+    JSObjectSetProperty(context, globalObject, print, printFunction, kJSPropertyAttributeNone, NULL); 
+    JSStringRelease(print);
+    
+    ASSERT(!JSObjectSetPrivate(printFunction, (void*)1));
+    ASSERT(!JSObjectGetPrivate(printFunction));
+
+    JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor");
+    JSObjectRef myConstructor = JSObjectMakeConstructor(context, NULL, myConstructor_callAsConstructor);
+    JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL);
+    JSStringRelease(myConstructorIString);
+    
+    ASSERT(!JSObjectSetPrivate(myConstructor, (void*)1));
+    ASSERT(!JSObjectGetPrivate(myConstructor));
+    
+    string = JSStringCreateWithUTF8CString("Base");
+    JSObjectRef baseConstructor = JSObjectMakeConstructor(context, Base_class(context), NULL);
+    JSObjectSetProperty(context, globalObject, string, baseConstructor, kJSPropertyAttributeNone, NULL);
+    JSStringRelease(string);
+    
+    string = JSStringCreateWithUTF8CString("Derived");
+    JSObjectRef derivedConstructor = JSObjectMakeConstructor(context, Derived_class(context), NULL);
+    JSObjectSetProperty(context, globalObject, string, derivedConstructor, kJSPropertyAttributeNone, NULL);
+    JSStringRelease(string);
+    
+    string = JSStringCreateWithUTF8CString("Derived2");
+    JSObjectRef derived2Constructor = JSObjectMakeConstructor(context, Derived2_class(context), NULL);
+    JSObjectSetProperty(context, globalObject, string, derived2Constructor, kJSPropertyAttributeNone, NULL);
+    JSStringRelease(string);
+
+    o = JSObjectMake(context, NULL, NULL);
+    JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL);
+    JSObjectSetProperty(context, o, jsCFIString,  JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL);
+    JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o);
+    size_t expectedCount = JSPropertyNameArrayGetCount(nameArray);
+    size_t count;
+    for (count = 0; count < expectedCount; ++count)
+        JSPropertyNameArrayGetNameAtIndex(nameArray, count);
+    JSPropertyNameArrayRelease(nameArray);
+    ASSERT(count == 1); // jsCFString should not be enumerated
+
+    JSValueRef argumentsArrayValues[] = { JSValueMakeNumber(context, 10), JSValueMakeNumber(context, 20) };
+    o = JSObjectMakeArray(context, sizeof(argumentsArrayValues) / sizeof(JSValueRef), argumentsArrayValues, NULL);
+    string = JSStringCreateWithUTF8CString("length");
+    v = JSObjectGetProperty(context, o, string, NULL);
+    assertEqualsAsNumber(v, 2);
+    v = JSObjectGetPropertyAtIndex(context, o, 0, NULL);
+    assertEqualsAsNumber(v, 10);
+    v = JSObjectGetPropertyAtIndex(context, o, 1, NULL);
+    assertEqualsAsNumber(v, 20);
+
+    o = JSObjectMakeArray(context, 0, NULL, NULL);
+    v = JSObjectGetProperty(context, o, string, NULL);
+    assertEqualsAsNumber(v, 0);
+    JSStringRelease(string);
+
+    JSValueRef argumentsDateValues[] = { JSValueMakeNumber(context, 0) };
+    o = JSObjectMakeDate(context, 1, argumentsDateValues, NULL);
+    if (timeZoneIsPST())
+        assertEqualsAsUTF8String(o, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)");
+
+    string = JSStringCreateWithUTF8CString("an error message");
+    JSValueRef argumentsErrorValues[] = { JSValueMakeString(context, string) };
+    o = JSObjectMakeError(context, 1, argumentsErrorValues, NULL);
+    assertEqualsAsUTF8String(o, "Error: an error message");
+    JSStringRelease(string);
+
+    string = JSStringCreateWithUTF8CString("foo");
+    JSStringRef string2 = JSStringCreateWithUTF8CString("gi");
+    JSValueRef argumentsRegExpValues[] = { JSValueMakeString(context, string), JSValueMakeString(context, string2) };
+    o = JSObjectMakeRegExp(context, 2, argumentsRegExpValues, NULL);
+    assertEqualsAsUTF8String(o, "/foo/gi");
+    JSStringRelease(string);
+    JSStringRelease(string2);
+
+    JSClassDefinition nullDefinition = kJSClassDefinitionEmpty;
+    nullDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
+    JSClassRef nullClass = JSClassCreate(&nullDefinition);
+    JSClassRelease(nullClass);
+    
+    nullDefinition = kJSClassDefinitionEmpty;
+    nullClass = JSClassCreate(&nullDefinition);
+    JSClassRelease(nullClass);
+
+    functionBody = JSStringCreateWithUTF8CString("return this;");
+    function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
+    JSStringRelease(functionBody);
+    v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
+    ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
+    v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
+    ASSERT(JSValueIsEqual(context, v, o, NULL));
+
+    functionBody = JSStringCreateWithUTF8CString("return eval(\"this\");");
+    function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
+    JSStringRelease(functionBody);
+    v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
+    ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
+    v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
+    ASSERT(JSValueIsEqual(context, v, o, NULL));
+
+    JSStringRef script = JSStringCreateWithUTF8CString("this;");
+    v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
+    ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
+    v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
+    ASSERT(JSValueIsEqual(context, v, o, NULL));
+    JSStringRelease(script);
+
+    script = JSStringCreateWithUTF8CString("eval(this);");
+    v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
+    ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
+    v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
+    ASSERT(JSValueIsEqual(context, v, o, NULL));
+    JSStringRelease(script);
+
+    // Verify that creating a constructor for a class with no static functions does not trigger
+    // an assert inside putDirect or lead to a crash during GC. 
+    nullDefinition = kJSClassDefinitionEmpty;
+    nullClass = JSClassCreate(&nullDefinition);
+    myConstructor = JSObjectMakeConstructor(context, nullClass, 0);
+    JSClassRelease(nullClass);
+
+    char* scriptUTF8 = createStringWithContentsOfFile(scriptPath);
+    if (!scriptUTF8) {
+        printf("FAIL: Test script could not be loaded.\n");
+        failed = 1;
+    } else {
+        script = JSStringCreateWithUTF8CString(scriptUTF8);
+        result = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
+        if (result && JSValueIsUndefined(context, result))
+            printf("PASS: Test script executed successfully.\n");
+        else {
+            printf("FAIL: Test script returned unexpected value:\n");
+            JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL);
+            CFStringRef exceptionCF = JSStringCopyCFString(kCFAllocatorDefault, exceptionIString);
+            CFShow(exceptionCF);
+            CFRelease(exceptionCF);
+            JSStringRelease(exceptionIString);
+            failed = 1;
+        }
+        JSStringRelease(script);
+        free(scriptUTF8);
+    }
+
+    // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
+    function = NULL;
+    v = NULL;
+    o = NULL;
+    globalObject = NULL;
+    myConstructor = NULL;
+
+    JSStringRelease(jsEmptyIString);
+    JSStringRelease(jsOneIString);
+    JSStringRelease(jsCFIString);
+    JSStringRelease(jsCFEmptyIString);
+    JSStringRelease(jsCFIStringWithCharacters);
+    JSStringRelease(jsCFEmptyIStringWithCharacters);
+    JSStringRelease(goodSyntax);
+    JSStringRelease(badSyntax);
+
+    JSGlobalContextRelease(context);
+    JSClassRelease(globalObjectClass);
+
+    // Test for an infinite prototype chain that used to be created. This test
+    // passes if the call to JSObjectHasProperty() does not hang.
+
+    JSClassDefinition prototypeLoopClassDefinition = kJSClassDefinitionEmpty;
+    prototypeLoopClassDefinition.staticFunctions = globalObject_staticFunctions;
+    JSClassRef prototypeLoopClass = JSClassCreate(&prototypeLoopClassDefinition);
+    JSGlobalContextRef prototypeLoopContext = JSGlobalContextCreateInGroup(NULL, prototypeLoopClass);
+
+    JSStringRef nameProperty = JSStringCreateWithUTF8CString("name");
+    JSObjectHasProperty(prototypeLoopContext, JSContextGetGlobalObject(prototypeLoopContext), nameProperty);
+
+    JSGlobalContextRelease(prototypeLoopContext);
+    JSClassRelease(prototypeLoopClass);
+
+    printf("PASS: Infinite prototype chain does not occur.\n");
+
+    if (checkForCycleInPrototypeChain())
+        printf("PASS: A cycle in a prototype chain can't be created.\n");
+    else {
+        printf("FAIL: A cycle in a prototype chain can be created.\n");
+        failed = true;
+    }
+
+    if (failed) {
+        printf("FAIL: Some tests failed.\n");
+        return 1;
+    }
+
+    printf("PASS: Program exited normally.\n");
+    return 0;
+}
+
+static char* createStringWithContentsOfFile(const char* fileName)
+{
+    char* buffer;
+    
+    size_t buffer_size = 0;
+    size_t buffer_capacity = 1024;
+    buffer = (char*)malloc(buffer_capacity);
+    
+    FILE* f = fopen(fileName, "r");
+    if (!f) {
+        fprintf(stderr, "Could not open file: %s\n", fileName);
+        return 0;
+    }
+    
+    while (!feof(f) && !ferror(f)) {
+        buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f);
+        if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0'
+            buffer_capacity *= 2;
+            buffer = (char*)realloc(buffer, buffer_capacity);
+            ASSERT(buffer);
+        }
+        
+        ASSERT(buffer_size < buffer_capacity);
+    }
+    fclose(f);
+    buffer[buffer_size] = '\0';
+    
+    return buffer;
+}
diff --git a/Source/JavaScriptCore/API/tests/testapi.js b/Source/JavaScriptCore/API/tests/testapi.js
new file mode 100644
index 0000000..15c9e50
--- /dev/null
+++ b/Source/JavaScriptCore/API/tests/testapi.js
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+function bludgeonArguments() { if (0) arguments; return function g() {} }
+h = bludgeonArguments();
+gc();
+
+var failed = false;
+function pass(msg)
+{
+    print("PASS: " + msg, "green");
+}
+
+function fail(msg)
+{
+    print("FAIL: " + msg, "red");
+    failed = true;
+}
+
+function shouldBe(a, b)
+{
+    var evalA;
+    try {
+        evalA = eval(a);
+    } catch(e) {
+        evalA = e;
+    }
+    
+    if (evalA == b || isNaN(evalA) && typeof evalA == 'number' && isNaN(b) && typeof b == 'number')
+        pass(a + " should be " + b + " and is.");
+    else
+        fail(a + " should be " + b + " but instead is " + evalA + ".");
+}
+
+function shouldThrow(a)
+{
+    var evalA;
+    try {
+        eval(a);
+    } catch(e) {
+        pass(a + " threw: " + e);
+        return;
+    }
+
+    fail(a + " did not throw an exception.");
+}
+
+function globalStaticFunction()
+{
+    return 4;
+}
+
+shouldBe("globalStaticValue", 3);
+shouldBe("globalStaticFunction()", 4);
+
+shouldBe("typeof MyObject", "function"); // our object implements 'call'
+MyObject.cantFind = 1;
+shouldBe("MyObject.cantFind", undefined);
+MyObject.regularType = 1;
+shouldBe("MyObject.regularType", 1);
+MyObject.alwaysOne = 2;
+shouldBe("MyObject.alwaysOne", 1);
+MyObject.cantDelete = 1;
+delete MyObject.cantDelete;
+shouldBe("MyObject.cantDelete", 1);
+shouldBe("delete MyObject.throwOnDelete", "an exception");
+MyObject.cantSet = 1;
+shouldBe("MyObject.cantSet", undefined);
+shouldBe("MyObject.throwOnGet", "an exception");
+shouldBe("MyObject.throwOnSet = 5", "an exception");
+shouldBe("MyObject('throwOnCall')", "an exception");
+shouldBe("new MyObject('throwOnConstruct')", "an exception");
+shouldBe("'throwOnHasInstance' instanceof MyObject", "an exception");
+
+var foundMyPropertyName = false;
+var foundRegularType = false;
+for (var p in MyObject) {
+    if (p == "myPropertyName")
+        foundMyPropertyName = true;
+    if (p == "regularType")
+        foundRegularType = true;
+}
+
+if (foundMyPropertyName)
+    pass("MyObject.myPropertyName was enumerated");
+else
+    fail("MyObject.myPropertyName was not enumerated");
+
+if (foundRegularType)
+    pass("MyObject.regularType was enumerated");
+else
+    fail("MyObject.regularType was not enumerated");
+
+var alwaysOneDescriptor = Object.getOwnPropertyDescriptor(MyObject, "alwaysOne");
+shouldBe('typeof alwaysOneDescriptor', "object");
+shouldBe('alwaysOneDescriptor.value', MyObject.alwaysOne);
+shouldBe('alwaysOneDescriptor.configurable', true);
+shouldBe('alwaysOneDescriptor.enumerable', false); // Actually it is.
+var cantFindDescriptor = Object.getOwnPropertyDescriptor(MyObject, "cantFind");
+shouldBe('typeof cantFindDescriptor', "object");
+shouldBe('cantFindDescriptor.value', MyObject.cantFind);
+shouldBe('cantFindDescriptor.configurable', true);
+shouldBe('cantFindDescriptor.enumerable', false);
+try {
+    // If getOwnPropertyDescriptor() returned an access descriptor, this wouldn't throw.
+    Object.getOwnPropertyDescriptor(MyObject, "throwOnGet");
+} catch (e) {
+    pass("getting property descriptor of throwOnGet threw exception");
+}
+var myPropertyNameDescriptor = Object.getOwnPropertyDescriptor(MyObject, "myPropertyName");
+shouldBe('typeof myPropertyNameDescriptor', "object");
+shouldBe('myPropertyNameDescriptor.value', MyObject.myPropertyName);
+shouldBe('myPropertyNameDescriptor.configurable', true);
+shouldBe('myPropertyNameDescriptor.enumerable', false); // Actually it is.
+try {
+    // if getOwnPropertyDescriptor() returned an access descriptor, this wouldn't throw.
+    Object.getOwnPropertyDescriptor(MyObject, "hasPropertyLie");
+} catch (e) {
+    pass("getting property descriptor of hasPropertyLie threw exception");
+}
+shouldBe('Object.getOwnPropertyDescriptor(MyObject, "doesNotExist")', undefined);
+
+myObject = new MyObject();
+
+shouldBe("delete MyObject.regularType", true);
+shouldBe("MyObject.regularType", undefined);
+shouldBe("MyObject(0)", 1);
+shouldBe("MyObject()", undefined);
+shouldBe("typeof myObject", "object");
+shouldBe("MyObject ? 1 : 0", true); // toBoolean
+shouldBe("+MyObject", 1); // toNumber
+shouldBe("(MyObject.toString())", "[object MyObject]"); // toString
+shouldBe("String(MyObject)", "MyObjectAsString"); // type conversion to string
+shouldBe("MyObject - 0", 1); // toNumber
+
+shouldBe("typeof MyConstructor", "object");
+constructedObject = new MyConstructor(1);
+shouldBe("typeof constructedObject", "object");
+shouldBe("constructedObject.value", 1);
+shouldBe("myObject instanceof MyObject", true);
+shouldBe("(new Object()) instanceof MyObject", false);
+
+shouldThrow("MyObject.nullGetSet = 1");
+shouldThrow("MyObject.nullGetSet");
+shouldThrow("MyObject.nullCall()");
+shouldThrow("MyObject.hasPropertyLie");
+
+derived = new Derived();
+
+shouldBe("derived instanceof Derived", true);
+shouldBe("derived instanceof Base", true);
+
+// base properties and functions return 1 when called/gotten; derived, 2
+shouldBe("derived.baseProtoDup()", 2);
+shouldBe("derived.baseProto()", 1);
+shouldBe("derived.baseDup", 2);
+shouldBe("derived.baseOnly", 1);
+shouldBe("derived.protoOnly()", 2);
+shouldBe("derived.protoDup", 2);
+shouldBe("derived.derivedOnly", 2)
+
+// base properties throw 1 when set; derived, 2
+shouldBe("derived.baseDup = 0", 2);
+shouldBe("derived.baseOnly = 0", 1);
+shouldBe("derived.derivedOnly = 0", 2)
+shouldBe("derived.protoDup = 0", 2);
+
+derived2 = new Derived2();
+
+shouldBe("derived2 instanceof Derived2", true);
+shouldBe("derived2 instanceof Derived", true);
+shouldBe("derived2 instanceof Base", true);
+
+// base properties and functions return 1 when called/gotten; derived, 2
+shouldBe("derived2.baseProtoDup()", 2);
+shouldBe("derived2.baseProto()", 1);
+shouldBe("derived2.baseDup", 2);
+shouldBe("derived2.baseOnly", 1);
+shouldBe("derived2.protoOnly()", 2);
+shouldBe("derived2.protoDup", 2);
+shouldBe("derived2.derivedOnly", 2)
+
+// base properties throw 1 when set; derived, 2
+shouldBe("derived2.baseDup = 0", 2);
+shouldBe("derived2.baseOnly = 0", 1);
+shouldBe("derived2.derivedOnly = 0", 2)
+shouldBe("derived2.protoDup = 0", 2);
+
+shouldBe('Object.getOwnPropertyDescriptor(derived, "baseProto")', undefined);
+shouldBe('Object.getOwnPropertyDescriptor(derived, "baseProtoDup")', undefined);
+var baseDupDescriptor = Object.getOwnPropertyDescriptor(derived, "baseDup");
+shouldBe('typeof baseDupDescriptor', "object");
+shouldBe('baseDupDescriptor.value', derived.baseDup);
+shouldBe('baseDupDescriptor.configurable', true);
+shouldBe('baseDupDescriptor.enumerable', false);
+var baseOnlyDescriptor = Object.getOwnPropertyDescriptor(derived, "baseOnly");
+shouldBe('typeof baseOnlyDescriptor', "object");
+shouldBe('baseOnlyDescriptor.value', derived.baseOnly);
+shouldBe('baseOnlyDescriptor.configurable', true);
+shouldBe('baseOnlyDescriptor.enumerable', false);
+shouldBe('Object.getOwnPropertyDescriptor(derived, "protoOnly")', undefined);
+var protoDupDescriptor = Object.getOwnPropertyDescriptor(derived, "protoDup");
+shouldBe('typeof protoDupDescriptor', "object");
+shouldBe('protoDupDescriptor.value', derived.protoDup);
+shouldBe('protoDupDescriptor.configurable', true);
+shouldBe('protoDupDescriptor.enumerable', false);
+var derivedOnlyDescriptor = Object.getOwnPropertyDescriptor(derived, "derivedOnly");
+shouldBe('typeof derivedOnlyDescriptor', "object");
+shouldBe('derivedOnlyDescriptor.value', derived.derivedOnly);
+shouldBe('derivedOnlyDescriptor.configurable', true);
+shouldBe('derivedOnlyDescriptor.enumerable', false);
+
+shouldBe("undefined instanceof MyObject", false);
+EvilExceptionObject.hasInstance = function f() { return f(); };
+EvilExceptionObject.__proto__ = undefined;
+shouldThrow("undefined instanceof EvilExceptionObject");
+EvilExceptionObject.hasInstance = function () { return true; };
+shouldBe("undefined instanceof EvilExceptionObject", true);
+
+EvilExceptionObject.toNumber = function f() { return f(); }
+shouldThrow("EvilExceptionObject*5");
+EvilExceptionObject.toStringExplicit = function f() { return f(); }
+shouldThrow("String(EvilExceptionObject)");
+
+shouldBe("EmptyObject", "[object CallbackObject]");
+
+if (failed)
+    throw "Some tests failed";
+
-- 
cgit v1.1