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 int main(int argc
, char* argv
[])
943 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
944 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
945 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
949 const char *scriptPath
= "testapi.js";
951 scriptPath
= argv
[1];
954 // Test garbage collection with a fresh context
955 context
= JSGlobalContextCreateInGroup(NULL
, NULL
);
956 TestInitializeFinalize
= true;
957 testInitializeFinalize();
958 JSGlobalContextRelease(context
);
959 TestInitializeFinalize
= false;
961 ASSERT(Base_didFinalize
);
963 JSClassDefinition globalObjectClassDefinition
= kJSClassDefinitionEmpty
;
964 globalObjectClassDefinition
.initialize
= globalObject_initialize
;
965 globalObjectClassDefinition
.staticValues
= globalObject_staticValues
;
966 globalObjectClassDefinition
.staticFunctions
= globalObject_staticFunctions
;
967 globalObjectClassDefinition
.attributes
= kJSClassAttributeNoAutomaticPrototype
;
968 JSClassRef globalObjectClass
= JSClassCreate(&globalObjectClassDefinition
);
969 context
= JSGlobalContextCreateInGroup(NULL
, globalObjectClass
);
971 JSGlobalContextRetain(context
);
972 JSGlobalContextRelease(context
);
973 ASSERT(JSContextGetGlobalContext(context
) == context
);
975 JSReportExtraMemoryCost(context
, 0);
976 JSReportExtraMemoryCost(context
, 1);
977 JSReportExtraMemoryCost(context
, 1024);
979 JSObjectRef globalObject
= JSContextGetGlobalObject(context
);
980 ASSERT(JSValueIsObject(context
, globalObject
));
982 JSValueRef jsUndefined
= JSValueMakeUndefined(context
);
983 JSValueRef jsNull
= JSValueMakeNull(context
);
984 JSValueRef jsTrue
= JSValueMakeBoolean(context
, true);
985 JSValueRef jsFalse
= JSValueMakeBoolean(context
, false);
986 JSValueRef jsZero
= JSValueMakeNumber(context
, 0);
987 JSValueRef jsOne
= JSValueMakeNumber(context
, 1);
988 JSValueRef jsOneThird
= JSValueMakeNumber(context
, 1.0 / 3.0);
989 JSObjectRef jsObjectNoProto
= JSObjectMake(context
, NULL
, NULL
);
990 JSObjectSetPrototype(context
, jsObjectNoProto
, JSValueMakeNull(context
));
992 // FIXME: test funny utf8 characters
993 JSStringRef jsEmptyIString
= JSStringCreateWithUTF8CString("");
994 JSValueRef jsEmptyString
= JSValueMakeString(context
, jsEmptyIString
);
996 JSStringRef jsOneIString
= JSStringCreateWithUTF8CString("1");
997 JSValueRef jsOneString
= JSValueMakeString(context
, jsOneIString
);
999 UniChar singleUniChar
= 65; // Capital A
1000 CFMutableStringRef cfString
=
1001 CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault
,
1007 JSStringRef jsCFIString
= JSStringCreateWithCFString(cfString
);
1008 JSValueRef jsCFString
= JSValueMakeString(context
, jsCFIString
);
1010 CFStringRef cfEmptyString
= CFStringCreateWithCString(kCFAllocatorDefault
, "", kCFStringEncodingUTF8
);
1012 JSStringRef jsCFEmptyIString
= JSStringCreateWithCFString(cfEmptyString
);
1013 JSValueRef jsCFEmptyString
= JSValueMakeString(context
, jsCFEmptyIString
);
1015 CFIndex cfStringLength
= CFStringGetLength(cfString
);
1016 UniChar
* buffer
= (UniChar
*)malloc(cfStringLength
* sizeof(UniChar
));
1017 CFStringGetCharacters(cfString
,
1018 CFRangeMake(0, cfStringLength
),
1020 JSStringRef jsCFIStringWithCharacters
= JSStringCreateWithCharacters((JSChar
*)buffer
, cfStringLength
);
1021 JSValueRef jsCFStringWithCharacters
= JSValueMakeString(context
, jsCFIStringWithCharacters
);
1023 JSStringRef jsCFEmptyIStringWithCharacters
= JSStringCreateWithCharacters((JSChar
*)buffer
, CFStringGetLength(cfEmptyString
));
1025 JSValueRef jsCFEmptyStringWithCharacters
= JSValueMakeString(context
, jsCFEmptyIStringWithCharacters
);
1027 ASSERT(JSValueGetType(context
, jsUndefined
) == kJSTypeUndefined
);
1028 ASSERT(JSValueGetType(context
, jsNull
) == kJSTypeNull
);
1029 ASSERT(JSValueGetType(context
, jsTrue
) == kJSTypeBoolean
);
1030 ASSERT(JSValueGetType(context
, jsFalse
) == kJSTypeBoolean
);
1031 ASSERT(JSValueGetType(context
, jsZero
) == kJSTypeNumber
);
1032 ASSERT(JSValueGetType(context
, jsOne
) == kJSTypeNumber
);
1033 ASSERT(JSValueGetType(context
, jsOneThird
) == kJSTypeNumber
);
1034 ASSERT(JSValueGetType(context
, jsEmptyString
) == kJSTypeString
);
1035 ASSERT(JSValueGetType(context
, jsOneString
) == kJSTypeString
);
1036 ASSERT(JSValueGetType(context
, jsCFString
) == kJSTypeString
);
1037 ASSERT(JSValueGetType(context
, jsCFStringWithCharacters
) == kJSTypeString
);
1038 ASSERT(JSValueGetType(context
, jsCFEmptyString
) == kJSTypeString
);
1039 ASSERT(JSValueGetType(context
, jsCFEmptyStringWithCharacters
) == kJSTypeString
);
1041 JSObjectRef propertyCatchalls
= JSObjectMake(context
, PropertyCatchalls_class(context
), NULL
);
1042 JSStringRef propertyCatchallsString
= JSStringCreateWithUTF8CString("PropertyCatchalls");
1043 JSObjectSetProperty(context
, globalObject
, propertyCatchallsString
, propertyCatchalls
, kJSPropertyAttributeNone
, NULL
);
1044 JSStringRelease(propertyCatchallsString
);
1046 JSObjectRef myObject
= JSObjectMake(context
, MyObject_class(context
), NULL
);
1047 JSStringRef myObjectIString
= JSStringCreateWithUTF8CString("MyObject");
1048 JSObjectSetProperty(context
, globalObject
, myObjectIString
, myObject
, kJSPropertyAttributeNone
, NULL
);
1049 JSStringRelease(myObjectIString
);
1051 JSObjectRef EvilExceptionObject
= JSObjectMake(context
, EvilExceptionObject_class(context
), NULL
);
1052 JSStringRef EvilExceptionObjectIString
= JSStringCreateWithUTF8CString("EvilExceptionObject");
1053 JSObjectSetProperty(context
, globalObject
, EvilExceptionObjectIString
, EvilExceptionObject
, kJSPropertyAttributeNone
, NULL
);
1054 JSStringRelease(EvilExceptionObjectIString
);
1056 JSObjectRef EmptyObject
= JSObjectMake(context
, EmptyObject_class(context
), NULL
);
1057 JSStringRef EmptyObjectIString
= JSStringCreateWithUTF8CString("EmptyObject");
1058 JSObjectSetProperty(context
, globalObject
, EmptyObjectIString
, EmptyObject
, kJSPropertyAttributeNone
, NULL
);
1059 JSStringRelease(EmptyObjectIString
);
1061 JSStringRef lengthStr
= JSStringCreateWithUTF8CString("length");
1062 JSObjectRef aStackRef
= JSObjectMakeArray(context
, 0, 0, 0);
1063 aHeapRef
= aStackRef
;
1064 JSObjectSetProperty(context
, aHeapRef
, lengthStr
, JSValueMakeNumber(context
, 10), 0, 0);
1065 JSStringRef privatePropertyName
= JSStringCreateWithUTF8CString("privateProperty");
1066 if (!JSObjectSetPrivateProperty(context
, myObject
, privatePropertyName
, aHeapRef
)) {
1067 printf("FAIL: Could not set private property.\n");
1070 printf("PASS: Set private property.\n");
1072 if (JSObjectSetPrivateProperty(context
, aHeapRef
, privatePropertyName
, aHeapRef
)) {
1073 printf("FAIL: JSObjectSetPrivateProperty should fail on non-API objects.\n");
1076 printf("PASS: Did not allow JSObjectSetPrivateProperty on a non-API object.\n");
1077 if (JSObjectGetPrivateProperty(context
, myObject
, privatePropertyName
) != aHeapRef
) {
1078 printf("FAIL: Could not retrieve private property.\n");
1081 printf("PASS: Retrieved private property.\n");
1082 if (JSObjectGetPrivateProperty(context
, aHeapRef
, privatePropertyName
)) {
1083 printf("FAIL: JSObjectGetPrivateProperty should return NULL when called on a non-API object.\n");
1086 printf("PASS: JSObjectGetPrivateProperty return NULL.\n");
1088 if (JSObjectGetProperty(context
, myObject
, privatePropertyName
, 0) == aHeapRef
) {
1089 printf("FAIL: Accessed private property through ordinary property lookup.\n");
1092 printf("PASS: Cannot access private property through ordinary property lookup.\n");
1094 JSGarbageCollect(context
);
1096 for (int i
= 0; i
< 10000; i
++)
1097 JSObjectMake(context
, 0, 0);
1099 aHeapRef
= JSValueToObject(context
, JSObjectGetPrivateProperty(context
, myObject
, privatePropertyName
), 0);
1100 if (JSValueToNumber(context
, JSObjectGetProperty(context
, aHeapRef
, lengthStr
, 0), 0) != 10) {
1101 printf("FAIL: Private property has been collected.\n");
1104 printf("PASS: Private property does not appear to have been collected.\n");
1105 JSStringRelease(lengthStr
);
1107 if (!JSObjectSetPrivateProperty(context
, myObject
, privatePropertyName
, 0)) {
1108 printf("FAIL: Could not set private property to NULL.\n");
1111 printf("PASS: Set private property to NULL.\n");
1112 if (JSObjectGetPrivateProperty(context
, myObject
, privatePropertyName
)) {
1113 printf("FAIL: Could not retrieve private property.\n");
1116 printf("PASS: Retrieved private property.\n");
1118 JSStringRef validJSON
= JSStringCreateWithUTF8CString("{\"aProperty\":true}");
1119 JSValueRef jsonObject
= JSValueMakeFromJSONString(context
, validJSON
);
1120 JSStringRelease(validJSON
);
1121 if (!JSValueIsObject(context
, jsonObject
)) {
1122 printf("FAIL: Did not parse valid JSON correctly\n");
1125 printf("PASS: Parsed valid JSON string.\n");
1126 JSStringRef propertyName
= JSStringCreateWithUTF8CString("aProperty");
1127 assertEqualsAsBoolean(JSObjectGetProperty(context
, JSValueToObject(context
, jsonObject
, 0), propertyName
, 0), true);
1128 JSStringRelease(propertyName
);
1129 JSStringRef invalidJSON
= JSStringCreateWithUTF8CString("fail!");
1130 if (JSValueMakeFromJSONString(context
, invalidJSON
)) {
1131 printf("FAIL: Should return null for invalid JSON data\n");
1134 printf("PASS: Correctly returned null for invalid JSON data.\n");
1135 JSValueRef exception
;
1136 JSStringRef str
= JSValueCreateJSONString(context
, jsonObject
, 0, 0);
1137 if (!JSStringIsEqualToUTF8CString(str
, "{\"aProperty\":true}")) {
1138 printf("FAIL: Did not correctly serialise with indent of 0.\n");
1141 printf("PASS: Correctly serialised with indent of 0.\n");
1142 JSStringRelease(str
);
1144 str
= JSValueCreateJSONString(context
, jsonObject
, 4, 0);
1145 if (!JSStringIsEqualToUTF8CString(str
, "{\n \"aProperty\": true\n}")) {
1146 printf("FAIL: Did not correctly serialise with indent of 4.\n");
1149 printf("PASS: Correctly serialised with indent of 4.\n");
1150 JSStringRelease(str
);
1151 JSStringRef src
= JSStringCreateWithUTF8CString("({get a(){ throw '';}})");
1152 JSValueRef unstringifiableObj
= JSEvaluateScript(context
, src
, NULL
, NULL
, 1, NULL
);
1154 str
= JSValueCreateJSONString(context
, unstringifiableObj
, 4, 0);
1156 printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
1157 JSStringRelease(str
);
1160 printf("PASS: returned null when attempting to serialize unserializable value.\n");
1162 str
= JSValueCreateJSONString(context
, unstringifiableObj
, 4, &exception
);
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 printf("FAIL: Did not set exception on serialisation error\n");
1173 printf("PASS: set exception on serialisation error\n");
1174 // Conversions that throw exceptions
1176 ASSERT(NULL
== JSValueToObject(context
, jsNull
, &exception
));
1180 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
1181 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
1182 // After that's resolved, we can remove these casts
1183 ASSERT(isnan((float)JSValueToNumber(context
, jsObjectNoProto
, &exception
)));
1187 ASSERT(!JSValueToStringCopy(context
, jsObjectNoProto
, &exception
));
1190 ASSERT(JSValueToBoolean(context
, myObject
));
1193 ASSERT(!JSValueIsEqual(context
, jsObjectNoProto
, JSValueMakeNumber(context
, 1), &exception
));
1197 JSObjectGetPropertyAtIndex(context
, myObject
, 0, &exception
);
1198 ASSERT(1 == JSValueToNumber(context
, exception
, NULL
));
1200 assertEqualsAsBoolean(jsUndefined
, false);
1201 assertEqualsAsBoolean(jsNull
, false);
1202 assertEqualsAsBoolean(jsTrue
, true);
1203 assertEqualsAsBoolean(jsFalse
, false);
1204 assertEqualsAsBoolean(jsZero
, false);
1205 assertEqualsAsBoolean(jsOne
, true);
1206 assertEqualsAsBoolean(jsOneThird
, true);
1207 assertEqualsAsBoolean(jsEmptyString
, false);
1208 assertEqualsAsBoolean(jsOneString
, true);
1209 assertEqualsAsBoolean(jsCFString
, true);
1210 assertEqualsAsBoolean(jsCFStringWithCharacters
, true);
1211 assertEqualsAsBoolean(jsCFEmptyString
, false);
1212 assertEqualsAsBoolean(jsCFEmptyStringWithCharacters
, false);
1214 assertEqualsAsNumber(jsUndefined
, nan(""));
1215 assertEqualsAsNumber(jsNull
, 0);
1216 assertEqualsAsNumber(jsTrue
, 1);
1217 assertEqualsAsNumber(jsFalse
, 0);
1218 assertEqualsAsNumber(jsZero
, 0);
1219 assertEqualsAsNumber(jsOne
, 1);
1220 assertEqualsAsNumber(jsOneThird
, 1.0 / 3.0);
1221 assertEqualsAsNumber(jsEmptyString
, 0);
1222 assertEqualsAsNumber(jsOneString
, 1);
1223 assertEqualsAsNumber(jsCFString
, nan(""));
1224 assertEqualsAsNumber(jsCFStringWithCharacters
, nan(""));
1225 assertEqualsAsNumber(jsCFEmptyString
, 0);
1226 assertEqualsAsNumber(jsCFEmptyStringWithCharacters
, 0);
1227 ASSERT(sizeof(JSChar
) == sizeof(UniChar
));
1229 assertEqualsAsCharactersPtr(jsUndefined
, "undefined");
1230 assertEqualsAsCharactersPtr(jsNull
, "null");
1231 assertEqualsAsCharactersPtr(jsTrue
, "true");
1232 assertEqualsAsCharactersPtr(jsFalse
, "false");
1233 assertEqualsAsCharactersPtr(jsZero
, "0");
1234 assertEqualsAsCharactersPtr(jsOne
, "1");
1235 assertEqualsAsCharactersPtr(jsOneThird
, "0.3333333333333333");
1236 assertEqualsAsCharactersPtr(jsEmptyString
, "");
1237 assertEqualsAsCharactersPtr(jsOneString
, "1");
1238 assertEqualsAsCharactersPtr(jsCFString
, "A");
1239 assertEqualsAsCharactersPtr(jsCFStringWithCharacters
, "A");
1240 assertEqualsAsCharactersPtr(jsCFEmptyString
, "");
1241 assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters
, "");
1243 assertEqualsAsUTF8String(jsUndefined
, "undefined");
1244 assertEqualsAsUTF8String(jsNull
, "null");
1245 assertEqualsAsUTF8String(jsTrue
, "true");
1246 assertEqualsAsUTF8String(jsFalse
, "false");
1247 assertEqualsAsUTF8String(jsZero
, "0");
1248 assertEqualsAsUTF8String(jsOne
, "1");
1249 assertEqualsAsUTF8String(jsOneThird
, "0.3333333333333333");
1250 assertEqualsAsUTF8String(jsEmptyString
, "");
1251 assertEqualsAsUTF8String(jsOneString
, "1");
1252 assertEqualsAsUTF8String(jsCFString
, "A");
1253 assertEqualsAsUTF8String(jsCFStringWithCharacters
, "A");
1254 assertEqualsAsUTF8String(jsCFEmptyString
, "");
1255 assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters
, "");
1257 ASSERT(JSValueIsStrictEqual(context
, jsTrue
, jsTrue
));
1258 ASSERT(!JSValueIsStrictEqual(context
, jsOne
, jsOneString
));
1260 ASSERT(JSValueIsEqual(context
, jsOne
, jsOneString
, NULL
));
1261 ASSERT(!JSValueIsEqual(context
, jsTrue
, jsFalse
, NULL
));
1263 CFStringRef cfJSString
= JSStringCopyCFString(kCFAllocatorDefault
, jsCFIString
);
1264 CFStringRef cfJSEmptyString
= JSStringCopyCFString(kCFAllocatorDefault
, jsCFEmptyIString
);
1265 ASSERT(CFEqual(cfJSString
, cfString
));
1266 ASSERT(CFEqual(cfJSEmptyString
, cfEmptyString
));
1267 CFRelease(cfJSString
);
1268 CFRelease(cfJSEmptyString
);
1270 CFRelease(cfString
);
1271 CFRelease(cfEmptyString
);
1273 jsGlobalValue
= JSObjectMake(context
, NULL
, NULL
);
1274 makeGlobalNumberValue(context
);
1275 JSValueProtect(context
, jsGlobalValue
);
1276 JSGarbageCollect(context
);
1277 ASSERT(JSValueIsObject(context
, jsGlobalValue
));
1278 JSValueUnprotect(context
, jsGlobalValue
);
1279 JSValueUnprotect(context
, jsNumberValue
);
1281 JSStringRef goodSyntax
= JSStringCreateWithUTF8CString("x = 1;");
1282 JSStringRef badSyntax
= JSStringCreateWithUTF8CString("x := 1;");
1283 ASSERT(JSCheckScriptSyntax(context
, goodSyntax
, NULL
, 0, NULL
));
1284 ASSERT(!JSCheckScriptSyntax(context
, badSyntax
, NULL
, 0, NULL
));
1291 result
= JSEvaluateScript(context
, goodSyntax
, NULL
, NULL
, 1, NULL
);
1293 ASSERT(JSValueIsEqual(context
, result
, jsOne
, NULL
));
1296 result
= JSEvaluateScript(context
, badSyntax
, NULL
, NULL
, 1, &exception
);
1298 ASSERT(JSValueIsObject(context
, exception
));
1300 JSStringRef array
= JSStringCreateWithUTF8CString("Array");
1301 JSObjectRef arrayConstructor
= JSValueToObject(context
, JSObjectGetProperty(context
, globalObject
, array
, NULL
), NULL
);
1302 JSStringRelease(array
);
1303 result
= JSObjectCallAsConstructor(context
, arrayConstructor
, 0, NULL
, NULL
);
1305 ASSERT(JSValueIsObject(context
, result
));
1306 ASSERT(JSValueIsInstanceOfConstructor(context
, result
, arrayConstructor
, NULL
));
1307 ASSERT(!JSValueIsInstanceOfConstructor(context
, JSValueMakeNull(context
), arrayConstructor
, NULL
));
1309 o
= JSValueToObject(context
, result
, NULL
);
1311 ASSERT(JSValueIsUndefined(context
, JSObjectGetPropertyAtIndex(context
, o
, 0, &exception
)));
1314 JSObjectSetPropertyAtIndex(context
, o
, 0, JSValueMakeNumber(context
, 1), &exception
);
1318 ASSERT(1 == JSValueToNumber(context
, JSObjectGetPropertyAtIndex(context
, o
, 0, &exception
), &exception
));
1321 JSStringRef functionBody
;
1322 JSObjectRef function
;
1325 functionBody
= JSStringCreateWithUTF8CString("rreturn Array;");
1326 JSStringRef line
= JSStringCreateWithUTF8CString("line");
1327 ASSERT(!JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, &exception
));
1328 ASSERT(JSValueIsObject(context
, exception
));
1329 v
= JSObjectGetProperty(context
, JSValueToObject(context
, exception
, NULL
), line
, NULL
);
1330 assertEqualsAsNumber(v
, 1);
1331 JSStringRelease(functionBody
);
1332 JSStringRelease(line
);
1335 functionBody
= JSStringCreateWithUTF8CString("return Array;");
1336 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, &exception
);
1337 JSStringRelease(functionBody
);
1339 ASSERT(JSObjectIsFunction(context
, function
));
1340 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, NULL
);
1342 ASSERT(JSValueIsEqual(context
, v
, arrayConstructor
, NULL
));
1345 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, jsEmptyIString
, NULL
, 0, &exception
);
1347 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, &exception
);
1348 ASSERT(v
&& !exception
);
1349 ASSERT(JSValueIsUndefined(context
, v
));
1353 JSStringRef foo
= JSStringCreateWithUTF8CString("foo");
1354 JSStringRef argumentNames
[] = { foo
};
1355 functionBody
= JSStringCreateWithUTF8CString("return foo;");
1356 function
= JSObjectMakeFunction(context
, foo
, 1, argumentNames
, functionBody
, NULL
, 1, &exception
);
1357 ASSERT(function
&& !exception
);
1358 JSValueRef arguments
[] = { JSValueMakeNumber(context
, 2) };
1359 v
= JSObjectCallAsFunction(context
, function
, NULL
, 1, arguments
, &exception
);
1360 JSStringRelease(foo
);
1361 JSStringRelease(functionBody
);
1363 string
= JSValueToStringCopy(context
, function
, NULL
);
1364 assertEqualsAsUTF8String(JSValueMakeString(context
, string
), "function foo(foo) { return foo;\n}");
1365 JSStringRelease(string
);
1367 JSStringRef print
= JSStringCreateWithUTF8CString("print");
1368 JSObjectRef printFunction
= JSObjectMakeFunctionWithCallback(context
, print
, print_callAsFunction
);
1369 JSObjectSetProperty(context
, globalObject
, print
, printFunction
, kJSPropertyAttributeNone
, NULL
);
1370 JSStringRelease(print
);
1372 ASSERT(!JSObjectSetPrivate(printFunction
, (void*)1));
1373 ASSERT(!JSObjectGetPrivate(printFunction
));
1375 JSStringRef myConstructorIString
= JSStringCreateWithUTF8CString("MyConstructor");
1376 JSObjectRef myConstructor
= JSObjectMakeConstructor(context
, NULL
, myConstructor_callAsConstructor
);
1377 JSObjectSetProperty(context
, globalObject
, myConstructorIString
, myConstructor
, kJSPropertyAttributeNone
, NULL
);
1378 JSStringRelease(myConstructorIString
);
1380 ASSERT(!JSObjectSetPrivate(myConstructor
, (void*)1));
1381 ASSERT(!JSObjectGetPrivate(myConstructor
));
1383 string
= JSStringCreateWithUTF8CString("Base");
1384 JSObjectRef baseConstructor
= JSObjectMakeConstructor(context
, Base_class(context
), NULL
);
1385 JSObjectSetProperty(context
, globalObject
, string
, baseConstructor
, kJSPropertyAttributeNone
, NULL
);
1386 JSStringRelease(string
);
1388 string
= JSStringCreateWithUTF8CString("Derived");
1389 JSObjectRef derivedConstructor
= JSObjectMakeConstructor(context
, Derived_class(context
), NULL
);
1390 JSObjectSetProperty(context
, globalObject
, string
, derivedConstructor
, kJSPropertyAttributeNone
, NULL
);
1391 JSStringRelease(string
);
1393 string
= JSStringCreateWithUTF8CString("Derived2");
1394 JSObjectRef derived2Constructor
= JSObjectMakeConstructor(context
, Derived2_class(context
), NULL
);
1395 JSObjectSetProperty(context
, globalObject
, string
, derived2Constructor
, kJSPropertyAttributeNone
, NULL
);
1396 JSStringRelease(string
);
1398 o
= JSObjectMake(context
, NULL
, NULL
);
1399 JSObjectSetProperty(context
, o
, jsOneIString
, JSValueMakeNumber(context
, 1), kJSPropertyAttributeNone
, NULL
);
1400 JSObjectSetProperty(context
, o
, jsCFIString
, JSValueMakeNumber(context
, 1), kJSPropertyAttributeDontEnum
, NULL
);
1401 JSPropertyNameArrayRef nameArray
= JSObjectCopyPropertyNames(context
, o
);
1402 size_t expectedCount
= JSPropertyNameArrayGetCount(nameArray
);
1404 for (count
= 0; count
< expectedCount
; ++count
)
1405 JSPropertyNameArrayGetNameAtIndex(nameArray
, count
);
1406 JSPropertyNameArrayRelease(nameArray
);
1407 ASSERT(count
== 1); // jsCFString should not be enumerated
1409 JSValueRef argumentsArrayValues
[] = { JSValueMakeNumber(context
, 10), JSValueMakeNumber(context
, 20) };
1410 o
= JSObjectMakeArray(context
, sizeof(argumentsArrayValues
) / sizeof(JSValueRef
), argumentsArrayValues
, NULL
);
1411 string
= JSStringCreateWithUTF8CString("length");
1412 v
= JSObjectGetProperty(context
, o
, string
, NULL
);
1413 assertEqualsAsNumber(v
, 2);
1414 v
= JSObjectGetPropertyAtIndex(context
, o
, 0, NULL
);
1415 assertEqualsAsNumber(v
, 10);
1416 v
= JSObjectGetPropertyAtIndex(context
, o
, 1, NULL
);
1417 assertEqualsAsNumber(v
, 20);
1419 o
= JSObjectMakeArray(context
, 0, NULL
, NULL
);
1420 v
= JSObjectGetProperty(context
, o
, string
, NULL
);
1421 assertEqualsAsNumber(v
, 0);
1422 JSStringRelease(string
);
1424 JSValueRef argumentsDateValues
[] = { JSValueMakeNumber(context
, 0) };
1425 o
= JSObjectMakeDate(context
, 1, argumentsDateValues
, NULL
);
1426 if (timeZoneIsPST())
1427 assertEqualsAsUTF8String(o
, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)");
1429 string
= JSStringCreateWithUTF8CString("an error message");
1430 JSValueRef argumentsErrorValues
[] = { JSValueMakeString(context
, string
) };
1431 o
= JSObjectMakeError(context
, 1, argumentsErrorValues
, NULL
);
1432 assertEqualsAsUTF8String(o
, "Error: an error message");
1433 JSStringRelease(string
);
1435 string
= JSStringCreateWithUTF8CString("foo");
1436 JSStringRef string2
= JSStringCreateWithUTF8CString("gi");
1437 JSValueRef argumentsRegExpValues
[] = { JSValueMakeString(context
, string
), JSValueMakeString(context
, string2
) };
1438 o
= JSObjectMakeRegExp(context
, 2, argumentsRegExpValues
, NULL
);
1439 assertEqualsAsUTF8String(o
, "/foo/gi");
1440 JSStringRelease(string
);
1441 JSStringRelease(string2
);
1443 JSClassDefinition nullDefinition
= kJSClassDefinitionEmpty
;
1444 nullDefinition
.attributes
= kJSClassAttributeNoAutomaticPrototype
;
1445 JSClassRef nullClass
= JSClassCreate(&nullDefinition
);
1446 JSClassRelease(nullClass
);
1448 nullDefinition
= kJSClassDefinitionEmpty
;
1449 nullClass
= JSClassCreate(&nullDefinition
);
1450 JSClassRelease(nullClass
);
1452 functionBody
= JSStringCreateWithUTF8CString("return this;");
1453 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, NULL
);
1454 JSStringRelease(functionBody
);
1455 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, NULL
);
1456 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
1457 v
= JSObjectCallAsFunction(context
, function
, o
, 0, NULL
, NULL
);
1458 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
1460 functionBody
= JSStringCreateWithUTF8CString("return eval(\"this\");");
1461 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, NULL
);
1462 JSStringRelease(functionBody
);
1463 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, NULL
);
1464 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
1465 v
= JSObjectCallAsFunction(context
, function
, o
, 0, NULL
, NULL
);
1466 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
1468 JSStringRef script
= JSStringCreateWithUTF8CString("this;");
1469 v
= JSEvaluateScript(context
, script
, NULL
, NULL
, 1, NULL
);
1470 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
1471 v
= JSEvaluateScript(context
, script
, o
, NULL
, 1, NULL
);
1472 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
1473 JSStringRelease(script
);
1475 script
= JSStringCreateWithUTF8CString("eval(this);");
1476 v
= JSEvaluateScript(context
, script
, NULL
, NULL
, 1, NULL
);
1477 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
1478 v
= JSEvaluateScript(context
, script
, o
, NULL
, 1, NULL
);
1479 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
1480 JSStringRelease(script
);
1482 // Verify that creating a constructor for a class with no static functions does not trigger
1483 // an assert inside putDirect or lead to a crash during GC. <https://bugs.webkit.org/show_bug.cgi?id=25785>
1484 nullDefinition
= kJSClassDefinitionEmpty
;
1485 nullClass
= JSClassCreate(&nullDefinition
);
1486 myConstructor
= JSObjectMakeConstructor(context
, nullClass
, 0);
1487 JSClassRelease(nullClass
);
1489 char* scriptUTF8
= createStringWithContentsOfFile(scriptPath
);
1491 printf("FAIL: Test script could not be loaded.\n");
1494 script
= JSStringCreateWithUTF8CString(scriptUTF8
);
1495 result
= JSEvaluateScript(context
, script
, NULL
, NULL
, 1, &exception
);
1496 if (result
&& JSValueIsUndefined(context
, result
))
1497 printf("PASS: Test script executed successfully.\n");
1499 printf("FAIL: Test script returned unexpected value:\n");
1500 JSStringRef exceptionIString
= JSValueToStringCopy(context
, exception
, NULL
);
1501 CFStringRef exceptionCF
= JSStringCopyCFString(kCFAllocatorDefault
, exceptionIString
);
1502 CFShow(exceptionCF
);
1503 CFRelease(exceptionCF
);
1504 JSStringRelease(exceptionIString
);
1507 JSStringRelease(script
);
1511 // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
1515 globalObject
= NULL
;
1516 myConstructor
= NULL
;
1518 JSStringRelease(jsEmptyIString
);
1519 JSStringRelease(jsOneIString
);
1520 JSStringRelease(jsCFIString
);
1521 JSStringRelease(jsCFEmptyIString
);
1522 JSStringRelease(jsCFIStringWithCharacters
);
1523 JSStringRelease(jsCFEmptyIStringWithCharacters
);
1524 JSStringRelease(goodSyntax
);
1525 JSStringRelease(badSyntax
);
1527 JSGlobalContextRelease(context
);
1528 JSClassRelease(globalObjectClass
);
1530 // Test for an infinite prototype chain that used to be created. This test
1531 // passes if the call to JSObjectHasProperty() does not hang.
1533 JSClassDefinition prototypeLoopClassDefinition
= kJSClassDefinitionEmpty
;
1534 prototypeLoopClassDefinition
.staticFunctions
= globalObject_staticFunctions
;
1535 JSClassRef prototypeLoopClass
= JSClassCreate(&prototypeLoopClassDefinition
);
1536 JSGlobalContextRef prototypeLoopContext
= JSGlobalContextCreateInGroup(NULL
, prototypeLoopClass
);
1538 JSStringRef nameProperty
= JSStringCreateWithUTF8CString("name");
1539 JSObjectHasProperty(prototypeLoopContext
, JSContextGetGlobalObject(prototypeLoopContext
), nameProperty
);
1541 JSGlobalContextRelease(prototypeLoopContext
);
1542 JSClassRelease(prototypeLoopClass
);
1544 printf("PASS: Infinite prototype chain does not occur.\n");
1546 if (checkForCycleInPrototypeChain())
1547 printf("PASS: A cycle in a prototype chain can't be created.\n");
1549 printf("FAIL: A cycle in a prototype chain can be created.\n");
1554 printf("FAIL: Some tests failed.\n");
1558 printf("PASS: Program exited normally.\n");
1562 static char* createStringWithContentsOfFile(const char* fileName
)
1566 size_t buffer_size
= 0;
1567 size_t buffer_capacity
= 1024;
1568 buffer
= (char*)malloc(buffer_capacity
);
1570 FILE* f
= fopen(fileName
, "r");
1572 fprintf(stderr
, "Could not open file: %s\n", fileName
);
1576 while (!feof(f
) && !ferror(f
)) {
1577 buffer_size
+= fread(buffer
+ buffer_size
, 1, buffer_capacity
- buffer_size
, f
);
1578 if (buffer_size
== buffer_capacity
) { // guarantees space for trailing '\0'
1579 buffer_capacity
*= 2;
1580 buffer
= (char*)realloc(buffer
, buffer_capacity
);
1584 ASSERT(buffer_size
< buffer_capacity
);
1587 buffer
[buffer_size
] = '\0';