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 JSValueRef
MyObject_convertToTypeWrapper(JSContextRef context
, JSObjectRef object
, JSType type
, JSValueRef
* exception
)
316 UNUSED_PARAM(context
);
317 UNUSED_PARAM(object
);
319 UNUSED_PARAM(exception
);
320 // Forward to default object class
324 static bool MyObject_set_nullGetForwardSet(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
327 UNUSED_PARAM(object
);
328 UNUSED_PARAM(propertyName
);
330 UNUSED_PARAM(exception
);
331 return false; // Forward to parent class.
334 static JSStaticValue evilStaticValues
[] = {
335 { "nullGetSet", 0, 0, kJSPropertyAttributeNone
},
336 { "nullGetForwardSet", 0, MyObject_set_nullGetForwardSet
, kJSPropertyAttributeNone
},
340 static JSStaticFunction evilStaticFunctions
[] = {
341 { "nullCall", 0, kJSPropertyAttributeNone
},
345 JSClassDefinition MyObject_definition
= {
347 kJSClassAttributeNone
,
357 MyObject_hasProperty
,
358 MyObject_getProperty
,
359 MyObject_setProperty
,
360 MyObject_deleteProperty
,
361 MyObject_getPropertyNames
,
362 MyObject_callAsFunction
,
363 MyObject_callAsConstructor
,
364 MyObject_hasInstance
,
365 MyObject_convertToType
,
368 JSClassDefinition MyObject_convertToTypeWrapperDefinition
= {
370 kJSClassAttributeNone
,
388 MyObject_convertToTypeWrapper
,
391 JSClassDefinition MyObject_nullWrapperDefinition
= {
393 kJSClassAttributeNone
,
414 static JSClassRef
MyObject_class(JSContextRef context
)
416 UNUSED_PARAM(context
);
418 static JSClassRef jsClass
;
420 JSClassRef baseClass
= JSClassCreate(&MyObject_definition
);
421 MyObject_convertToTypeWrapperDefinition
.parentClass
= baseClass
;
422 JSClassRef wrapperClass
= JSClassCreate(&MyObject_convertToTypeWrapperDefinition
);
423 MyObject_nullWrapperDefinition
.parentClass
= wrapperClass
;
424 jsClass
= JSClassCreate(&MyObject_nullWrapperDefinition
);
430 static JSValueRef
PropertyCatchalls_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
432 UNUSED_PARAM(context
);
433 UNUSED_PARAM(object
);
434 UNUSED_PARAM(propertyName
);
435 UNUSED_PARAM(exception
);
437 if (JSStringIsEqualToUTF8CString(propertyName
, "x")) {
442 // Swallow all .x gets after 5, returning null.
443 return JSValueMakeNull(context
);
446 if (JSStringIsEqualToUTF8CString(propertyName
, "y")) {
451 // Swallow all .y gets after 5, returning null.
452 return JSValueMakeNull(context
);
455 if (JSStringIsEqualToUTF8CString(propertyName
, "z")) {
460 // Swallow all .y gets after 5, returning null.
461 return JSValueMakeNull(context
);
467 static bool PropertyCatchalls_setProperty(JSContextRef context
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
469 UNUSED_PARAM(context
);
470 UNUSED_PARAM(object
);
471 UNUSED_PARAM(propertyName
);
473 UNUSED_PARAM(exception
);
475 if (JSStringIsEqualToUTF8CString(propertyName
, "x")) {
480 // Swallow all .x sets after 4.
487 static void PropertyCatchalls_getPropertyNames(JSContextRef context
, JSObjectRef object
, JSPropertyNameAccumulatorRef propertyNames
)
489 UNUSED_PARAM(context
);
490 UNUSED_PARAM(object
);
493 static const char* numbers
[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
495 // Provide a property of a different name every time.
496 JSStringRef propertyName
= JSStringCreateWithUTF8CString(numbers
[count
++ % 10]);
497 JSPropertyNameAccumulatorAddName(propertyNames
, propertyName
);
498 JSStringRelease(propertyName
);
501 JSClassDefinition PropertyCatchalls_definition
= {
503 kJSClassAttributeNone
,
514 PropertyCatchalls_getProperty
,
515 PropertyCatchalls_setProperty
,
517 PropertyCatchalls_getPropertyNames
,
524 static JSClassRef
PropertyCatchalls_class(JSContextRef context
)
526 UNUSED_PARAM(context
);
528 static JSClassRef jsClass
;
530 jsClass
= JSClassCreate(&PropertyCatchalls_definition
);
535 static bool EvilExceptionObject_hasInstance(JSContextRef context
, JSObjectRef constructor
, JSValueRef possibleValue
, JSValueRef
* exception
)
537 UNUSED_PARAM(context
);
538 UNUSED_PARAM(constructor
);
540 JSStringRef hasInstanceName
= JSStringCreateWithUTF8CString("hasInstance");
541 JSValueRef hasInstance
= JSObjectGetProperty(context
, constructor
, hasInstanceName
, exception
);
542 JSStringRelease(hasInstanceName
);
545 JSObjectRef function
= JSValueToObject(context
, hasInstance
, exception
);
546 JSValueRef result
= JSObjectCallAsFunction(context
, function
, constructor
, 1, &possibleValue
, exception
);
547 return result
&& JSValueToBoolean(context
, result
);
550 static JSValueRef
EvilExceptionObject_convertToType(JSContextRef context
, JSObjectRef object
, JSType type
, JSValueRef
* exception
)
552 UNUSED_PARAM(object
);
553 UNUSED_PARAM(exception
);
554 JSStringRef funcName
;
557 funcName
= JSStringCreateWithUTF8CString("toNumber");
560 funcName
= JSStringCreateWithUTF8CString("toStringExplicit");
563 return JSValueMakeNull(context
);
567 JSValueRef func
= JSObjectGetProperty(context
, object
, funcName
, exception
);
568 JSStringRelease(funcName
);
569 JSObjectRef function
= JSValueToObject(context
, func
, exception
);
571 return JSValueMakeNull(context
);
572 JSValueRef value
= JSObjectCallAsFunction(context
, function
, object
, 0, NULL
, exception
);
574 JSStringRef errorString
= JSStringCreateWithUTF8CString("convertToType failed");
575 JSValueRef errorStringRef
= JSValueMakeString(context
, errorString
);
576 JSStringRelease(errorString
);
577 return errorStringRef
;
582 JSClassDefinition EvilExceptionObject_definition
= {
584 kJSClassAttributeNone
,
586 "EvilExceptionObject",
601 EvilExceptionObject_hasInstance
,
602 EvilExceptionObject_convertToType
,
605 static JSClassRef
EvilExceptionObject_class(JSContextRef context
)
607 UNUSED_PARAM(context
);
609 static JSClassRef jsClass
;
611 jsClass
= JSClassCreate(&EvilExceptionObject_definition
);
616 JSClassDefinition EmptyObject_definition
= {
618 kJSClassAttributeNone
,
639 static JSClassRef
EmptyObject_class(JSContextRef context
)
641 UNUSED_PARAM(context
);
643 static JSClassRef jsClass
;
645 jsClass
= JSClassCreate(&EmptyObject_definition
);
651 static JSValueRef
Base_get(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
653 UNUSED_PARAM(object
);
654 UNUSED_PARAM(propertyName
);
655 UNUSED_PARAM(exception
);
657 return JSValueMakeNumber(ctx
, 1); // distinguish base get form derived get
660 static bool Base_set(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
662 UNUSED_PARAM(object
);
663 UNUSED_PARAM(propertyName
);
666 *exception
= JSValueMakeNumber(ctx
, 1); // distinguish base set from derived set
670 static JSValueRef
Base_callAsFunction(JSContextRef ctx
, JSObjectRef function
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
672 UNUSED_PARAM(function
);
673 UNUSED_PARAM(thisObject
);
674 UNUSED_PARAM(argumentCount
);
675 UNUSED_PARAM(arguments
);
676 UNUSED_PARAM(exception
);
678 return JSValueMakeNumber(ctx
, 1); // distinguish base call from derived call
681 static JSValueRef
Base_returnHardNull(JSContextRef ctx
, JSObjectRef function
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
684 UNUSED_PARAM(function
);
685 UNUSED_PARAM(thisObject
);
686 UNUSED_PARAM(argumentCount
);
687 UNUSED_PARAM(arguments
);
688 UNUSED_PARAM(exception
);
690 return 0; // should convert to undefined!
693 static JSStaticFunction Base_staticFunctions
[] = {
694 { "baseProtoDup", NULL
, kJSPropertyAttributeNone
},
695 { "baseProto", Base_callAsFunction
, kJSPropertyAttributeNone
},
696 { "baseHardNull", Base_returnHardNull
, kJSPropertyAttributeNone
},
700 static JSStaticValue Base_staticValues
[] = {
701 { "baseDup", Base_get
, Base_set
, kJSPropertyAttributeNone
},
702 { "baseOnly", Base_get
, Base_set
, kJSPropertyAttributeNone
},
706 static bool TestInitializeFinalize
;
707 static void Base_initialize(JSContextRef context
, JSObjectRef object
)
709 UNUSED_PARAM(context
);
711 if (TestInitializeFinalize
) {
712 ASSERT((void*)1 == JSObjectGetPrivate(object
));
713 JSObjectSetPrivate(object
, (void*)2);
717 static unsigned Base_didFinalize
;
718 static void Base_finalize(JSObjectRef object
)
720 UNUSED_PARAM(object
);
721 if (TestInitializeFinalize
) {
722 ASSERT((void*)4 == JSObjectGetPrivate(object
));
723 Base_didFinalize
= true;
727 static JSClassRef
Base_class(JSContextRef context
)
729 UNUSED_PARAM(context
);
731 static JSClassRef jsClass
;
733 JSClassDefinition definition
= kJSClassDefinitionEmpty
;
734 definition
.staticValues
= Base_staticValues
;
735 definition
.staticFunctions
= Base_staticFunctions
;
736 definition
.initialize
= Base_initialize
;
737 definition
.finalize
= Base_finalize
;
738 jsClass
= JSClassCreate(&definition
);
743 static JSValueRef
Derived_get(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
745 UNUSED_PARAM(object
);
746 UNUSED_PARAM(propertyName
);
747 UNUSED_PARAM(exception
);
749 return JSValueMakeNumber(ctx
, 2); // distinguish base get form derived get
752 static bool Derived_set(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
755 UNUSED_PARAM(object
);
756 UNUSED_PARAM(propertyName
);
759 *exception
= JSValueMakeNumber(ctx
, 2); // distinguish base set from derived set
763 static JSValueRef
Derived_callAsFunction(JSContextRef ctx
, JSObjectRef function
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
765 UNUSED_PARAM(function
);
766 UNUSED_PARAM(thisObject
);
767 UNUSED_PARAM(argumentCount
);
768 UNUSED_PARAM(arguments
);
769 UNUSED_PARAM(exception
);
771 return JSValueMakeNumber(ctx
, 2); // distinguish base call from derived call
774 static JSStaticFunction Derived_staticFunctions
[] = {
775 { "protoOnly", Derived_callAsFunction
, kJSPropertyAttributeNone
},
776 { "protoDup", NULL
, kJSPropertyAttributeNone
},
777 { "baseProtoDup", Derived_callAsFunction
, kJSPropertyAttributeNone
},
781 static JSStaticValue Derived_staticValues
[] = {
782 { "derivedOnly", Derived_get
, Derived_set
, kJSPropertyAttributeNone
},
783 { "protoDup", Derived_get
, Derived_set
, kJSPropertyAttributeNone
},
784 { "baseDup", Derived_get
, Derived_set
, kJSPropertyAttributeNone
},
788 static void Derived_initialize(JSContextRef context
, JSObjectRef object
)
790 UNUSED_PARAM(context
);
792 if (TestInitializeFinalize
) {
793 ASSERT((void*)2 == JSObjectGetPrivate(object
));
794 JSObjectSetPrivate(object
, (void*)3);
798 static void Derived_finalize(JSObjectRef object
)
800 if (TestInitializeFinalize
) {
801 ASSERT((void*)3 == JSObjectGetPrivate(object
));
802 JSObjectSetPrivate(object
, (void*)4);
806 static JSClassRef
Derived_class(JSContextRef context
)
808 static JSClassRef jsClass
;
810 JSClassDefinition definition
= kJSClassDefinitionEmpty
;
811 definition
.parentClass
= Base_class(context
);
812 definition
.staticValues
= Derived_staticValues
;
813 definition
.staticFunctions
= Derived_staticFunctions
;
814 definition
.initialize
= Derived_initialize
;
815 definition
.finalize
= Derived_finalize
;
816 jsClass
= JSClassCreate(&definition
);
821 static JSClassRef
Derived2_class(JSContextRef context
)
823 static JSClassRef jsClass
;
825 JSClassDefinition definition
= kJSClassDefinitionEmpty
;
826 definition
.parentClass
= Derived_class(context
);
827 jsClass
= JSClassCreate(&definition
);
832 static JSValueRef
print_callAsFunction(JSContextRef ctx
, JSObjectRef functionObject
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
834 UNUSED_PARAM(functionObject
);
835 UNUSED_PARAM(thisObject
);
836 UNUSED_PARAM(exception
);
838 ASSERT(JSContextGetGlobalContext(ctx
) == context
);
840 if (argumentCount
> 0) {
841 JSStringRef string
= JSValueToStringCopy(ctx
, arguments
[0], NULL
);
842 size_t sizeUTF8
= JSStringGetMaximumUTF8CStringSize(string
);
843 char* stringUTF8
= (char*)malloc(sizeUTF8
);
844 JSStringGetUTF8CString(string
, stringUTF8
, sizeUTF8
);
845 printf("%s\n", stringUTF8
);
847 JSStringRelease(string
);
850 return JSValueMakeUndefined(ctx
);
853 static JSObjectRef
myConstructor_callAsConstructor(JSContextRef context
, JSObjectRef constructorObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
855 UNUSED_PARAM(constructorObject
);
856 UNUSED_PARAM(exception
);
858 JSObjectRef result
= JSObjectMake(context
, NULL
, NULL
);
859 if (argumentCount
> 0) {
860 JSStringRef value
= JSStringCreateWithUTF8CString("value");
861 JSObjectSetProperty(context
, result
, value
, arguments
[0], kJSPropertyAttributeNone
, NULL
);
862 JSStringRelease(value
);
868 static JSObjectRef
myBadConstructor_callAsConstructor(JSContextRef context
, JSObjectRef constructorObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
870 UNUSED_PARAM(context
);
871 UNUSED_PARAM(constructorObject
);
872 UNUSED_PARAM(argumentCount
);
873 UNUSED_PARAM(arguments
);
874 UNUSED_PARAM(exception
);
880 static void globalObject_initialize(JSContextRef context
, JSObjectRef object
)
882 UNUSED_PARAM(object
);
883 // Ensure that an execution context is passed in
886 // Ensure that the global object is set to the object that we were passed
887 JSObjectRef globalObject
= JSContextGetGlobalObject(context
);
888 ASSERT(globalObject
);
889 ASSERT(object
== globalObject
);
891 // Ensure that the standard global properties have been set on the global object
892 JSStringRef array
= JSStringCreateWithUTF8CString("Array");
893 JSObjectRef arrayConstructor
= JSValueToObject(context
, JSObjectGetProperty(context
, globalObject
, array
, NULL
), NULL
);
894 JSStringRelease(array
);
896 UNUSED_PARAM(arrayConstructor
);
897 ASSERT(arrayConstructor
);
900 static JSValueRef
globalObject_get(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
902 UNUSED_PARAM(object
);
903 UNUSED_PARAM(propertyName
);
904 UNUSED_PARAM(exception
);
906 return JSValueMakeNumber(ctx
, 3);
909 static bool globalObject_set(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
911 UNUSED_PARAM(object
);
912 UNUSED_PARAM(propertyName
);
915 *exception
= JSValueMakeNumber(ctx
, 3);
919 static JSValueRef
globalObject_call(JSContextRef ctx
, JSObjectRef function
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
921 UNUSED_PARAM(function
);
922 UNUSED_PARAM(thisObject
);
923 UNUSED_PARAM(argumentCount
);
924 UNUSED_PARAM(arguments
);
925 UNUSED_PARAM(exception
);
927 return JSValueMakeNumber(ctx
, 3);
930 static JSValueRef
functionGC(JSContextRef context
, JSObjectRef function
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
932 UNUSED_PARAM(function
);
933 UNUSED_PARAM(thisObject
);
934 UNUSED_PARAM(argumentCount
);
935 UNUSED_PARAM(arguments
);
936 UNUSED_PARAM(exception
);
937 JSGarbageCollect(context
);
938 return JSValueMakeUndefined(context
);
941 static JSStaticValue globalObject_staticValues
[] = {
942 { "globalStaticValue", globalObject_get
, globalObject_set
, kJSPropertyAttributeNone
},
946 static JSStaticFunction globalObject_staticFunctions
[] = {
947 { "globalStaticFunction", globalObject_call
, kJSPropertyAttributeNone
},
948 { "gc", functionGC
, kJSPropertyAttributeNone
},
952 static char* createStringWithContentsOfFile(const char* fileName
);
954 static void testInitializeFinalize()
956 JSObjectRef o
= JSObjectMake(context
, Derived_class(context
), (void*)1);
958 ASSERT(JSObjectGetPrivate(o
) == (void*)3);
961 static JSValueRef jsNumberValue
= NULL
;
963 static JSObjectRef aHeapRef
= NULL
;
965 static void makeGlobalNumberValue(JSContextRef context
) {
966 JSValueRef v
= JSValueMakeNumber(context
, 420);
967 JSValueProtect(context
, v
);
972 static bool assertTrue(bool value
, const char* message
)
976 fprintf(stderr
, "assertTrue failed: '%s'\n", message
);
978 fprintf(stderr
, "assertTrue failed.\n");
984 static bool checkForCycleInPrototypeChain()
987 JSGlobalContextRef context
= JSGlobalContextCreate(0);
988 JSObjectRef object1
= JSObjectMake(context
, /* jsClass */ 0, /* data */ 0);
989 JSObjectRef object2
= JSObjectMake(context
, /* jsClass */ 0, /* data */ 0);
990 JSObjectRef object3
= JSObjectMake(context
, /* jsClass */ 0, /* data */ 0);
992 JSObjectSetPrototype(context
, object1
, JSValueMakeNull(context
));
993 ASSERT(JSValueIsNull(context
, JSObjectGetPrototype(context
, object1
)));
995 // object1 -> object1
996 JSObjectSetPrototype(context
, object1
, object1
);
997 result
&= assertTrue(JSValueIsNull(context
, JSObjectGetPrototype(context
, object1
)), "It is possible to assign self as a prototype");
999 // object1 -> object2 -> object1
1000 JSObjectSetPrototype(context
, object2
, object1
);
1001 ASSERT(JSValueIsStrictEqual(context
, JSObjectGetPrototype(context
, object2
), object1
));
1002 JSObjectSetPrototype(context
, object1
, object2
);
1003 result
&= assertTrue(JSValueIsNull(context
, JSObjectGetPrototype(context
, object1
)), "It is possible to close a prototype chain cycle");
1005 // object1 -> object2 -> object3 -> object1
1006 JSObjectSetPrototype(context
, object2
, object3
);
1007 ASSERT(JSValueIsStrictEqual(context
, JSObjectGetPrototype(context
, object2
), object3
));
1008 JSObjectSetPrototype(context
, object1
, object2
);
1009 ASSERT(JSValueIsStrictEqual(context
, JSObjectGetPrototype(context
, object1
), object2
));
1010 JSObjectSetPrototype(context
, object3
, object1
);
1011 result
&= assertTrue(!JSValueIsStrictEqual(context
, JSObjectGetPrototype(context
, object3
), object1
), "It is possible to close a prototype chain cycle");
1013 JSValueRef exception
;
1014 JSStringRef code
= JSStringCreateWithUTF8CString("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o");
1015 JSStringRef file
= JSStringCreateWithUTF8CString("");
1016 result
&= assertTrue(!JSEvaluateScript(context
, code
, /* thisObject*/ 0, file
, 1, &exception
)
1017 , "An exception should be thrown");
1019 JSStringRelease(code
);
1020 JSStringRelease(file
);
1021 JSGlobalContextRelease(context
);
1025 static void checkConstnessInJSObjectNames()
1027 JSStaticFunction fun
;
1028 fun
.name
= "something";
1030 val
.name
= "something";
1033 int main(int argc
, char* argv
[])
1036 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
1037 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
1038 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
1042 const char *scriptPath
= "testapi.js";
1044 scriptPath
= argv
[1];
1047 // Test garbage collection with a fresh context
1048 context
= JSGlobalContextCreateInGroup(NULL
, NULL
);
1049 TestInitializeFinalize
= true;
1050 testInitializeFinalize();
1051 JSGlobalContextRelease(context
);
1052 TestInitializeFinalize
= false;
1054 ASSERT(Base_didFinalize
);
1056 JSClassDefinition globalObjectClassDefinition
= kJSClassDefinitionEmpty
;
1057 globalObjectClassDefinition
.initialize
= globalObject_initialize
;
1058 globalObjectClassDefinition
.staticValues
= globalObject_staticValues
;
1059 globalObjectClassDefinition
.staticFunctions
= globalObject_staticFunctions
;
1060 globalObjectClassDefinition
.attributes
= kJSClassAttributeNoAutomaticPrototype
;
1061 JSClassRef globalObjectClass
= JSClassCreate(&globalObjectClassDefinition
);
1062 context
= JSGlobalContextCreateInGroup(NULL
, globalObjectClass
);
1064 JSGlobalContextRetain(context
);
1065 JSGlobalContextRelease(context
);
1066 ASSERT(JSContextGetGlobalContext(context
) == context
);
1068 JSReportExtraMemoryCost(context
, 0);
1069 JSReportExtraMemoryCost(context
, 1);
1070 JSReportExtraMemoryCost(context
, 1024);
1072 JSObjectRef globalObject
= JSContextGetGlobalObject(context
);
1073 ASSERT(JSValueIsObject(context
, globalObject
));
1075 JSValueRef jsUndefined
= JSValueMakeUndefined(context
);
1076 JSValueRef jsNull
= JSValueMakeNull(context
);
1077 JSValueRef jsTrue
= JSValueMakeBoolean(context
, true);
1078 JSValueRef jsFalse
= JSValueMakeBoolean(context
, false);
1079 JSValueRef jsZero
= JSValueMakeNumber(context
, 0);
1080 JSValueRef jsOne
= JSValueMakeNumber(context
, 1);
1081 JSValueRef jsOneThird
= JSValueMakeNumber(context
, 1.0 / 3.0);
1082 JSObjectRef jsObjectNoProto
= JSObjectMake(context
, NULL
, NULL
);
1083 JSObjectSetPrototype(context
, jsObjectNoProto
, JSValueMakeNull(context
));
1085 // FIXME: test funny utf8 characters
1086 JSStringRef jsEmptyIString
= JSStringCreateWithUTF8CString("");
1087 JSValueRef jsEmptyString
= JSValueMakeString(context
, jsEmptyIString
);
1089 JSStringRef jsOneIString
= JSStringCreateWithUTF8CString("1");
1090 JSValueRef jsOneString
= JSValueMakeString(context
, jsOneIString
);
1092 UniChar singleUniChar
= 65; // Capital A
1093 CFMutableStringRef cfString
=
1094 CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault
,
1100 JSStringRef jsCFIString
= JSStringCreateWithCFString(cfString
);
1101 JSValueRef jsCFString
= JSValueMakeString(context
, jsCFIString
);
1103 CFStringRef cfEmptyString
= CFStringCreateWithCString(kCFAllocatorDefault
, "", kCFStringEncodingUTF8
);
1105 JSStringRef jsCFEmptyIString
= JSStringCreateWithCFString(cfEmptyString
);
1106 JSValueRef jsCFEmptyString
= JSValueMakeString(context
, jsCFEmptyIString
);
1108 CFIndex cfStringLength
= CFStringGetLength(cfString
);
1109 UniChar
* buffer
= (UniChar
*)malloc(cfStringLength
* sizeof(UniChar
));
1110 CFStringGetCharacters(cfString
,
1111 CFRangeMake(0, cfStringLength
),
1113 JSStringRef jsCFIStringWithCharacters
= JSStringCreateWithCharacters((JSChar
*)buffer
, cfStringLength
);
1114 JSValueRef jsCFStringWithCharacters
= JSValueMakeString(context
, jsCFIStringWithCharacters
);
1116 JSStringRef jsCFEmptyIStringWithCharacters
= JSStringCreateWithCharacters((JSChar
*)buffer
, CFStringGetLength(cfEmptyString
));
1118 JSValueRef jsCFEmptyStringWithCharacters
= JSValueMakeString(context
, jsCFEmptyIStringWithCharacters
);
1120 ASSERT(JSValueGetType(context
, jsUndefined
) == kJSTypeUndefined
);
1121 ASSERT(JSValueGetType(context
, jsNull
) == kJSTypeNull
);
1122 ASSERT(JSValueGetType(context
, jsTrue
) == kJSTypeBoolean
);
1123 ASSERT(JSValueGetType(context
, jsFalse
) == kJSTypeBoolean
);
1124 ASSERT(JSValueGetType(context
, jsZero
) == kJSTypeNumber
);
1125 ASSERT(JSValueGetType(context
, jsOne
) == kJSTypeNumber
);
1126 ASSERT(JSValueGetType(context
, jsOneThird
) == kJSTypeNumber
);
1127 ASSERT(JSValueGetType(context
, jsEmptyString
) == kJSTypeString
);
1128 ASSERT(JSValueGetType(context
, jsOneString
) == kJSTypeString
);
1129 ASSERT(JSValueGetType(context
, jsCFString
) == kJSTypeString
);
1130 ASSERT(JSValueGetType(context
, jsCFStringWithCharacters
) == kJSTypeString
);
1131 ASSERT(JSValueGetType(context
, jsCFEmptyString
) == kJSTypeString
);
1132 ASSERT(JSValueGetType(context
, jsCFEmptyStringWithCharacters
) == kJSTypeString
);
1134 JSObjectRef propertyCatchalls
= JSObjectMake(context
, PropertyCatchalls_class(context
), NULL
);
1135 JSStringRef propertyCatchallsString
= JSStringCreateWithUTF8CString("PropertyCatchalls");
1136 JSObjectSetProperty(context
, globalObject
, propertyCatchallsString
, propertyCatchalls
, kJSPropertyAttributeNone
, NULL
);
1137 JSStringRelease(propertyCatchallsString
);
1139 JSObjectRef myObject
= JSObjectMake(context
, MyObject_class(context
), NULL
);
1140 JSStringRef myObjectIString
= JSStringCreateWithUTF8CString("MyObject");
1141 JSObjectSetProperty(context
, globalObject
, myObjectIString
, myObject
, kJSPropertyAttributeNone
, NULL
);
1142 JSStringRelease(myObjectIString
);
1144 JSObjectRef EvilExceptionObject
= JSObjectMake(context
, EvilExceptionObject_class(context
), NULL
);
1145 JSStringRef EvilExceptionObjectIString
= JSStringCreateWithUTF8CString("EvilExceptionObject");
1146 JSObjectSetProperty(context
, globalObject
, EvilExceptionObjectIString
, EvilExceptionObject
, kJSPropertyAttributeNone
, NULL
);
1147 JSStringRelease(EvilExceptionObjectIString
);
1149 JSObjectRef EmptyObject
= JSObjectMake(context
, EmptyObject_class(context
), NULL
);
1150 JSStringRef EmptyObjectIString
= JSStringCreateWithUTF8CString("EmptyObject");
1151 JSObjectSetProperty(context
, globalObject
, EmptyObjectIString
, EmptyObject
, kJSPropertyAttributeNone
, NULL
);
1152 JSStringRelease(EmptyObjectIString
);
1154 JSStringRef lengthStr
= JSStringCreateWithUTF8CString("length");
1155 JSObjectRef aStackRef
= JSObjectMakeArray(context
, 0, 0, 0);
1156 aHeapRef
= aStackRef
;
1157 JSObjectSetProperty(context
, aHeapRef
, lengthStr
, JSValueMakeNumber(context
, 10), 0, 0);
1158 JSStringRef privatePropertyName
= JSStringCreateWithUTF8CString("privateProperty");
1159 if (!JSObjectSetPrivateProperty(context
, myObject
, privatePropertyName
, aHeapRef
)) {
1160 printf("FAIL: Could not set private property.\n");
1163 printf("PASS: Set private property.\n");
1165 if (JSObjectSetPrivateProperty(context
, aHeapRef
, privatePropertyName
, aHeapRef
)) {
1166 printf("FAIL: JSObjectSetPrivateProperty should fail on non-API objects.\n");
1169 printf("PASS: Did not allow JSObjectSetPrivateProperty on a non-API object.\n");
1170 if (JSObjectGetPrivateProperty(context
, myObject
, privatePropertyName
) != aHeapRef
) {
1171 printf("FAIL: Could not retrieve private property.\n");
1174 printf("PASS: Retrieved private property.\n");
1175 if (JSObjectGetPrivateProperty(context
, aHeapRef
, privatePropertyName
)) {
1176 printf("FAIL: JSObjectGetPrivateProperty should return NULL when called on a non-API object.\n");
1179 printf("PASS: JSObjectGetPrivateProperty return NULL.\n");
1181 if (JSObjectGetProperty(context
, myObject
, privatePropertyName
, 0) == aHeapRef
) {
1182 printf("FAIL: Accessed private property through ordinary property lookup.\n");
1185 printf("PASS: Cannot access private property through ordinary property lookup.\n");
1187 JSGarbageCollect(context
);
1189 for (int i
= 0; i
< 10000; i
++)
1190 JSObjectMake(context
, 0, 0);
1192 aHeapRef
= JSValueToObject(context
, JSObjectGetPrivateProperty(context
, myObject
, privatePropertyName
), 0);
1193 if (JSValueToNumber(context
, JSObjectGetProperty(context
, aHeapRef
, lengthStr
, 0), 0) != 10) {
1194 printf("FAIL: Private property has been collected.\n");
1197 printf("PASS: Private property does not appear to have been collected.\n");
1198 JSStringRelease(lengthStr
);
1200 if (!JSObjectSetPrivateProperty(context
, myObject
, privatePropertyName
, 0)) {
1201 printf("FAIL: Could not set private property to NULL.\n");
1204 printf("PASS: Set private property to NULL.\n");
1205 if (JSObjectGetPrivateProperty(context
, myObject
, privatePropertyName
)) {
1206 printf("FAIL: Could not retrieve private property.\n");
1209 printf("PASS: Retrieved private property.\n");
1211 JSStringRef validJSON
= JSStringCreateWithUTF8CString("{\"aProperty\":true}");
1212 JSValueRef jsonObject
= JSValueMakeFromJSONString(context
, validJSON
);
1213 JSStringRelease(validJSON
);
1214 if (!JSValueIsObject(context
, jsonObject
)) {
1215 printf("FAIL: Did not parse valid JSON correctly\n");
1218 printf("PASS: Parsed valid JSON string.\n");
1219 JSStringRef propertyName
= JSStringCreateWithUTF8CString("aProperty");
1220 assertEqualsAsBoolean(JSObjectGetProperty(context
, JSValueToObject(context
, jsonObject
, 0), propertyName
, 0), true);
1221 JSStringRelease(propertyName
);
1222 JSStringRef invalidJSON
= JSStringCreateWithUTF8CString("fail!");
1223 if (JSValueMakeFromJSONString(context
, invalidJSON
)) {
1224 printf("FAIL: Should return null for invalid JSON data\n");
1227 printf("PASS: Correctly returned null for invalid JSON data.\n");
1228 JSValueRef exception
;
1229 JSStringRef str
= JSValueCreateJSONString(context
, jsonObject
, 0, 0);
1230 if (!JSStringIsEqualToUTF8CString(str
, "{\"aProperty\":true}")) {
1231 printf("FAIL: Did not correctly serialise with indent of 0.\n");
1234 printf("PASS: Correctly serialised with indent of 0.\n");
1235 JSStringRelease(str
);
1237 str
= JSValueCreateJSONString(context
, jsonObject
, 4, 0);
1238 if (!JSStringIsEqualToUTF8CString(str
, "{\n \"aProperty\": true\n}")) {
1239 printf("FAIL: Did not correctly serialise with indent of 4.\n");
1242 printf("PASS: Correctly serialised with indent of 4.\n");
1243 JSStringRelease(str
);
1244 JSStringRef src
= JSStringCreateWithUTF8CString("({get a(){ throw '';}})");
1245 JSValueRef unstringifiableObj
= JSEvaluateScript(context
, src
, NULL
, NULL
, 1, NULL
);
1247 str
= JSValueCreateJSONString(context
, unstringifiableObj
, 4, 0);
1249 printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
1250 JSStringRelease(str
);
1253 printf("PASS: returned null when attempting to serialize unserializable value.\n");
1255 str
= JSValueCreateJSONString(context
, unstringifiableObj
, 4, &exception
);
1257 printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
1258 JSStringRelease(str
);
1261 printf("PASS: returned null when attempting to serialize unserializable value.\n");
1263 printf("FAIL: Did not set exception on serialisation error\n");
1266 printf("PASS: set exception on serialisation error\n");
1267 // Conversions that throw exceptions
1269 ASSERT(NULL
== JSValueToObject(context
, jsNull
, &exception
));
1273 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
1274 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
1275 // After that's resolved, we can remove these casts
1276 ASSERT(isnan((float)JSValueToNumber(context
, jsObjectNoProto
, &exception
)));
1280 ASSERT(!JSValueToStringCopy(context
, jsObjectNoProto
, &exception
));
1283 ASSERT(JSValueToBoolean(context
, myObject
));
1286 ASSERT(!JSValueIsEqual(context
, jsObjectNoProto
, JSValueMakeNumber(context
, 1), &exception
));
1290 JSObjectGetPropertyAtIndex(context
, myObject
, 0, &exception
);
1291 ASSERT(1 == JSValueToNumber(context
, exception
, NULL
));
1293 assertEqualsAsBoolean(jsUndefined
, false);
1294 assertEqualsAsBoolean(jsNull
, false);
1295 assertEqualsAsBoolean(jsTrue
, true);
1296 assertEqualsAsBoolean(jsFalse
, false);
1297 assertEqualsAsBoolean(jsZero
, false);
1298 assertEqualsAsBoolean(jsOne
, true);
1299 assertEqualsAsBoolean(jsOneThird
, true);
1300 assertEqualsAsBoolean(jsEmptyString
, false);
1301 assertEqualsAsBoolean(jsOneString
, true);
1302 assertEqualsAsBoolean(jsCFString
, true);
1303 assertEqualsAsBoolean(jsCFStringWithCharacters
, true);
1304 assertEqualsAsBoolean(jsCFEmptyString
, false);
1305 assertEqualsAsBoolean(jsCFEmptyStringWithCharacters
, false);
1307 assertEqualsAsNumber(jsUndefined
, nan(""));
1308 assertEqualsAsNumber(jsNull
, 0);
1309 assertEqualsAsNumber(jsTrue
, 1);
1310 assertEqualsAsNumber(jsFalse
, 0);
1311 assertEqualsAsNumber(jsZero
, 0);
1312 assertEqualsAsNumber(jsOne
, 1);
1313 assertEqualsAsNumber(jsOneThird
, 1.0 / 3.0);
1314 assertEqualsAsNumber(jsEmptyString
, 0);
1315 assertEqualsAsNumber(jsOneString
, 1);
1316 assertEqualsAsNumber(jsCFString
, nan(""));
1317 assertEqualsAsNumber(jsCFStringWithCharacters
, nan(""));
1318 assertEqualsAsNumber(jsCFEmptyString
, 0);
1319 assertEqualsAsNumber(jsCFEmptyStringWithCharacters
, 0);
1320 ASSERT(sizeof(JSChar
) == sizeof(UniChar
));
1322 assertEqualsAsCharactersPtr(jsUndefined
, "undefined");
1323 assertEqualsAsCharactersPtr(jsNull
, "null");
1324 assertEqualsAsCharactersPtr(jsTrue
, "true");
1325 assertEqualsAsCharactersPtr(jsFalse
, "false");
1326 assertEqualsAsCharactersPtr(jsZero
, "0");
1327 assertEqualsAsCharactersPtr(jsOne
, "1");
1328 assertEqualsAsCharactersPtr(jsOneThird
, "0.3333333333333333");
1329 assertEqualsAsCharactersPtr(jsEmptyString
, "");
1330 assertEqualsAsCharactersPtr(jsOneString
, "1");
1331 assertEqualsAsCharactersPtr(jsCFString
, "A");
1332 assertEqualsAsCharactersPtr(jsCFStringWithCharacters
, "A");
1333 assertEqualsAsCharactersPtr(jsCFEmptyString
, "");
1334 assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters
, "");
1336 assertEqualsAsUTF8String(jsUndefined
, "undefined");
1337 assertEqualsAsUTF8String(jsNull
, "null");
1338 assertEqualsAsUTF8String(jsTrue
, "true");
1339 assertEqualsAsUTF8String(jsFalse
, "false");
1340 assertEqualsAsUTF8String(jsZero
, "0");
1341 assertEqualsAsUTF8String(jsOne
, "1");
1342 assertEqualsAsUTF8String(jsOneThird
, "0.3333333333333333");
1343 assertEqualsAsUTF8String(jsEmptyString
, "");
1344 assertEqualsAsUTF8String(jsOneString
, "1");
1345 assertEqualsAsUTF8String(jsCFString
, "A");
1346 assertEqualsAsUTF8String(jsCFStringWithCharacters
, "A");
1347 assertEqualsAsUTF8String(jsCFEmptyString
, "");
1348 assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters
, "");
1350 checkConstnessInJSObjectNames();
1352 ASSERT(JSValueIsStrictEqual(context
, jsTrue
, jsTrue
));
1353 ASSERT(!JSValueIsStrictEqual(context
, jsOne
, jsOneString
));
1355 ASSERT(JSValueIsEqual(context
, jsOne
, jsOneString
, NULL
));
1356 ASSERT(!JSValueIsEqual(context
, jsTrue
, jsFalse
, NULL
));
1358 CFStringRef cfJSString
= JSStringCopyCFString(kCFAllocatorDefault
, jsCFIString
);
1359 CFStringRef cfJSEmptyString
= JSStringCopyCFString(kCFAllocatorDefault
, jsCFEmptyIString
);
1360 ASSERT(CFEqual(cfJSString
, cfString
));
1361 ASSERT(CFEqual(cfJSEmptyString
, cfEmptyString
));
1362 CFRelease(cfJSString
);
1363 CFRelease(cfJSEmptyString
);
1365 CFRelease(cfString
);
1366 CFRelease(cfEmptyString
);
1368 jsGlobalValue
= JSObjectMake(context
, NULL
, NULL
);
1369 makeGlobalNumberValue(context
);
1370 JSValueProtect(context
, jsGlobalValue
);
1371 JSGarbageCollect(context
);
1372 ASSERT(JSValueIsObject(context
, jsGlobalValue
));
1373 JSValueUnprotect(context
, jsGlobalValue
);
1374 JSValueUnprotect(context
, jsNumberValue
);
1376 JSStringRef goodSyntax
= JSStringCreateWithUTF8CString("x = 1;");
1377 JSStringRef badSyntax
= JSStringCreateWithUTF8CString("x := 1;");
1378 ASSERT(JSCheckScriptSyntax(context
, goodSyntax
, NULL
, 0, NULL
));
1379 ASSERT(!JSCheckScriptSyntax(context
, badSyntax
, NULL
, 0, NULL
));
1386 result
= JSEvaluateScript(context
, goodSyntax
, NULL
, NULL
, 1, NULL
);
1388 ASSERT(JSValueIsEqual(context
, result
, jsOne
, NULL
));
1391 result
= JSEvaluateScript(context
, badSyntax
, NULL
, NULL
, 1, &exception
);
1393 ASSERT(JSValueIsObject(context
, exception
));
1395 JSStringRef array
= JSStringCreateWithUTF8CString("Array");
1396 JSObjectRef arrayConstructor
= JSValueToObject(context
, JSObjectGetProperty(context
, globalObject
, array
, NULL
), NULL
);
1397 JSStringRelease(array
);
1398 result
= JSObjectCallAsConstructor(context
, arrayConstructor
, 0, NULL
, NULL
);
1400 ASSERT(JSValueIsObject(context
, result
));
1401 ASSERT(JSValueIsInstanceOfConstructor(context
, result
, arrayConstructor
, NULL
));
1402 ASSERT(!JSValueIsInstanceOfConstructor(context
, JSValueMakeNull(context
), arrayConstructor
, NULL
));
1404 o
= JSValueToObject(context
, result
, NULL
);
1406 ASSERT(JSValueIsUndefined(context
, JSObjectGetPropertyAtIndex(context
, o
, 0, &exception
)));
1409 JSObjectSetPropertyAtIndex(context
, o
, 0, JSValueMakeNumber(context
, 1), &exception
);
1413 ASSERT(1 == JSValueToNumber(context
, JSObjectGetPropertyAtIndex(context
, o
, 0, &exception
), &exception
));
1416 JSStringRef functionBody
;
1417 JSObjectRef function
;
1420 functionBody
= JSStringCreateWithUTF8CString("rreturn Array;");
1421 JSStringRef line
= JSStringCreateWithUTF8CString("line");
1422 ASSERT(!JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, &exception
));
1423 ASSERT(JSValueIsObject(context
, exception
));
1424 v
= JSObjectGetProperty(context
, JSValueToObject(context
, exception
, NULL
), line
, NULL
);
1425 assertEqualsAsNumber(v
, 1);
1426 JSStringRelease(functionBody
);
1427 JSStringRelease(line
);
1430 functionBody
= JSStringCreateWithUTF8CString("return Array;");
1431 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, &exception
);
1432 JSStringRelease(functionBody
);
1434 ASSERT(JSObjectIsFunction(context
, function
));
1435 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, NULL
);
1437 ASSERT(JSValueIsEqual(context
, v
, arrayConstructor
, NULL
));
1440 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, jsEmptyIString
, NULL
, 0, &exception
);
1442 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, &exception
);
1443 ASSERT(v
&& !exception
);
1444 ASSERT(JSValueIsUndefined(context
, v
));
1448 JSStringRef foo
= JSStringCreateWithUTF8CString("foo");
1449 JSStringRef argumentNames
[] = { foo
};
1450 functionBody
= JSStringCreateWithUTF8CString("return foo;");
1451 function
= JSObjectMakeFunction(context
, foo
, 1, argumentNames
, functionBody
, NULL
, 1, &exception
);
1452 ASSERT(function
&& !exception
);
1453 JSValueRef arguments
[] = { JSValueMakeNumber(context
, 2) };
1454 JSObjectCallAsFunction(context
, function
, NULL
, 1, arguments
, &exception
);
1455 JSStringRelease(foo
);
1456 JSStringRelease(functionBody
);
1458 string
= JSValueToStringCopy(context
, function
, NULL
);
1459 assertEqualsAsUTF8String(JSValueMakeString(context
, string
), "function foo(foo) { return foo;\n}");
1460 JSStringRelease(string
);
1462 JSStringRef print
= JSStringCreateWithUTF8CString("print");
1463 JSObjectRef printFunction
= JSObjectMakeFunctionWithCallback(context
, print
, print_callAsFunction
);
1464 JSObjectSetProperty(context
, globalObject
, print
, printFunction
, kJSPropertyAttributeNone
, NULL
);
1465 JSStringRelease(print
);
1467 ASSERT(!JSObjectSetPrivate(printFunction
, (void*)1));
1468 ASSERT(!JSObjectGetPrivate(printFunction
));
1470 JSStringRef myConstructorIString
= JSStringCreateWithUTF8CString("MyConstructor");
1471 JSObjectRef myConstructor
= JSObjectMakeConstructor(context
, NULL
, myConstructor_callAsConstructor
);
1472 JSObjectSetProperty(context
, globalObject
, myConstructorIString
, myConstructor
, kJSPropertyAttributeNone
, NULL
);
1473 JSStringRelease(myConstructorIString
);
1475 JSStringRef myBadConstructorIString
= JSStringCreateWithUTF8CString("MyBadConstructor");
1476 JSObjectRef myBadConstructor
= JSObjectMakeConstructor(context
, NULL
, myBadConstructor_callAsConstructor
);
1477 JSObjectSetProperty(context
, globalObject
, myBadConstructorIString
, myBadConstructor
, kJSPropertyAttributeNone
, NULL
);
1478 JSStringRelease(myBadConstructorIString
);
1480 ASSERT(!JSObjectSetPrivate(myConstructor
, (void*)1));
1481 ASSERT(!JSObjectGetPrivate(myConstructor
));
1483 string
= JSStringCreateWithUTF8CString("Base");
1484 JSObjectRef baseConstructor
= JSObjectMakeConstructor(context
, Base_class(context
), NULL
);
1485 JSObjectSetProperty(context
, globalObject
, string
, baseConstructor
, kJSPropertyAttributeNone
, NULL
);
1486 JSStringRelease(string
);
1488 string
= JSStringCreateWithUTF8CString("Derived");
1489 JSObjectRef derivedConstructor
= JSObjectMakeConstructor(context
, Derived_class(context
), NULL
);
1490 JSObjectSetProperty(context
, globalObject
, string
, derivedConstructor
, kJSPropertyAttributeNone
, NULL
);
1491 JSStringRelease(string
);
1493 string
= JSStringCreateWithUTF8CString("Derived2");
1494 JSObjectRef derived2Constructor
= JSObjectMakeConstructor(context
, Derived2_class(context
), NULL
);
1495 JSObjectSetProperty(context
, globalObject
, string
, derived2Constructor
, kJSPropertyAttributeNone
, NULL
);
1496 JSStringRelease(string
);
1498 o
= JSObjectMake(context
, NULL
, NULL
);
1499 JSObjectSetProperty(context
, o
, jsOneIString
, JSValueMakeNumber(context
, 1), kJSPropertyAttributeNone
, NULL
);
1500 JSObjectSetProperty(context
, o
, jsCFIString
, JSValueMakeNumber(context
, 1), kJSPropertyAttributeDontEnum
, NULL
);
1501 JSPropertyNameArrayRef nameArray
= JSObjectCopyPropertyNames(context
, o
);
1502 size_t expectedCount
= JSPropertyNameArrayGetCount(nameArray
);
1504 for (count
= 0; count
< expectedCount
; ++count
)
1505 JSPropertyNameArrayGetNameAtIndex(nameArray
, count
);
1506 JSPropertyNameArrayRelease(nameArray
);
1507 ASSERT(count
== 1); // jsCFString should not be enumerated
1509 JSValueRef argumentsArrayValues
[] = { JSValueMakeNumber(context
, 10), JSValueMakeNumber(context
, 20) };
1510 o
= JSObjectMakeArray(context
, sizeof(argumentsArrayValues
) / sizeof(JSValueRef
), argumentsArrayValues
, NULL
);
1511 string
= JSStringCreateWithUTF8CString("length");
1512 v
= JSObjectGetProperty(context
, o
, string
, NULL
);
1513 assertEqualsAsNumber(v
, 2);
1514 v
= JSObjectGetPropertyAtIndex(context
, o
, 0, NULL
);
1515 assertEqualsAsNumber(v
, 10);
1516 v
= JSObjectGetPropertyAtIndex(context
, o
, 1, NULL
);
1517 assertEqualsAsNumber(v
, 20);
1519 o
= JSObjectMakeArray(context
, 0, NULL
, NULL
);
1520 v
= JSObjectGetProperty(context
, o
, string
, NULL
);
1521 assertEqualsAsNumber(v
, 0);
1522 JSStringRelease(string
);
1524 JSValueRef argumentsDateValues
[] = { JSValueMakeNumber(context
, 0) };
1525 o
= JSObjectMakeDate(context
, 1, argumentsDateValues
, NULL
);
1526 if (timeZoneIsPST())
1527 assertEqualsAsUTF8String(o
, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)");
1529 string
= JSStringCreateWithUTF8CString("an error message");
1530 JSValueRef argumentsErrorValues
[] = { JSValueMakeString(context
, string
) };
1531 o
= JSObjectMakeError(context
, 1, argumentsErrorValues
, NULL
);
1532 assertEqualsAsUTF8String(o
, "Error: an error message");
1533 JSStringRelease(string
);
1535 string
= JSStringCreateWithUTF8CString("foo");
1536 JSStringRef string2
= JSStringCreateWithUTF8CString("gi");
1537 JSValueRef argumentsRegExpValues
[] = { JSValueMakeString(context
, string
), JSValueMakeString(context
, string2
) };
1538 o
= JSObjectMakeRegExp(context
, 2, argumentsRegExpValues
, NULL
);
1539 assertEqualsAsUTF8String(o
, "/foo/gi");
1540 JSStringRelease(string
);
1541 JSStringRelease(string2
);
1543 JSClassDefinition nullDefinition
= kJSClassDefinitionEmpty
;
1544 nullDefinition
.attributes
= kJSClassAttributeNoAutomaticPrototype
;
1545 JSClassRef nullClass
= JSClassCreate(&nullDefinition
);
1546 JSClassRelease(nullClass
);
1548 nullDefinition
= kJSClassDefinitionEmpty
;
1549 nullClass
= JSClassCreate(&nullDefinition
);
1550 JSClassRelease(nullClass
);
1552 functionBody
= JSStringCreateWithUTF8CString("return this;");
1553 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, NULL
);
1554 JSStringRelease(functionBody
);
1555 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, NULL
);
1556 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
1557 v
= JSObjectCallAsFunction(context
, function
, o
, 0, NULL
, NULL
);
1558 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
1560 functionBody
= JSStringCreateWithUTF8CString("return eval(\"this\");");
1561 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, NULL
);
1562 JSStringRelease(functionBody
);
1563 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, NULL
);
1564 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
1565 v
= JSObjectCallAsFunction(context
, function
, o
, 0, NULL
, NULL
);
1566 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
1568 JSStringRef script
= JSStringCreateWithUTF8CString("this;");
1569 v
= JSEvaluateScript(context
, script
, NULL
, NULL
, 1, NULL
);
1570 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
1571 v
= JSEvaluateScript(context
, script
, o
, NULL
, 1, NULL
);
1572 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
1573 JSStringRelease(script
);
1575 script
= JSStringCreateWithUTF8CString("eval(this);");
1576 v
= JSEvaluateScript(context
, script
, NULL
, NULL
, 1, NULL
);
1577 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
1578 v
= JSEvaluateScript(context
, script
, o
, NULL
, 1, NULL
);
1579 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
1580 JSStringRelease(script
);
1582 // Verify that creating a constructor for a class with no static functions does not trigger
1583 // an assert inside putDirect or lead to a crash during GC. <https://bugs.webkit.org/show_bug.cgi?id=25785>
1584 nullDefinition
= kJSClassDefinitionEmpty
;
1585 nullClass
= JSClassCreate(&nullDefinition
);
1586 JSObjectMakeConstructor(context
, nullClass
, 0);
1587 JSClassRelease(nullClass
);
1589 char* scriptUTF8
= createStringWithContentsOfFile(scriptPath
);
1591 printf("FAIL: Test script could not be loaded.\n");
1594 script
= JSStringCreateWithUTF8CString(scriptUTF8
);
1595 result
= JSEvaluateScript(context
, script
, NULL
, NULL
, 1, &exception
);
1596 if (result
&& JSValueIsUndefined(context
, result
))
1597 printf("PASS: Test script executed successfully.\n");
1599 printf("FAIL: Test script returned unexpected value:\n");
1600 JSStringRef exceptionIString
= JSValueToStringCopy(context
, exception
, NULL
);
1601 CFStringRef exceptionCF
= JSStringCopyCFString(kCFAllocatorDefault
, exceptionIString
);
1602 CFShow(exceptionCF
);
1603 CFRelease(exceptionCF
);
1604 JSStringRelease(exceptionIString
);
1607 JSStringRelease(script
);
1611 // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
1615 globalObject
= NULL
;
1616 myConstructor
= NULL
;
1618 JSStringRelease(jsEmptyIString
);
1619 JSStringRelease(jsOneIString
);
1620 JSStringRelease(jsCFIString
);
1621 JSStringRelease(jsCFEmptyIString
);
1622 JSStringRelease(jsCFIStringWithCharacters
);
1623 JSStringRelease(jsCFEmptyIStringWithCharacters
);
1624 JSStringRelease(goodSyntax
);
1625 JSStringRelease(badSyntax
);
1627 JSGlobalContextRelease(context
);
1628 JSClassRelease(globalObjectClass
);
1630 // Test for an infinite prototype chain that used to be created. This test
1631 // passes if the call to JSObjectHasProperty() does not hang.
1633 JSClassDefinition prototypeLoopClassDefinition
= kJSClassDefinitionEmpty
;
1634 prototypeLoopClassDefinition
.staticFunctions
= globalObject_staticFunctions
;
1635 JSClassRef prototypeLoopClass
= JSClassCreate(&prototypeLoopClassDefinition
);
1636 JSGlobalContextRef prototypeLoopContext
= JSGlobalContextCreateInGroup(NULL
, prototypeLoopClass
);
1638 JSStringRef nameProperty
= JSStringCreateWithUTF8CString("name");
1639 JSObjectHasProperty(prototypeLoopContext
, JSContextGetGlobalObject(prototypeLoopContext
), nameProperty
);
1641 JSGlobalContextRelease(prototypeLoopContext
);
1642 JSClassRelease(prototypeLoopClass
);
1644 printf("PASS: Infinite prototype chain does not occur.\n");
1646 if (checkForCycleInPrototypeChain())
1647 printf("PASS: A cycle in a prototype chain can't be created.\n");
1649 printf("FAIL: A cycle in a prototype chain can be created.\n");
1654 printf("FAIL: Some tests failed.\n");
1658 printf("PASS: Program exited normally.\n");
1662 static char* createStringWithContentsOfFile(const char* fileName
)
1666 size_t buffer_size
= 0;
1667 size_t buffer_capacity
= 1024;
1668 buffer
= (char*)malloc(buffer_capacity
);
1670 FILE* f
= fopen(fileName
, "r");
1672 fprintf(stderr
, "Could not open file: %s\n", fileName
);
1676 while (!feof(f
) && !ferror(f
)) {
1677 buffer_size
+= fread(buffer
+ buffer_size
, 1, buffer_capacity
- buffer_size
, f
);
1678 if (buffer_size
== buffer_capacity
) { // guarantees space for trailing '\0'
1679 buffer_capacity
*= 2;
1680 buffer
= (char*)realloc(buffer
, buffer_capacity
);
1684 ASSERT(buffer_size
< buffer_capacity
);
1687 buffer
[buffer_size
] = '\0';