2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "JavaScriptCore.h"
27 #include "JSBasePrivate.h"
28 #include "JSContextRefPrivate.h"
29 #include "JSObjectRefPrivate.h"
31 #define ASSERT_DISABLED 0
32 #include <wtf/Assertions.h>
33 #include <wtf/UnusedParam.h>
41 #include <wtf/MathExtras.h>
43 static double nan(const char*)
45 return std::numeric_limits<double>::quiet_NaN();
50 static JSGlobalContextRef context;
52 static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue)
54 if (JSValueToBoolean(context, value) != expectedValue) {
55 fprintf(stderr, "assertEqualsAsBoolean failed: %p, %d\n", value, expectedValue);
60 static void assertEqualsAsNumber(JSValueRef value, double expectedValue)
62 double number = JSValueToNumber(context, value, NULL);
64 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
65 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
66 // After that's resolved, we can remove these casts
67 if (number != expectedValue && !(isnan((float)number) && isnan((float)expectedValue))) {
68 fprintf(stderr, "assertEqualsAsNumber failed: %p, %lf\n", value, expectedValue);
73 static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue)
75 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
77 size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString);
78 char* jsBuffer = (char*)malloc(jsSize);
79 JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize);
82 for (i = 0; jsBuffer[i]; i++) {
83 if (jsBuffer[i] != expectedValue[i]) {
84 fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]);
89 if (jsSize < strlen(jsBuffer) + 1) {
90 fprintf(stderr, "assertEqualsAsUTF8String failed: jsSize was too small\n");
95 JSStringRelease(valueAsString);
98 static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedValue)
100 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
102 size_t jsLength = JSStringGetLength(valueAsString);
103 const JSChar* jsBuffer = JSStringGetCharactersPtr(valueAsString);
105 CFStringRef expectedValueAsCFString = CFStringCreateWithCString(kCFAllocatorDefault,
107 kCFStringEncodingUTF8);
108 CFIndex cfLength = CFStringGetLength(expectedValueAsCFString);
109 UniChar* cfBuffer = (UniChar*)malloc(cfLength * sizeof(UniChar));
110 CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer);
111 CFRelease(expectedValueAsCFString);
113 if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0) {
114 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n");
118 if (jsLength != (size_t)cfLength) {
119 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength);
124 JSStringRelease(valueAsString);
127 static bool timeZoneIsPST()
129 char timeZoneName[70];
131 memset(>m, 0, sizeof(gtm));
132 strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m);
134 return 0 == strcmp("PST", timeZoneName);
137 static JSValueRef jsGlobalValue; // non-stack value for testing JSValueProtect()
139 /* MyObject pseudo-class */
141 static bool MyObject_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName)
143 UNUSED_PARAM(context);
144 UNUSED_PARAM(object);
146 if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")
147 || JSStringIsEqualToUTF8CString(propertyName, "cantFind")
148 || JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")
149 || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")
150 || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")
151 || JSStringIsEqualToUTF8CString(propertyName, "0")) {
158 static JSValueRef MyObject_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
160 UNUSED_PARAM(context);
161 UNUSED_PARAM(object);
163 if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")) {
164 return JSValueMakeNumber(context, 1);
167 if (JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")) {
168 return JSValueMakeNumber(context, 1);
171 if (JSStringIsEqualToUTF8CString(propertyName, "cantFind")) {
172 return JSValueMakeUndefined(context);
175 if (JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")) {
179 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")) {
180 return JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
183 if (JSStringIsEqualToUTF8CString(propertyName, "0")) {
184 *exception = JSValueMakeNumber(context, 1);
185 return JSValueMakeNumber(context, 1);
188 return JSValueMakeNull(context);
191 static bool MyObject_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
193 UNUSED_PARAM(context);
194 UNUSED_PARAM(object);
196 UNUSED_PARAM(exception);
198 if (JSStringIsEqualToUTF8CString(propertyName, "cantSet"))
199 return true; // pretend we set the property in order to swallow it
201 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnSet")) {
202 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
208 static bool MyObject_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
210 UNUSED_PARAM(context);
211 UNUSED_PARAM(object);
213 if (JSStringIsEqualToUTF8CString(propertyName, "cantDelete"))
216 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnDelete")) {
217 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
224 static void MyObject_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
226 UNUSED_PARAM(context);
227 UNUSED_PARAM(object);
229 JSStringRef propertyName;
231 propertyName = JSStringCreateWithUTF8CString("alwaysOne");
232 JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
233 JSStringRelease(propertyName);
235 propertyName = JSStringCreateWithUTF8CString("myPropertyName");
236 JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
237 JSStringRelease(propertyName);
240 static JSValueRef MyObject_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
242 UNUSED_PARAM(context);
243 UNUSED_PARAM(object);
244 UNUSED_PARAM(thisObject);
245 UNUSED_PARAM(exception);
247 if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnCall")) {
248 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
249 return JSValueMakeUndefined(context);
252 if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
253 return JSValueMakeNumber(context, 1);
255 return JSValueMakeUndefined(context);
258 static JSObjectRef MyObject_callAsConstructor(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
260 UNUSED_PARAM(context);
261 UNUSED_PARAM(object);
263 if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnConstruct")) {
264 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
268 if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
269 return JSValueToObject(context, JSValueMakeNumber(context, 1), exception);
271 return JSValueToObject(context, JSValueMakeNumber(context, 0), exception);
274 static bool MyObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
276 UNUSED_PARAM(context);
277 UNUSED_PARAM(constructor);
279 if (JSValueIsString(context, possibleValue) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, possibleValue, 0), "throwOnHasInstance")) {
280 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), constructor, JSStringCreateWithUTF8CString("test script"), 1, exception);
284 JSStringRef numberString = JSStringCreateWithUTF8CString("Number");
285 JSObjectRef numberConstructor = JSValueToObject(context, JSObjectGetProperty(context, JSContextGetGlobalObject(context), numberString, exception), exception);
286 JSStringRelease(numberString);
288 return JSValueIsInstanceOfConstructor(context, possibleValue, numberConstructor, exception);
291 static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
293 UNUSED_PARAM(object);
294 UNUSED_PARAM(exception);
298 return JSValueMakeNumber(context, 1);
301 JSStringRef string = JSStringCreateWithUTF8CString("MyObjectAsString");
302 JSValueRef result = JSValueMakeString(context, string);
303 JSStringRelease(string);
310 // string conversion -- forward to default object class
311 return JSValueMakeNull(context);
314 static bool MyObject_set_nullGetForwardSet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
317 UNUSED_PARAM(object);
318 UNUSED_PARAM(propertyName);
320 UNUSED_PARAM(exception);
321 return false; // Forward to parent class.
324 static JSStaticValue evilStaticValues[] = {
325 { "nullGetSet", 0, 0, kJSPropertyAttributeNone },
326 { "nullGetForwardSet", 0, MyObject_set_nullGetForwardSet, kJSPropertyAttributeNone },
330 static JSStaticFunction evilStaticFunctions[] = {
331 { "nullCall", 0, kJSPropertyAttributeNone },
335 JSClassDefinition MyObject_definition = {
337 kJSClassAttributeNone,
347 MyObject_hasProperty,
348 MyObject_getProperty,
349 MyObject_setProperty,
350 MyObject_deleteProperty,
351 MyObject_getPropertyNames,
352 MyObject_callAsFunction,
353 MyObject_callAsConstructor,
354 MyObject_hasInstance,
355 MyObject_convertToType,
358 static JSClassRef MyObject_class(JSContextRef context)
360 UNUSED_PARAM(context);
362 static JSClassRef jsClass;
364 jsClass = JSClassCreate(&MyObject_definition);
369 static JSValueRef PropertyCatchalls_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
371 UNUSED_PARAM(context);
372 UNUSED_PARAM(object);
373 UNUSED_PARAM(propertyName);
374 UNUSED_PARAM(exception);
376 if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
381 // Swallow all .x gets after 5, returning null.
382 return JSValueMakeNull(context);
385 if (JSStringIsEqualToUTF8CString(propertyName, "y")) {
390 // Swallow all .y gets after 5, returning null.
391 return JSValueMakeNull(context);
394 if (JSStringIsEqualToUTF8CString(propertyName, "z")) {
399 // Swallow all .y gets after 5, returning null.
400 return JSValueMakeNull(context);
406 static bool PropertyCatchalls_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
408 UNUSED_PARAM(context);
409 UNUSED_PARAM(object);
410 UNUSED_PARAM(propertyName);
412 UNUSED_PARAM(exception);
414 if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
419 // Swallow all .x sets after 4.
426 static void PropertyCatchalls_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
428 UNUSED_PARAM(context);
429 UNUSED_PARAM(object);
432 static const char* numbers[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
434 // Provide a property of a different name every time.
435 JSStringRef propertyName = JSStringCreateWithUTF8CString(numbers[count++ % 10]);
436 JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
437 JSStringRelease(propertyName);
440 JSClassDefinition PropertyCatchalls_definition = {
442 kJSClassAttributeNone,
453 PropertyCatchalls_getProperty,
454 PropertyCatchalls_setProperty,
456 PropertyCatchalls_getPropertyNames,
463 static JSClassRef PropertyCatchalls_class(JSContextRef context)
465 UNUSED_PARAM(context);
467 static JSClassRef jsClass;
469 jsClass = JSClassCreate(&PropertyCatchalls_definition);
474 static bool EvilExceptionObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
476 UNUSED_PARAM(context);
477 UNUSED_PARAM(constructor);
479 JSStringRef hasInstanceName = JSStringCreateWithUTF8CString("hasInstance");
480 JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception);
481 JSStringRelease(hasInstanceName);
484 JSObjectRef function = JSValueToObject(context, hasInstance, exception);
485 JSValueRef result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception);
486 return result && JSValueToBoolean(context, result);
489 static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
491 UNUSED_PARAM(object);
492 UNUSED_PARAM(exception);
493 JSStringRef funcName;
496 funcName = JSStringCreateWithUTF8CString("toNumber");
499 funcName = JSStringCreateWithUTF8CString("toStringExplicit");
502 return JSValueMakeNull(context);
506 JSValueRef func = JSObjectGetProperty(context, object, funcName, exception);
507 JSStringRelease(funcName);
508 JSObjectRef function = JSValueToObject(context, func, exception);
510 return JSValueMakeNull(context);
511 JSValueRef value = JSObjectCallAsFunction(context, function, object, 0, NULL, exception);
513 JSStringRef errorString = JSStringCreateWithUTF8CString("convertToType failed");
514 JSValueRef errorStringRef = JSValueMakeString(context, errorString);
515 JSStringRelease(errorString);
516 return errorStringRef;
521 JSClassDefinition EvilExceptionObject_definition = {
523 kJSClassAttributeNone,
525 "EvilExceptionObject",
540 EvilExceptionObject_hasInstance,
541 EvilExceptionObject_convertToType,
544 static JSClassRef EvilExceptionObject_class(JSContextRef context)
546 UNUSED_PARAM(context);
548 static JSClassRef jsClass;
550 jsClass = JSClassCreate(&EvilExceptionObject_definition);
555 JSClassDefinition EmptyObject_definition = {
557 kJSClassAttributeNone,
578 static JSClassRef EmptyObject_class(JSContextRef context)
580 UNUSED_PARAM(context);
582 static JSClassRef jsClass;
584 jsClass = JSClassCreate(&EmptyObject_definition);
590 static JSValueRef Base_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
592 UNUSED_PARAM(object);
593 UNUSED_PARAM(propertyName);
594 UNUSED_PARAM(exception);
596 return JSValueMakeNumber(ctx, 1); // distinguish base get form derived get
599 static bool Base_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
601 UNUSED_PARAM(object);
602 UNUSED_PARAM(propertyName);
605 *exception = JSValueMakeNumber(ctx, 1); // distinguish base set from derived set
609 static JSValueRef Base_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
611 UNUSED_PARAM(function);
612 UNUSED_PARAM(thisObject);
613 UNUSED_PARAM(argumentCount);
614 UNUSED_PARAM(arguments);
615 UNUSED_PARAM(exception);
617 return JSValueMakeNumber(ctx, 1); // distinguish base call from derived call
620 static JSStaticFunction Base_staticFunctions[] = {
621 { "baseProtoDup", NULL, kJSPropertyAttributeNone },
622 { "baseProto", Base_callAsFunction, kJSPropertyAttributeNone },
626 static JSStaticValue Base_staticValues[] = {
627 { "baseDup", Base_get, Base_set, kJSPropertyAttributeNone },
628 { "baseOnly", Base_get, Base_set, kJSPropertyAttributeNone },
632 static bool TestInitializeFinalize;
633 static void Base_initialize(JSContextRef context, JSObjectRef object)
635 UNUSED_PARAM(context);
637 if (TestInitializeFinalize) {
638 ASSERT((void*)1 == JSObjectGetPrivate(object));
639 JSObjectSetPrivate(object, (void*)2);
643 static unsigned Base_didFinalize;
644 static void Base_finalize(JSObjectRef object)
646 UNUSED_PARAM(object);
647 if (TestInitializeFinalize) {
648 ASSERT((void*)4 == JSObjectGetPrivate(object));
649 Base_didFinalize = true;
653 static JSClassRef Base_class(JSContextRef context)
655 UNUSED_PARAM(context);
657 static JSClassRef jsClass;
659 JSClassDefinition definition = kJSClassDefinitionEmpty;
660 definition.staticValues = Base_staticValues;
661 definition.staticFunctions = Base_staticFunctions;
662 definition.initialize = Base_initialize;
663 definition.finalize = Base_finalize;
664 jsClass = JSClassCreate(&definition);
669 static JSValueRef Derived_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
671 UNUSED_PARAM(object);
672 UNUSED_PARAM(propertyName);
673 UNUSED_PARAM(exception);
675 return JSValueMakeNumber(ctx, 2); // distinguish base get form derived get
678 static bool Derived_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
681 UNUSED_PARAM(object);
682 UNUSED_PARAM(propertyName);
685 *exception = JSValueMakeNumber(ctx, 2); // distinguish base set from derived set
689 static JSValueRef Derived_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
691 UNUSED_PARAM(function);
692 UNUSED_PARAM(thisObject);
693 UNUSED_PARAM(argumentCount);
694 UNUSED_PARAM(arguments);
695 UNUSED_PARAM(exception);
697 return JSValueMakeNumber(ctx, 2); // distinguish base call from derived call
700 static JSStaticFunction Derived_staticFunctions[] = {
701 { "protoOnly", Derived_callAsFunction, kJSPropertyAttributeNone },
702 { "protoDup", NULL, kJSPropertyAttributeNone },
703 { "baseProtoDup", Derived_callAsFunction, kJSPropertyAttributeNone },
707 static JSStaticValue Derived_staticValues[] = {
708 { "derivedOnly", Derived_get, Derived_set, kJSPropertyAttributeNone },
709 { "protoDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
710 { "baseDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
714 static void Derived_initialize(JSContextRef context, JSObjectRef object)
716 UNUSED_PARAM(context);
718 if (TestInitializeFinalize) {
719 ASSERT((void*)2 == JSObjectGetPrivate(object));
720 JSObjectSetPrivate(object, (void*)3);
724 static void Derived_finalize(JSObjectRef object)
726 if (TestInitializeFinalize) {
727 ASSERT((void*)3 == JSObjectGetPrivate(object));
728 JSObjectSetPrivate(object, (void*)4);
732 static JSClassRef Derived_class(JSContextRef context)
734 static JSClassRef jsClass;
736 JSClassDefinition definition = kJSClassDefinitionEmpty;
737 definition.parentClass = Base_class(context);
738 definition.staticValues = Derived_staticValues;
739 definition.staticFunctions = Derived_staticFunctions;
740 definition.initialize = Derived_initialize;
741 definition.finalize = Derived_finalize;
742 jsClass = JSClassCreate(&definition);
747 static JSClassRef Derived2_class(JSContextRef context)
749 static JSClassRef jsClass;
751 JSClassDefinition definition = kJSClassDefinitionEmpty;
752 definition.parentClass = Derived_class(context);
753 jsClass = JSClassCreate(&definition);
758 static JSValueRef print_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
760 UNUSED_PARAM(functionObject);
761 UNUSED_PARAM(thisObject);
762 UNUSED_PARAM(exception);
764 ASSERT(JSContextGetGlobalContext(ctx) == context);
766 if (argumentCount > 0) {
767 JSStringRef string = JSValueToStringCopy(ctx, arguments[0], NULL);
768 size_t sizeUTF8 = JSStringGetMaximumUTF8CStringSize(string);
769 char* stringUTF8 = (char*)malloc(sizeUTF8);
770 JSStringGetUTF8CString(string, stringUTF8, sizeUTF8);
771 printf("%s\n", stringUTF8);
773 JSStringRelease(string);
776 return JSValueMakeUndefined(ctx);
779 static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
781 UNUSED_PARAM(constructorObject);
782 UNUSED_PARAM(exception);
784 JSObjectRef result = JSObjectMake(context, NULL, NULL);
785 if (argumentCount > 0) {
786 JSStringRef value = JSStringCreateWithUTF8CString("value");
787 JSObjectSetProperty(context, result, value, arguments[0], kJSPropertyAttributeNone, NULL);
788 JSStringRelease(value);
795 static void globalObject_initialize(JSContextRef context, JSObjectRef object)
797 UNUSED_PARAM(object);
798 // Ensure that an execution context is passed in
801 // Ensure that the global object is set to the object that we were passed
802 JSObjectRef globalObject = JSContextGetGlobalObject(context);
803 ASSERT(globalObject);
804 ASSERT(object == globalObject);
806 // Ensure that the standard global properties have been set on the global object
807 JSStringRef array = JSStringCreateWithUTF8CString("Array");
808 JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
809 JSStringRelease(array);
811 UNUSED_PARAM(arrayConstructor);
812 ASSERT(arrayConstructor);
815 static JSValueRef globalObject_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
817 UNUSED_PARAM(object);
818 UNUSED_PARAM(propertyName);
819 UNUSED_PARAM(exception);
821 return JSValueMakeNumber(ctx, 3);
824 static bool globalObject_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
826 UNUSED_PARAM(object);
827 UNUSED_PARAM(propertyName);
830 *exception = JSValueMakeNumber(ctx, 3);
834 static JSValueRef globalObject_call(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
836 UNUSED_PARAM(function);
837 UNUSED_PARAM(thisObject);
838 UNUSED_PARAM(argumentCount);
839 UNUSED_PARAM(arguments);
840 UNUSED_PARAM(exception);
842 return JSValueMakeNumber(ctx, 3);
845 static JSValueRef functionGC(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
847 UNUSED_PARAM(function);
848 UNUSED_PARAM(thisObject);
849 UNUSED_PARAM(argumentCount);
850 UNUSED_PARAM(arguments);
851 UNUSED_PARAM(exception);
852 JSGarbageCollect(context);
853 return JSValueMakeUndefined(context);
856 static JSStaticValue globalObject_staticValues[] = {
857 { "globalStaticValue", globalObject_get, globalObject_set, kJSPropertyAttributeNone },
861 static JSStaticFunction globalObject_staticFunctions[] = {
862 { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone },
863 { "gc", functionGC, kJSPropertyAttributeNone },
867 static char* createStringWithContentsOfFile(const char* fileName);
869 static void testInitializeFinalize()
871 JSObjectRef o = JSObjectMake(context, Derived_class(context), (void*)1);
873 ASSERT(JSObjectGetPrivate(o) == (void*)3);
876 static JSValueRef jsNumberValue = NULL;
878 static JSObjectRef aHeapRef = NULL;
880 static void makeGlobalNumberValue(JSContextRef context) {
881 JSValueRef v = JSValueMakeNumber(context, 420);
882 JSValueProtect(context, v);
887 static bool assertTrue(bool value, const char* message)
891 fprintf(stderr, "assertTrue failed: '%s'\n", message);
893 fprintf(stderr, "assertTrue failed.\n");
899 static bool checkForCycleInPrototypeChain()
902 JSGlobalContextRef context = JSGlobalContextCreate(0);
903 JSObjectRef object1 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
904 JSObjectRef object2 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
905 JSObjectRef object3 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
907 JSObjectSetPrototype(context, object1, JSValueMakeNull(context));
908 ASSERT(JSValueIsNull(context, JSObjectGetPrototype(context, object1)));
910 // object1 -> object1
911 JSObjectSetPrototype(context, object1, object1);
912 result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to assign self as a prototype");
914 // object1 -> object2 -> object1
915 JSObjectSetPrototype(context, object2, object1);
916 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object1));
917 JSObjectSetPrototype(context, object1, object2);
918 result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to close a prototype chain cycle");
920 // object1 -> object2 -> object3 -> object1
921 JSObjectSetPrototype(context, object2, object3);
922 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object3));
923 JSObjectSetPrototype(context, object1, object2);
924 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object1), object2));
925 JSObjectSetPrototype(context, object3, object1);
926 result &= assertTrue(!JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object3), object1), "It is possible to close a prototype chain cycle");
928 JSValueRef exception;
929 JSStringRef code = JSStringCreateWithUTF8CString("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o");
930 JSStringRef file = JSStringCreateWithUTF8CString("");
931 result &= assertTrue(!JSEvaluateScript(context, code, /* thisObject*/ 0, file, 1, &exception)
932 , "An exception should be thrown");
934 JSStringRelease(code);
935 JSStringRelease(file);
936 JSGlobalContextRelease(context);
940 static void checkConstnessInJSObjectNames()
942 JSStaticFunction fun;
943 fun.name = "something";
945 val.name = "something";
948 int main(int argc, char* argv[])
951 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
952 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
953 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
957 const char *scriptPath = "testapi.js";
959 scriptPath = argv[1];
962 // Test garbage collection with a fresh context
963 context = JSGlobalContextCreateInGroup(NULL, NULL);
964 TestInitializeFinalize = true;
965 testInitializeFinalize();
966 JSGlobalContextRelease(context);
967 TestInitializeFinalize = false;
969 ASSERT(Base_didFinalize);
971 JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty;
972 globalObjectClassDefinition.initialize = globalObject_initialize;
973 globalObjectClassDefinition.staticValues = globalObject_staticValues;
974 globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions;
975 globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
976 JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition);
977 context = JSGlobalContextCreateInGroup(NULL, globalObjectClass);
979 JSGlobalContextRetain(context);
980 JSGlobalContextRelease(context);
981 ASSERT(JSContextGetGlobalContext(context) == context);
983 JSReportExtraMemoryCost(context, 0);
984 JSReportExtraMemoryCost(context, 1);
985 JSReportExtraMemoryCost(context, 1024);
987 JSObjectRef globalObject = JSContextGetGlobalObject(context);
988 ASSERT(JSValueIsObject(context, globalObject));
990 JSValueRef jsUndefined = JSValueMakeUndefined(context);
991 JSValueRef jsNull = JSValueMakeNull(context);
992 JSValueRef jsTrue = JSValueMakeBoolean(context, true);
993 JSValueRef jsFalse = JSValueMakeBoolean(context, false);
994 JSValueRef jsZero = JSValueMakeNumber(context, 0);
995 JSValueRef jsOne = JSValueMakeNumber(context, 1);
996 JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0);
997 JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, NULL);
998 JSObjectSetPrototype(context, jsObjectNoProto, JSValueMakeNull(context));
1000 // FIXME: test funny utf8 characters
1001 JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString("");
1002 JSValueRef jsEmptyString = JSValueMakeString(context, jsEmptyIString);
1004 JSStringRef jsOneIString = JSStringCreateWithUTF8CString("1");
1005 JSValueRef jsOneString = JSValueMakeString(context, jsOneIString);
1007 UniChar singleUniChar = 65; // Capital A
1008 CFMutableStringRef cfString =
1009 CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault,
1015 JSStringRef jsCFIString = JSStringCreateWithCFString(cfString);
1016 JSValueRef jsCFString = JSValueMakeString(context, jsCFIString);
1018 CFStringRef cfEmptyString = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8);
1020 JSStringRef jsCFEmptyIString = JSStringCreateWithCFString(cfEmptyString);
1021 JSValueRef jsCFEmptyString = JSValueMakeString(context, jsCFEmptyIString);
1023 CFIndex cfStringLength = CFStringGetLength(cfString);
1024 UniChar* buffer = (UniChar*)malloc(cfStringLength * sizeof(UniChar));
1025 CFStringGetCharacters(cfString,
1026 CFRangeMake(0, cfStringLength),
1028 JSStringRef jsCFIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, cfStringLength);
1029 JSValueRef jsCFStringWithCharacters = JSValueMakeString(context, jsCFIStringWithCharacters);
1031 JSStringRef jsCFEmptyIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, CFStringGetLength(cfEmptyString));
1033 JSValueRef jsCFEmptyStringWithCharacters = JSValueMakeString(context, jsCFEmptyIStringWithCharacters);
1035 ASSERT(JSValueGetType(context, jsUndefined) == kJSTypeUndefined);
1036 ASSERT(JSValueGetType(context, jsNull) == kJSTypeNull);
1037 ASSERT(JSValueGetType(context, jsTrue) == kJSTypeBoolean);
1038 ASSERT(JSValueGetType(context, jsFalse) == kJSTypeBoolean);
1039 ASSERT(JSValueGetType(context, jsZero) == kJSTypeNumber);
1040 ASSERT(JSValueGetType(context, jsOne) == kJSTypeNumber);
1041 ASSERT(JSValueGetType(context, jsOneThird) == kJSTypeNumber);
1042 ASSERT(JSValueGetType(context, jsEmptyString) == kJSTypeString);
1043 ASSERT(JSValueGetType(context, jsOneString) == kJSTypeString);
1044 ASSERT(JSValueGetType(context, jsCFString) == kJSTypeString);
1045 ASSERT(JSValueGetType(context, jsCFStringWithCharacters) == kJSTypeString);
1046 ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString);
1047 ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);
1049 JSObjectRef propertyCatchalls = JSObjectMake(context, PropertyCatchalls_class(context), NULL);
1050 JSStringRef propertyCatchallsString = JSStringCreateWithUTF8CString("PropertyCatchalls");
1051 JSObjectSetProperty(context, globalObject, propertyCatchallsString, propertyCatchalls, kJSPropertyAttributeNone, NULL);
1052 JSStringRelease(propertyCatchallsString);
1054 JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
1055 JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
1056 JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
1057 JSStringRelease(myObjectIString);
1059 JSObjectRef EvilExceptionObject = JSObjectMake(context, EvilExceptionObject_class(context), NULL);
1060 JSStringRef EvilExceptionObjectIString = JSStringCreateWithUTF8CString("EvilExceptionObject");
1061 JSObjectSetProperty(context, globalObject, EvilExceptionObjectIString, EvilExceptionObject, kJSPropertyAttributeNone, NULL);
1062 JSStringRelease(EvilExceptionObjectIString);
1064 JSObjectRef EmptyObject = JSObjectMake(context, EmptyObject_class(context), NULL);
1065 JSStringRef EmptyObjectIString = JSStringCreateWithUTF8CString("EmptyObject");
1066 JSObjectSetProperty(context, globalObject, EmptyObjectIString, EmptyObject, kJSPropertyAttributeNone, NULL);
1067 JSStringRelease(EmptyObjectIString);
1069 JSStringRef lengthStr = JSStringCreateWithUTF8CString("length");
1070 JSObjectRef aStackRef = JSObjectMakeArray(context, 0, 0, 0);
1071 aHeapRef = aStackRef;
1072 JSObjectSetProperty(context, aHeapRef, lengthStr, JSValueMakeNumber(context, 10), 0, 0);
1073 JSStringRef privatePropertyName = JSStringCreateWithUTF8CString("privateProperty");
1074 if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, aHeapRef)) {
1075 printf("FAIL: Could not set private property.\n");
1078 printf("PASS: Set private property.\n");
1080 if (JSObjectSetPrivateProperty(context, aHeapRef, privatePropertyName, aHeapRef)) {
1081 printf("FAIL: JSObjectSetPrivateProperty should fail on non-API objects.\n");
1084 printf("PASS: Did not allow JSObjectSetPrivateProperty on a non-API object.\n");
1085 if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName) != aHeapRef) {
1086 printf("FAIL: Could not retrieve private property.\n");
1089 printf("PASS: Retrieved private property.\n");
1090 if (JSObjectGetPrivateProperty(context, aHeapRef, privatePropertyName)) {
1091 printf("FAIL: JSObjectGetPrivateProperty should return NULL when called on a non-API object.\n");
1094 printf("PASS: JSObjectGetPrivateProperty return NULL.\n");
1096 if (JSObjectGetProperty(context, myObject, privatePropertyName, 0) == aHeapRef) {
1097 printf("FAIL: Accessed private property through ordinary property lookup.\n");
1100 printf("PASS: Cannot access private property through ordinary property lookup.\n");
1102 JSGarbageCollect(context);
1104 for (int i = 0; i < 10000; i++)
1105 JSObjectMake(context, 0, 0);
1107 aHeapRef = JSValueToObject(context, JSObjectGetPrivateProperty(context, myObject, privatePropertyName), 0);
1108 if (JSValueToNumber(context, JSObjectGetProperty(context, aHeapRef, lengthStr, 0), 0) != 10) {
1109 printf("FAIL: Private property has been collected.\n");
1112 printf("PASS: Private property does not appear to have been collected.\n");
1113 JSStringRelease(lengthStr);
1115 if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, 0)) {
1116 printf("FAIL: Could not set private property to NULL.\n");
1119 printf("PASS: Set private property to NULL.\n");
1120 if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName)) {
1121 printf("FAIL: Could not retrieve private property.\n");
1124 printf("PASS: Retrieved private property.\n");
1126 JSStringRef validJSON = JSStringCreateWithUTF8CString("{\"aProperty\":true}");
1127 JSValueRef jsonObject = JSValueMakeFromJSONString(context, validJSON);
1128 JSStringRelease(validJSON);
1129 if (!JSValueIsObject(context, jsonObject)) {
1130 printf("FAIL: Did not parse valid JSON correctly\n");
1133 printf("PASS: Parsed valid JSON string.\n");
1134 JSStringRef propertyName = JSStringCreateWithUTF8CString("aProperty");
1135 assertEqualsAsBoolean(JSObjectGetProperty(context, JSValueToObject(context, jsonObject, 0), propertyName, 0), true);
1136 JSStringRelease(propertyName);
1137 JSStringRef invalidJSON = JSStringCreateWithUTF8CString("fail!");
1138 if (JSValueMakeFromJSONString(context, invalidJSON)) {
1139 printf("FAIL: Should return null for invalid JSON data\n");
1142 printf("PASS: Correctly returned null for invalid JSON data.\n");
1143 JSValueRef exception;
1144 JSStringRef str = JSValueCreateJSONString(context, jsonObject, 0, 0);
1145 if (!JSStringIsEqualToUTF8CString(str, "{\"aProperty\":true}")) {
1146 printf("FAIL: Did not correctly serialise with indent of 0.\n");
1149 printf("PASS: Correctly serialised with indent of 0.\n");
1150 JSStringRelease(str);
1152 str = JSValueCreateJSONString(context, jsonObject, 4, 0);
1153 if (!JSStringIsEqualToUTF8CString(str, "{\n \"aProperty\": true\n}")) {
1154 printf("FAIL: Did not correctly serialise with indent of 4.\n");
1157 printf("PASS: Correctly serialised with indent of 4.\n");
1158 JSStringRelease(str);
1159 JSStringRef src = JSStringCreateWithUTF8CString("({get a(){ throw '';}})");
1160 JSValueRef unstringifiableObj = JSEvaluateScript(context, src, NULL, NULL, 1, NULL);
1162 str = JSValueCreateJSONString(context, unstringifiableObj, 4, 0);
1164 printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
1165 JSStringRelease(str);
1168 printf("PASS: returned null when attempting to serialize unserializable value.\n");
1170 str = JSValueCreateJSONString(context, unstringifiableObj, 4, &exception);
1172 printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
1173 JSStringRelease(str);
1176 printf("PASS: returned null when attempting to serialize unserializable value.\n");
1178 printf("FAIL: Did not set exception on serialisation error\n");
1181 printf("PASS: set exception on serialisation error\n");
1182 // Conversions that throw exceptions
1184 ASSERT(NULL == JSValueToObject(context, jsNull, &exception));
1188 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
1189 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
1190 // After that's resolved, we can remove these casts
1191 ASSERT(isnan((float)JSValueToNumber(context, jsObjectNoProto, &exception)));
1195 ASSERT(!JSValueToStringCopy(context, jsObjectNoProto, &exception));
1198 ASSERT(JSValueToBoolean(context, myObject));
1201 ASSERT(!JSValueIsEqual(context, jsObjectNoProto, JSValueMakeNumber(context, 1), &exception));
1205 JSObjectGetPropertyAtIndex(context, myObject, 0, &exception);
1206 ASSERT(1 == JSValueToNumber(context, exception, NULL));
1208 assertEqualsAsBoolean(jsUndefined, false);
1209 assertEqualsAsBoolean(jsNull, false);
1210 assertEqualsAsBoolean(jsTrue, true);
1211 assertEqualsAsBoolean(jsFalse, false);
1212 assertEqualsAsBoolean(jsZero, false);
1213 assertEqualsAsBoolean(jsOne, true);
1214 assertEqualsAsBoolean(jsOneThird, true);
1215 assertEqualsAsBoolean(jsEmptyString, false);
1216 assertEqualsAsBoolean(jsOneString, true);
1217 assertEqualsAsBoolean(jsCFString, true);
1218 assertEqualsAsBoolean(jsCFStringWithCharacters, true);
1219 assertEqualsAsBoolean(jsCFEmptyString, false);
1220 assertEqualsAsBoolean(jsCFEmptyStringWithCharacters, false);
1222 assertEqualsAsNumber(jsUndefined, nan(""));
1223 assertEqualsAsNumber(jsNull, 0);
1224 assertEqualsAsNumber(jsTrue, 1);
1225 assertEqualsAsNumber(jsFalse, 0);
1226 assertEqualsAsNumber(jsZero, 0);
1227 assertEqualsAsNumber(jsOne, 1);
1228 assertEqualsAsNumber(jsOneThird, 1.0 / 3.0);
1229 assertEqualsAsNumber(jsEmptyString, 0);
1230 assertEqualsAsNumber(jsOneString, 1);
1231 assertEqualsAsNumber(jsCFString, nan(""));
1232 assertEqualsAsNumber(jsCFStringWithCharacters, nan(""));
1233 assertEqualsAsNumber(jsCFEmptyString, 0);
1234 assertEqualsAsNumber(jsCFEmptyStringWithCharacters, 0);
1235 ASSERT(sizeof(JSChar) == sizeof(UniChar));
1237 assertEqualsAsCharactersPtr(jsUndefined, "undefined");
1238 assertEqualsAsCharactersPtr(jsNull, "null");
1239 assertEqualsAsCharactersPtr(jsTrue, "true");
1240 assertEqualsAsCharactersPtr(jsFalse, "false");
1241 assertEqualsAsCharactersPtr(jsZero, "0");
1242 assertEqualsAsCharactersPtr(jsOne, "1");
1243 assertEqualsAsCharactersPtr(jsOneThird, "0.3333333333333333");
1244 assertEqualsAsCharactersPtr(jsEmptyString, "");
1245 assertEqualsAsCharactersPtr(jsOneString, "1");
1246 assertEqualsAsCharactersPtr(jsCFString, "A");
1247 assertEqualsAsCharactersPtr(jsCFStringWithCharacters, "A");
1248 assertEqualsAsCharactersPtr(jsCFEmptyString, "");
1249 assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters, "");
1251 assertEqualsAsUTF8String(jsUndefined, "undefined");
1252 assertEqualsAsUTF8String(jsNull, "null");
1253 assertEqualsAsUTF8String(jsTrue, "true");
1254 assertEqualsAsUTF8String(jsFalse, "false");
1255 assertEqualsAsUTF8String(jsZero, "0");
1256 assertEqualsAsUTF8String(jsOne, "1");
1257 assertEqualsAsUTF8String(jsOneThird, "0.3333333333333333");
1258 assertEqualsAsUTF8String(jsEmptyString, "");
1259 assertEqualsAsUTF8String(jsOneString, "1");
1260 assertEqualsAsUTF8String(jsCFString, "A");
1261 assertEqualsAsUTF8String(jsCFStringWithCharacters, "A");
1262 assertEqualsAsUTF8String(jsCFEmptyString, "");
1263 assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters, "");
1265 checkConstnessInJSObjectNames();
1267 ASSERT(JSValueIsStrictEqual(context, jsTrue, jsTrue));
1268 ASSERT(!JSValueIsStrictEqual(context, jsOne, jsOneString));
1270 ASSERT(JSValueIsEqual(context, jsOne, jsOneString, NULL));
1271 ASSERT(!JSValueIsEqual(context, jsTrue, jsFalse, NULL));
1273 CFStringRef cfJSString = JSStringCopyCFString(kCFAllocatorDefault, jsCFIString);
1274 CFStringRef cfJSEmptyString = JSStringCopyCFString(kCFAllocatorDefault, jsCFEmptyIString);
1275 ASSERT(CFEqual(cfJSString, cfString));
1276 ASSERT(CFEqual(cfJSEmptyString, cfEmptyString));
1277 CFRelease(cfJSString);
1278 CFRelease(cfJSEmptyString);
1280 CFRelease(cfString);
1281 CFRelease(cfEmptyString);
1283 jsGlobalValue = JSObjectMake(context, NULL, NULL);
1284 makeGlobalNumberValue(context);
1285 JSValueProtect(context, jsGlobalValue);
1286 JSGarbageCollect(context);
1287 ASSERT(JSValueIsObject(context, jsGlobalValue));
1288 JSValueUnprotect(context, jsGlobalValue);
1289 JSValueUnprotect(context, jsNumberValue);
1291 JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;");
1292 JSStringRef badSyntax = JSStringCreateWithUTF8CString("x := 1;");
1293 ASSERT(JSCheckScriptSyntax(context, goodSyntax, NULL, 0, NULL));
1294 ASSERT(!JSCheckScriptSyntax(context, badSyntax, NULL, 0, NULL));
1301 result = JSEvaluateScript(context, goodSyntax, NULL, NULL, 1, NULL);
1303 ASSERT(JSValueIsEqual(context, result, jsOne, NULL));
1306 result = JSEvaluateScript(context, badSyntax, NULL, NULL, 1, &exception);
1308 ASSERT(JSValueIsObject(context, exception));
1310 JSStringRef array = JSStringCreateWithUTF8CString("Array");
1311 JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
1312 JSStringRelease(array);
1313 result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL);
1315 ASSERT(JSValueIsObject(context, result));
1316 ASSERT(JSValueIsInstanceOfConstructor(context, result, arrayConstructor, NULL));
1317 ASSERT(!JSValueIsInstanceOfConstructor(context, JSValueMakeNull(context), arrayConstructor, NULL));
1319 o = JSValueToObject(context, result, NULL);
1321 ASSERT(JSValueIsUndefined(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception)));
1324 JSObjectSetPropertyAtIndex(context, o, 0, JSValueMakeNumber(context, 1), &exception);
1328 ASSERT(1 == JSValueToNumber(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception), &exception));
1331 JSStringRef functionBody;
1332 JSObjectRef function;
1335 functionBody = JSStringCreateWithUTF8CString("rreturn Array;");
1336 JSStringRef line = JSStringCreateWithUTF8CString("line");
1337 ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception));
1338 ASSERT(JSValueIsObject(context, exception));
1339 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL);
1340 assertEqualsAsNumber(v, 1);
1341 JSStringRelease(functionBody);
1342 JSStringRelease(line);
1345 functionBody = JSStringCreateWithUTF8CString("return Array;");
1346 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception);
1347 JSStringRelease(functionBody);
1349 ASSERT(JSObjectIsFunction(context, function));
1350 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1352 ASSERT(JSValueIsEqual(context, v, arrayConstructor, NULL));
1355 function = JSObjectMakeFunction(context, NULL, 0, NULL, jsEmptyIString, NULL, 0, &exception);
1357 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, &exception);
1358 ASSERT(v && !exception);
1359 ASSERT(JSValueIsUndefined(context, v));
1363 JSStringRef foo = JSStringCreateWithUTF8CString("foo");
1364 JSStringRef argumentNames[] = { foo };
1365 functionBody = JSStringCreateWithUTF8CString("return foo;");
1366 function = JSObjectMakeFunction(context, foo, 1, argumentNames, functionBody, NULL, 1, &exception);
1367 ASSERT(function && !exception);
1368 JSValueRef arguments[] = { JSValueMakeNumber(context, 2) };
1369 JSObjectCallAsFunction(context, function, NULL, 1, arguments, &exception);
1370 JSStringRelease(foo);
1371 JSStringRelease(functionBody);
1373 string = JSValueToStringCopy(context, function, NULL);
1374 assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) { return foo;\n}");
1375 JSStringRelease(string);
1377 JSStringRef print = JSStringCreateWithUTF8CString("print");
1378 JSObjectRef printFunction = JSObjectMakeFunctionWithCallback(context, print, print_callAsFunction);
1379 JSObjectSetProperty(context, globalObject, print, printFunction, kJSPropertyAttributeNone, NULL);
1380 JSStringRelease(print);
1382 ASSERT(!JSObjectSetPrivate(printFunction, (void*)1));
1383 ASSERT(!JSObjectGetPrivate(printFunction));
1385 JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor");
1386 JSObjectRef myConstructor = JSObjectMakeConstructor(context, NULL, myConstructor_callAsConstructor);
1387 JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL);
1388 JSStringRelease(myConstructorIString);
1390 ASSERT(!JSObjectSetPrivate(myConstructor, (void*)1));
1391 ASSERT(!JSObjectGetPrivate(myConstructor));
1393 string = JSStringCreateWithUTF8CString("Base");
1394 JSObjectRef baseConstructor = JSObjectMakeConstructor(context, Base_class(context), NULL);
1395 JSObjectSetProperty(context, globalObject, string, baseConstructor, kJSPropertyAttributeNone, NULL);
1396 JSStringRelease(string);
1398 string = JSStringCreateWithUTF8CString("Derived");
1399 JSObjectRef derivedConstructor = JSObjectMakeConstructor(context, Derived_class(context), NULL);
1400 JSObjectSetProperty(context, globalObject, string, derivedConstructor, kJSPropertyAttributeNone, NULL);
1401 JSStringRelease(string);
1403 string = JSStringCreateWithUTF8CString("Derived2");
1404 JSObjectRef derived2Constructor = JSObjectMakeConstructor(context, Derived2_class(context), NULL);
1405 JSObjectSetProperty(context, globalObject, string, derived2Constructor, kJSPropertyAttributeNone, NULL);
1406 JSStringRelease(string);
1408 o = JSObjectMake(context, NULL, NULL);
1409 JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL);
1410 JSObjectSetProperty(context, o, jsCFIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL);
1411 JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o);
1412 size_t expectedCount = JSPropertyNameArrayGetCount(nameArray);
1414 for (count = 0; count < expectedCount; ++count)
1415 JSPropertyNameArrayGetNameAtIndex(nameArray, count);
1416 JSPropertyNameArrayRelease(nameArray);
1417 ASSERT(count == 1); // jsCFString should not be enumerated
1419 JSValueRef argumentsArrayValues[] = { JSValueMakeNumber(context, 10), JSValueMakeNumber(context, 20) };
1420 o = JSObjectMakeArray(context, sizeof(argumentsArrayValues) / sizeof(JSValueRef), argumentsArrayValues, NULL);
1421 string = JSStringCreateWithUTF8CString("length");
1422 v = JSObjectGetProperty(context, o, string, NULL);
1423 assertEqualsAsNumber(v, 2);
1424 v = JSObjectGetPropertyAtIndex(context, o, 0, NULL);
1425 assertEqualsAsNumber(v, 10);
1426 v = JSObjectGetPropertyAtIndex(context, o, 1, NULL);
1427 assertEqualsAsNumber(v, 20);
1429 o = JSObjectMakeArray(context, 0, NULL, NULL);
1430 v = JSObjectGetProperty(context, o, string, NULL);
1431 assertEqualsAsNumber(v, 0);
1432 JSStringRelease(string);
1434 JSValueRef argumentsDateValues[] = { JSValueMakeNumber(context, 0) };
1435 o = JSObjectMakeDate(context, 1, argumentsDateValues, NULL);
1436 if (timeZoneIsPST())
1437 assertEqualsAsUTF8String(o, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)");
1439 string = JSStringCreateWithUTF8CString("an error message");
1440 JSValueRef argumentsErrorValues[] = { JSValueMakeString(context, string) };
1441 o = JSObjectMakeError(context, 1, argumentsErrorValues, NULL);
1442 assertEqualsAsUTF8String(o, "Error: an error message");
1443 JSStringRelease(string);
1445 string = JSStringCreateWithUTF8CString("foo");
1446 JSStringRef string2 = JSStringCreateWithUTF8CString("gi");
1447 JSValueRef argumentsRegExpValues[] = { JSValueMakeString(context, string), JSValueMakeString(context, string2) };
1448 o = JSObjectMakeRegExp(context, 2, argumentsRegExpValues, NULL);
1449 assertEqualsAsUTF8String(o, "/foo/gi");
1450 JSStringRelease(string);
1451 JSStringRelease(string2);
1453 JSClassDefinition nullDefinition = kJSClassDefinitionEmpty;
1454 nullDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
1455 JSClassRef nullClass = JSClassCreate(&nullDefinition);
1456 JSClassRelease(nullClass);
1458 nullDefinition = kJSClassDefinitionEmpty;
1459 nullClass = JSClassCreate(&nullDefinition);
1460 JSClassRelease(nullClass);
1462 functionBody = JSStringCreateWithUTF8CString("return this;");
1463 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
1464 JSStringRelease(functionBody);
1465 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1466 ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1467 v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
1468 ASSERT(JSValueIsEqual(context, v, o, NULL));
1470 functionBody = JSStringCreateWithUTF8CString("return eval(\"this\");");
1471 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
1472 JSStringRelease(functionBody);
1473 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1474 ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1475 v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
1476 ASSERT(JSValueIsEqual(context, v, o, NULL));
1478 JSStringRef script = JSStringCreateWithUTF8CString("this;");
1479 v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
1480 ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1481 v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
1482 ASSERT(JSValueIsEqual(context, v, o, NULL));
1483 JSStringRelease(script);
1485 script = JSStringCreateWithUTF8CString("eval(this);");
1486 v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
1487 ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1488 v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
1489 ASSERT(JSValueIsEqual(context, v, o, NULL));
1490 JSStringRelease(script);
1492 // Verify that creating a constructor for a class with no static functions does not trigger
1493 // an assert inside putDirect or lead to a crash during GC. <https://bugs.webkit.org/show_bug.cgi?id=25785>
1494 nullDefinition = kJSClassDefinitionEmpty;
1495 nullClass = JSClassCreate(&nullDefinition);
1496 JSObjectMakeConstructor(context, nullClass, 0);
1497 JSClassRelease(nullClass);
1499 char* scriptUTF8 = createStringWithContentsOfFile(scriptPath);
1501 printf("FAIL: Test script could not be loaded.\n");
1504 script = JSStringCreateWithUTF8CString(scriptUTF8);
1505 result = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
1506 if (result && JSValueIsUndefined(context, result))
1507 printf("PASS: Test script executed successfully.\n");
1509 printf("FAIL: Test script returned unexpected value:\n");
1510 JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL);
1511 CFStringRef exceptionCF = JSStringCopyCFString(kCFAllocatorDefault, exceptionIString);
1512 CFShow(exceptionCF);
1513 CFRelease(exceptionCF);
1514 JSStringRelease(exceptionIString);
1517 JSStringRelease(script);
1521 // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
1525 globalObject = NULL;
1526 myConstructor = NULL;
1528 JSStringRelease(jsEmptyIString);
1529 JSStringRelease(jsOneIString);
1530 JSStringRelease(jsCFIString);
1531 JSStringRelease(jsCFEmptyIString);
1532 JSStringRelease(jsCFIStringWithCharacters);
1533 JSStringRelease(jsCFEmptyIStringWithCharacters);
1534 JSStringRelease(goodSyntax);
1535 JSStringRelease(badSyntax);
1537 JSGlobalContextRelease(context);
1538 JSClassRelease(globalObjectClass);
1540 // Test for an infinite prototype chain that used to be created. This test
1541 // passes if the call to JSObjectHasProperty() does not hang.
1543 JSClassDefinition prototypeLoopClassDefinition = kJSClassDefinitionEmpty;
1544 prototypeLoopClassDefinition.staticFunctions = globalObject_staticFunctions;
1545 JSClassRef prototypeLoopClass = JSClassCreate(&prototypeLoopClassDefinition);
1546 JSGlobalContextRef prototypeLoopContext = JSGlobalContextCreateInGroup(NULL, prototypeLoopClass);
1548 JSStringRef nameProperty = JSStringCreateWithUTF8CString("name");
1549 JSObjectHasProperty(prototypeLoopContext, JSContextGetGlobalObject(prototypeLoopContext), nameProperty);
1551 JSGlobalContextRelease(prototypeLoopContext);
1552 JSClassRelease(prototypeLoopClass);
1554 printf("PASS: Infinite prototype chain does not occur.\n");
1556 if (checkForCycleInPrototypeChain())
1557 printf("PASS: A cycle in a prototype chain can't be created.\n");
1559 printf("FAIL: A cycle in a prototype chain can be created.\n");
1564 printf("FAIL: Some tests failed.\n");
1568 printf("PASS: Program exited normally.\n");
1572 static char* createStringWithContentsOfFile(const char* fileName)
1576 size_t buffer_size = 0;
1577 size_t buffer_capacity = 1024;
1578 buffer = (char*)malloc(buffer_capacity);
1580 FILE* f = fopen(fileName, "r");
1582 fprintf(stderr, "Could not open file: %s\n", fileName);
1586 while (!feof(f) && !ferror(f)) {
1587 buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f);
1588 if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0'
1589 buffer_capacity *= 2;
1590 buffer = (char*)realloc(buffer, buffer_capacity);
1594 ASSERT(buffer_size < buffer_capacity);
1597 buffer[buffer_size] = '\0';