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"
29 #include <wtf/Assertions.h>
30 #include <wtf/UnusedParam.h>
34 #include <wtf/MathExtras.h>
36 static double nan(const char*)
38 return std::numeric_limits
<double>::quiet_NaN();
43 static JSGlobalContextRef context
= 0;
45 static void assertEqualsAsBoolean(JSValueRef value
, bool expectedValue
)
47 if (JSValueToBoolean(context
, value
) != expectedValue
)
48 fprintf(stderr
, "assertEqualsAsBoolean failed: %p, %d\n", value
, expectedValue
);
51 static void assertEqualsAsNumber(JSValueRef value
, double expectedValue
)
53 double number
= JSValueToNumber(context
, value
, NULL
);
55 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
56 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
57 // After that's resolved, we can remove these casts
58 if (number
!= expectedValue
&& !(isnan((float)number
) && isnan((float)expectedValue
)))
59 fprintf(stderr
, "assertEqualsAsNumber failed: %p, %lf\n", value
, expectedValue
);
62 static void assertEqualsAsUTF8String(JSValueRef value
, const char* expectedValue
)
64 JSStringRef valueAsString
= JSValueToStringCopy(context
, value
, NULL
);
66 size_t jsSize
= JSStringGetMaximumUTF8CStringSize(valueAsString
);
67 char* jsBuffer
= (char*)malloc(jsSize
);
68 JSStringGetUTF8CString(valueAsString
, jsBuffer
, jsSize
);
71 for (i
= 0; jsBuffer
[i
]; i
++)
72 if (jsBuffer
[i
] != expectedValue
[i
])
73 fprintf(stderr
, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i
, jsBuffer
[i
], jsBuffer
[i
], expectedValue
[i
], expectedValue
[i
]);
75 if (jsSize
< strlen(jsBuffer
) + 1)
76 fprintf(stderr
, "assertEqualsAsUTF8String failed: jsSize was too small\n");
79 JSStringRelease(valueAsString
);
82 static void assertEqualsAsCharactersPtr(JSValueRef value
, const char* expectedValue
)
84 JSStringRef valueAsString
= JSValueToStringCopy(context
, value
, NULL
);
86 size_t jsLength
= JSStringGetLength(valueAsString
);
87 const JSChar
* jsBuffer
= JSStringGetCharactersPtr(valueAsString
);
89 CFStringRef expectedValueAsCFString
= CFStringCreateWithCString(kCFAllocatorDefault
,
91 kCFStringEncodingUTF8
);
92 CFIndex cfLength
= CFStringGetLength(expectedValueAsCFString
);
93 UniChar
* cfBuffer
= (UniChar
*)malloc(cfLength
* sizeof(UniChar
));
94 CFStringGetCharacters(expectedValueAsCFString
, CFRangeMake(0, cfLength
), cfBuffer
);
95 CFRelease(expectedValueAsCFString
);
97 if (memcmp(jsBuffer
, cfBuffer
, cfLength
* sizeof(UniChar
)) != 0)
98 fprintf(stderr
, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n");
100 if (jsLength
!= (size_t)cfLength
)
101 fprintf(stderr
, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength
, cfLength
);
104 JSStringRelease(valueAsString
);
107 static JSValueRef jsGlobalValue
; // non-stack value for testing JSValueProtect()
109 /* MyObject pseudo-class */
111 static bool MyObject_hasProperty(JSContextRef context
, JSObjectRef object
, JSStringRef propertyName
)
113 UNUSED_PARAM(context
);
114 UNUSED_PARAM(object
);
116 if (JSStringIsEqualToUTF8CString(propertyName
, "alwaysOne")
117 || JSStringIsEqualToUTF8CString(propertyName
, "cantFind")
118 || JSStringIsEqualToUTF8CString(propertyName
, "myPropertyName")
119 || JSStringIsEqualToUTF8CString(propertyName
, "hasPropertyLie")
120 || JSStringIsEqualToUTF8CString(propertyName
, "0")) {
127 static JSValueRef
MyObject_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
129 UNUSED_PARAM(context
);
130 UNUSED_PARAM(object
);
132 if (JSStringIsEqualToUTF8CString(propertyName
, "alwaysOne")) {
133 return JSValueMakeNumber(context
, 1);
136 if (JSStringIsEqualToUTF8CString(propertyName
, "myPropertyName")) {
137 return JSValueMakeNumber(context
, 1);
140 if (JSStringIsEqualToUTF8CString(propertyName
, "cantFind")) {
141 return JSValueMakeUndefined(context
);
144 if (JSStringIsEqualToUTF8CString(propertyName
, "0")) {
145 *exception
= JSValueMakeNumber(context
, 1);
146 return JSValueMakeNumber(context
, 1);
152 static bool MyObject_setProperty(JSContextRef context
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
154 UNUSED_PARAM(context
);
155 UNUSED_PARAM(object
);
157 UNUSED_PARAM(exception
);
159 if (JSStringIsEqualToUTF8CString(propertyName
, "cantSet"))
160 return true; // pretend we set the property in order to swallow it
165 static bool MyObject_deleteProperty(JSContextRef context
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
167 UNUSED_PARAM(context
);
168 UNUSED_PARAM(object
);
170 if (JSStringIsEqualToUTF8CString(propertyName
, "cantDelete"))
173 if (JSStringIsEqualToUTF8CString(propertyName
, "throwOnDelete")) {
174 *exception
= JSValueMakeNumber(context
, 2);
181 static void MyObject_getPropertyNames(JSContextRef context
, JSObjectRef object
, JSPropertyNameAccumulatorRef propertyNames
)
183 UNUSED_PARAM(context
);
184 UNUSED_PARAM(object
);
186 JSStringRef propertyName
;
188 propertyName
= JSStringCreateWithUTF8CString("alwaysOne");
189 JSPropertyNameAccumulatorAddName(propertyNames
, propertyName
);
190 JSStringRelease(propertyName
);
192 propertyName
= JSStringCreateWithUTF8CString("myPropertyName");
193 JSPropertyNameAccumulatorAddName(propertyNames
, propertyName
);
194 JSStringRelease(propertyName
);
197 static JSValueRef
MyObject_callAsFunction(JSContextRef context
, JSObjectRef object
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
199 UNUSED_PARAM(context
);
200 UNUSED_PARAM(object
);
201 UNUSED_PARAM(thisObject
);
202 UNUSED_PARAM(exception
);
204 if (argumentCount
> 0 && JSValueIsStrictEqual(context
, arguments
[0], JSValueMakeNumber(context
, 0)))
205 return JSValueMakeNumber(context
, 1);
207 return JSValueMakeUndefined(context
);
210 static JSObjectRef
MyObject_callAsConstructor(JSContextRef context
, JSObjectRef object
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
212 UNUSED_PARAM(context
);
213 UNUSED_PARAM(object
);
215 if (argumentCount
> 0 && JSValueIsStrictEqual(context
, arguments
[0], JSValueMakeNumber(context
, 0)))
216 return JSValueToObject(context
, JSValueMakeNumber(context
, 1), exception
);
218 return JSValueToObject(context
, JSValueMakeNumber(context
, 0), exception
);
221 static bool MyObject_hasInstance(JSContextRef context
, JSObjectRef constructor
, JSValueRef possibleValue
, JSValueRef
* exception
)
223 UNUSED_PARAM(context
);
224 UNUSED_PARAM(constructor
);
226 JSStringRef numberString
= JSStringCreateWithUTF8CString("Number");
227 JSObjectRef numberConstructor
= JSValueToObject(context
, JSObjectGetProperty(context
, JSContextGetGlobalObject(context
), numberString
, exception
), exception
);
228 JSStringRelease(numberString
);
230 return JSValueIsInstanceOfConstructor(context
, possibleValue
, numberConstructor
, exception
);
233 static JSValueRef
MyObject_convertToType(JSContextRef context
, JSObjectRef object
, JSType type
, JSValueRef
* exception
)
235 UNUSED_PARAM(object
);
236 UNUSED_PARAM(exception
);
240 return JSValueMakeNumber(context
, 1);
243 JSStringRef string
= JSStringCreateWithUTF8CString("MyObjectAsString");
244 JSValueRef result
= JSValueMakeString(context
, string
);
245 JSStringRelease(string
);
252 // string conversion -- forward to default object class
256 static JSStaticValue evilStaticValues
[] = {
257 { "nullGetSet", 0, 0, kJSPropertyAttributeNone
},
261 static JSStaticFunction evilStaticFunctions
[] = {
262 { "nullCall", 0, kJSPropertyAttributeNone
},
266 JSClassDefinition MyObject_definition
= {
268 kJSClassAttributeNone
,
278 MyObject_hasProperty
,
279 MyObject_getProperty
,
280 MyObject_setProperty
,
281 MyObject_deleteProperty
,
282 MyObject_getPropertyNames
,
283 MyObject_callAsFunction
,
284 MyObject_callAsConstructor
,
285 MyObject_hasInstance
,
286 MyObject_convertToType
,
289 static JSClassRef
MyObject_class(JSContextRef context
)
291 UNUSED_PARAM(context
);
293 static JSClassRef jsClass
;
295 jsClass
= JSClassCreate(&MyObject_definition
);
300 static JSValueRef
Base_get(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
302 UNUSED_PARAM(object
);
303 UNUSED_PARAM(propertyName
);
304 UNUSED_PARAM(exception
);
306 return JSValueMakeNumber(ctx
, 1); // distinguish base get form derived get
309 static bool Base_set(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
311 UNUSED_PARAM(object
);
312 UNUSED_PARAM(propertyName
);
315 *exception
= JSValueMakeNumber(ctx
, 1); // distinguish base set from derived set
319 static JSValueRef
Base_callAsFunction(JSContextRef ctx
, JSObjectRef function
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
321 UNUSED_PARAM(function
);
322 UNUSED_PARAM(thisObject
);
323 UNUSED_PARAM(argumentCount
);
324 UNUSED_PARAM(arguments
);
325 UNUSED_PARAM(exception
);
327 return JSValueMakeNumber(ctx
, 1); // distinguish base call from derived call
330 static JSStaticFunction Base_staticFunctions
[] = {
331 { "baseProtoDup", NULL
, kJSPropertyAttributeNone
},
332 { "baseProto", Base_callAsFunction
, kJSPropertyAttributeNone
},
336 static JSStaticValue Base_staticValues
[] = {
337 { "baseDup", Base_get
, Base_set
, kJSPropertyAttributeNone
},
338 { "baseOnly", Base_get
, Base_set
, kJSPropertyAttributeNone
},
342 static bool TestInitializeFinalize
;
343 static void Base_initialize(JSContextRef context
, JSObjectRef object
)
345 UNUSED_PARAM(context
);
347 if (TestInitializeFinalize
) {
348 ASSERT((void*)1 == JSObjectGetPrivate(object
));
349 JSObjectSetPrivate(object
, (void*)2);
353 static unsigned Base_didFinalize
;
354 static void Base_finalize(JSObjectRef object
)
356 UNUSED_PARAM(object
);
357 if (TestInitializeFinalize
) {
358 ASSERT((void*)4 == JSObjectGetPrivate(object
));
359 Base_didFinalize
= true;
363 static JSClassRef
Base_class(JSContextRef context
)
365 UNUSED_PARAM(context
);
367 static JSClassRef jsClass
;
369 JSClassDefinition definition
= kJSClassDefinitionEmpty
;
370 definition
.staticValues
= Base_staticValues
;
371 definition
.staticFunctions
= Base_staticFunctions
;
372 definition
.initialize
= Base_initialize
;
373 definition
.finalize
= Base_finalize
;
374 jsClass
= JSClassCreate(&definition
);
379 static JSValueRef
Derived_get(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
381 UNUSED_PARAM(object
);
382 UNUSED_PARAM(propertyName
);
383 UNUSED_PARAM(exception
);
385 return JSValueMakeNumber(ctx
, 2); // distinguish base get form derived get
388 static bool Derived_set(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
391 UNUSED_PARAM(object
);
392 UNUSED_PARAM(propertyName
);
395 *exception
= JSValueMakeNumber(ctx
, 2); // distinguish base set from derived set
399 static JSValueRef
Derived_callAsFunction(JSContextRef ctx
, JSObjectRef function
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
401 UNUSED_PARAM(function
);
402 UNUSED_PARAM(thisObject
);
403 UNUSED_PARAM(argumentCount
);
404 UNUSED_PARAM(arguments
);
405 UNUSED_PARAM(exception
);
407 return JSValueMakeNumber(ctx
, 2); // distinguish base call from derived call
410 static JSStaticFunction Derived_staticFunctions
[] = {
411 { "protoOnly", Derived_callAsFunction
, kJSPropertyAttributeNone
},
412 { "protoDup", NULL
, kJSPropertyAttributeNone
},
413 { "baseProtoDup", Derived_callAsFunction
, kJSPropertyAttributeNone
},
417 static JSStaticValue Derived_staticValues
[] = {
418 { "derivedOnly", Derived_get
, Derived_set
, kJSPropertyAttributeNone
},
419 { "protoDup", Derived_get
, Derived_set
, kJSPropertyAttributeNone
},
420 { "baseDup", Derived_get
, Derived_set
, kJSPropertyAttributeNone
},
424 static void Derived_initialize(JSContextRef context
, JSObjectRef object
)
426 UNUSED_PARAM(context
);
428 if (TestInitializeFinalize
) {
429 ASSERT((void*)2 == JSObjectGetPrivate(object
));
430 JSObjectSetPrivate(object
, (void*)3);
434 static void Derived_finalize(JSObjectRef object
)
436 if (TestInitializeFinalize
) {
437 ASSERT((void*)3 == JSObjectGetPrivate(object
));
438 JSObjectSetPrivate(object
, (void*)4);
442 static JSClassRef
Derived_class(JSContextRef context
)
444 static JSClassRef jsClass
;
446 JSClassDefinition definition
= kJSClassDefinitionEmpty
;
447 definition
.parentClass
= Base_class(context
);
448 definition
.staticValues
= Derived_staticValues
;
449 definition
.staticFunctions
= Derived_staticFunctions
;
450 definition
.initialize
= Derived_initialize
;
451 definition
.finalize
= Derived_finalize
;
452 jsClass
= JSClassCreate(&definition
);
457 static JSValueRef
print_callAsFunction(JSContextRef context
, JSObjectRef functionObject
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
459 UNUSED_PARAM(functionObject
);
460 UNUSED_PARAM(thisObject
);
461 UNUSED_PARAM(exception
);
463 if (argumentCount
> 0) {
464 JSStringRef string
= JSValueToStringCopy(context
, arguments
[0], NULL
);
465 size_t sizeUTF8
= JSStringGetMaximumUTF8CStringSize(string
);
466 char* stringUTF8
= (char*)malloc(sizeUTF8
);
467 JSStringGetUTF8CString(string
, stringUTF8
, sizeUTF8
);
468 printf("%s\n", stringUTF8
);
470 JSStringRelease(string
);
473 return JSValueMakeUndefined(context
);
476 static JSObjectRef
myConstructor_callAsConstructor(JSContextRef context
, JSObjectRef constructorObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
478 UNUSED_PARAM(constructorObject
);
479 UNUSED_PARAM(exception
);
481 JSObjectRef result
= JSObjectMake(context
, NULL
, NULL
);
482 if (argumentCount
> 0) {
483 JSStringRef value
= JSStringCreateWithUTF8CString("value");
484 JSObjectSetProperty(context
, result
, value
, arguments
[0], kJSPropertyAttributeNone
, NULL
);
485 JSStringRelease(value
);
492 static void globalObject_initialize(JSContextRef context
, JSObjectRef object
)
494 UNUSED_PARAM(object
);
495 // Ensure that an execution context is passed in
498 // Ensure that the global object is set to the object that we were passed
499 JSObjectRef globalObject
= JSContextGetGlobalObject(context
);
500 ASSERT(globalObject
);
501 ASSERT(object
== globalObject
);
503 // Ensure that the standard global properties have been set on the global object
504 JSStringRef array
= JSStringCreateWithUTF8CString("Array");
505 JSObjectRef arrayConstructor
= JSValueToObject(context
, JSObjectGetProperty(context
, globalObject
, array
, NULL
), NULL
);
506 JSStringRelease(array
);
508 UNUSED_PARAM(arrayConstructor
);
509 ASSERT(arrayConstructor
);
512 static JSValueRef
globalObject_get(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
514 UNUSED_PARAM(object
);
515 UNUSED_PARAM(propertyName
);
516 UNUSED_PARAM(exception
);
518 return JSValueMakeNumber(ctx
, 3);
521 static bool globalObject_set(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
523 UNUSED_PARAM(object
);
524 UNUSED_PARAM(propertyName
);
527 *exception
= JSValueMakeNumber(ctx
, 3);
531 static JSValueRef
globalObject_call(JSContextRef ctx
, JSObjectRef function
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
533 UNUSED_PARAM(function
);
534 UNUSED_PARAM(thisObject
);
535 UNUSED_PARAM(argumentCount
);
536 UNUSED_PARAM(arguments
);
537 UNUSED_PARAM(exception
);
539 return JSValueMakeNumber(ctx
, 3);
542 static JSStaticValue globalObject_staticValues
[] = {
543 { "globalStaticValue", globalObject_get
, globalObject_set
, kJSPropertyAttributeNone
},
547 static JSStaticFunction globalObject_staticFunctions
[] = {
548 { "globalStaticFunction", globalObject_call
, kJSPropertyAttributeNone
},
552 static char* createStringWithContentsOfFile(const char* fileName
);
554 static void testInitializeFinalize()
556 JSObjectRef o
= JSObjectMake(context
, Derived_class(context
), (void*)1);
558 ASSERT(JSObjectGetPrivate(o
) == (void*)3);
561 int main(int argc
, char* argv
[])
563 const char *scriptPath
= "testapi.js";
565 scriptPath
= argv
[1];
568 // Test garbage collection with a fresh context
569 context
= JSGlobalContextCreateInGroup(NULL
, NULL
);
570 TestInitializeFinalize
= true;
571 testInitializeFinalize();
572 JSGlobalContextRelease(context
);
573 TestInitializeFinalize
= false;
575 ASSERT(Base_didFinalize
);
577 JSClassDefinition globalObjectClassDefinition
= kJSClassDefinitionEmpty
;
578 globalObjectClassDefinition
.initialize
= globalObject_initialize
;
579 globalObjectClassDefinition
.staticValues
= globalObject_staticValues
;
580 globalObjectClassDefinition
.staticFunctions
= globalObject_staticFunctions
;
581 globalObjectClassDefinition
.attributes
= kJSClassAttributeNoAutomaticPrototype
;
582 JSClassRef globalObjectClass
= JSClassCreate(&globalObjectClassDefinition
);
583 context
= JSGlobalContextCreateInGroup(NULL
, globalObjectClass
);
585 JSGlobalContextRetain(context
);
586 JSGlobalContextRelease(context
);
588 JSReportExtraMemoryCost(context
, 0);
589 JSReportExtraMemoryCost(context
, 1);
590 JSReportExtraMemoryCost(context
, 1024);
592 JSObjectRef globalObject
= JSContextGetGlobalObject(context
);
593 ASSERT(JSValueIsObject(context
, globalObject
));
595 JSValueRef jsUndefined
= JSValueMakeUndefined(context
);
596 JSValueRef jsNull
= JSValueMakeNull(context
);
597 JSValueRef jsTrue
= JSValueMakeBoolean(context
, true);
598 JSValueRef jsFalse
= JSValueMakeBoolean(context
, false);
599 JSValueRef jsZero
= JSValueMakeNumber(context
, 0);
600 JSValueRef jsOne
= JSValueMakeNumber(context
, 1);
601 JSValueRef jsOneThird
= JSValueMakeNumber(context
, 1.0 / 3.0);
602 JSObjectRef jsObjectNoProto
= JSObjectMake(context
, NULL
, NULL
);
603 JSObjectSetPrototype(context
, jsObjectNoProto
, JSValueMakeNull(context
));
605 // FIXME: test funny utf8 characters
606 JSStringRef jsEmptyIString
= JSStringCreateWithUTF8CString("");
607 JSValueRef jsEmptyString
= JSValueMakeString(context
, jsEmptyIString
);
609 JSStringRef jsOneIString
= JSStringCreateWithUTF8CString("1");
610 JSValueRef jsOneString
= JSValueMakeString(context
, jsOneIString
);
612 UniChar singleUniChar
= 65; // Capital A
613 CFMutableStringRef cfString
=
614 CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault
,
620 JSStringRef jsCFIString
= JSStringCreateWithCFString(cfString
);
621 JSValueRef jsCFString
= JSValueMakeString(context
, jsCFIString
);
623 CFStringRef cfEmptyString
= CFStringCreateWithCString(kCFAllocatorDefault
, "", kCFStringEncodingUTF8
);
625 JSStringRef jsCFEmptyIString
= JSStringCreateWithCFString(cfEmptyString
);
626 JSValueRef jsCFEmptyString
= JSValueMakeString(context
, jsCFEmptyIString
);
628 CFIndex cfStringLength
= CFStringGetLength(cfString
);
629 UniChar
* buffer
= (UniChar
*)malloc(cfStringLength
* sizeof(UniChar
));
630 CFStringGetCharacters(cfString
,
631 CFRangeMake(0, cfStringLength
),
633 JSStringRef jsCFIStringWithCharacters
= JSStringCreateWithCharacters((JSChar
*)buffer
, cfStringLength
);
634 JSValueRef jsCFStringWithCharacters
= JSValueMakeString(context
, jsCFIStringWithCharacters
);
636 JSStringRef jsCFEmptyIStringWithCharacters
= JSStringCreateWithCharacters((JSChar
*)buffer
, CFStringGetLength(cfEmptyString
));
638 JSValueRef jsCFEmptyStringWithCharacters
= JSValueMakeString(context
, jsCFEmptyIStringWithCharacters
);
640 ASSERT(JSValueGetType(context
, jsUndefined
) == kJSTypeUndefined
);
641 ASSERT(JSValueGetType(context
, jsNull
) == kJSTypeNull
);
642 ASSERT(JSValueGetType(context
, jsTrue
) == kJSTypeBoolean
);
643 ASSERT(JSValueGetType(context
, jsFalse
) == kJSTypeBoolean
);
644 ASSERT(JSValueGetType(context
, jsZero
) == kJSTypeNumber
);
645 ASSERT(JSValueGetType(context
, jsOne
) == kJSTypeNumber
);
646 ASSERT(JSValueGetType(context
, jsOneThird
) == kJSTypeNumber
);
647 ASSERT(JSValueGetType(context
, jsEmptyString
) == kJSTypeString
);
648 ASSERT(JSValueGetType(context
, jsOneString
) == kJSTypeString
);
649 ASSERT(JSValueGetType(context
, jsCFString
) == kJSTypeString
);
650 ASSERT(JSValueGetType(context
, jsCFStringWithCharacters
) == kJSTypeString
);
651 ASSERT(JSValueGetType(context
, jsCFEmptyString
) == kJSTypeString
);
652 ASSERT(JSValueGetType(context
, jsCFEmptyStringWithCharacters
) == kJSTypeString
);
654 JSObjectRef myObject
= JSObjectMake(context
, MyObject_class(context
), NULL
);
655 JSStringRef myObjectIString
= JSStringCreateWithUTF8CString("MyObject");
656 JSObjectSetProperty(context
, globalObject
, myObjectIString
, myObject
, kJSPropertyAttributeNone
, NULL
);
657 JSStringRelease(myObjectIString
);
659 JSValueRef exception
;
661 // Conversions that throw exceptions
663 ASSERT(NULL
== JSValueToObject(context
, jsNull
, &exception
));
667 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
668 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
669 // After that's resolved, we can remove these casts
670 ASSERT(isnan((float)JSValueToNumber(context
, jsObjectNoProto
, &exception
)));
674 ASSERT(!JSValueToStringCopy(context
, jsObjectNoProto
, &exception
));
677 ASSERT(JSValueToBoolean(context
, myObject
));
680 ASSERT(!JSValueIsEqual(context
, jsObjectNoProto
, JSValueMakeNumber(context
, 1), &exception
));
684 JSObjectGetPropertyAtIndex(context
, myObject
, 0, &exception
);
685 ASSERT(1 == JSValueToNumber(context
, exception
, NULL
));
687 assertEqualsAsBoolean(jsUndefined
, false);
688 assertEqualsAsBoolean(jsNull
, false);
689 assertEqualsAsBoolean(jsTrue
, true);
690 assertEqualsAsBoolean(jsFalse
, false);
691 assertEqualsAsBoolean(jsZero
, false);
692 assertEqualsAsBoolean(jsOne
, true);
693 assertEqualsAsBoolean(jsOneThird
, true);
694 assertEqualsAsBoolean(jsEmptyString
, false);
695 assertEqualsAsBoolean(jsOneString
, true);
696 assertEqualsAsBoolean(jsCFString
, true);
697 assertEqualsAsBoolean(jsCFStringWithCharacters
, true);
698 assertEqualsAsBoolean(jsCFEmptyString
, false);
699 assertEqualsAsBoolean(jsCFEmptyStringWithCharacters
, false);
701 assertEqualsAsNumber(jsUndefined
, nan(""));
702 assertEqualsAsNumber(jsNull
, 0);
703 assertEqualsAsNumber(jsTrue
, 1);
704 assertEqualsAsNumber(jsFalse
, 0);
705 assertEqualsAsNumber(jsZero
, 0);
706 assertEqualsAsNumber(jsOne
, 1);
707 assertEqualsAsNumber(jsOneThird
, 1.0 / 3.0);
708 assertEqualsAsNumber(jsEmptyString
, 0);
709 assertEqualsAsNumber(jsOneString
, 1);
710 assertEqualsAsNumber(jsCFString
, nan(""));
711 assertEqualsAsNumber(jsCFStringWithCharacters
, nan(""));
712 assertEqualsAsNumber(jsCFEmptyString
, 0);
713 assertEqualsAsNumber(jsCFEmptyStringWithCharacters
, 0);
714 ASSERT(sizeof(JSChar
) == sizeof(UniChar
));
716 assertEqualsAsCharactersPtr(jsUndefined
, "undefined");
717 assertEqualsAsCharactersPtr(jsNull
, "null");
718 assertEqualsAsCharactersPtr(jsTrue
, "true");
719 assertEqualsAsCharactersPtr(jsFalse
, "false");
720 assertEqualsAsCharactersPtr(jsZero
, "0");
721 assertEqualsAsCharactersPtr(jsOne
, "1");
722 assertEqualsAsCharactersPtr(jsOneThird
, "0.3333333333333333");
723 assertEqualsAsCharactersPtr(jsEmptyString
, "");
724 assertEqualsAsCharactersPtr(jsOneString
, "1");
725 assertEqualsAsCharactersPtr(jsCFString
, "A");
726 assertEqualsAsCharactersPtr(jsCFStringWithCharacters
, "A");
727 assertEqualsAsCharactersPtr(jsCFEmptyString
, "");
728 assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters
, "");
730 assertEqualsAsUTF8String(jsUndefined
, "undefined");
731 assertEqualsAsUTF8String(jsNull
, "null");
732 assertEqualsAsUTF8String(jsTrue
, "true");
733 assertEqualsAsUTF8String(jsFalse
, "false");
734 assertEqualsAsUTF8String(jsZero
, "0");
735 assertEqualsAsUTF8String(jsOne
, "1");
736 assertEqualsAsUTF8String(jsOneThird
, "0.3333333333333333");
737 assertEqualsAsUTF8String(jsEmptyString
, "");
738 assertEqualsAsUTF8String(jsOneString
, "1");
739 assertEqualsAsUTF8String(jsCFString
, "A");
740 assertEqualsAsUTF8String(jsCFStringWithCharacters
, "A");
741 assertEqualsAsUTF8String(jsCFEmptyString
, "");
742 assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters
, "");
744 ASSERT(JSValueIsStrictEqual(context
, jsTrue
, jsTrue
));
745 ASSERT(!JSValueIsStrictEqual(context
, jsOne
, jsOneString
));
747 ASSERT(JSValueIsEqual(context
, jsOne
, jsOneString
, NULL
));
748 ASSERT(!JSValueIsEqual(context
, jsTrue
, jsFalse
, NULL
));
750 CFStringRef cfJSString
= JSStringCopyCFString(kCFAllocatorDefault
, jsCFIString
);
751 CFStringRef cfJSEmptyString
= JSStringCopyCFString(kCFAllocatorDefault
, jsCFEmptyIString
);
752 ASSERT(CFEqual(cfJSString
, cfString
));
753 ASSERT(CFEqual(cfJSEmptyString
, cfEmptyString
));
754 CFRelease(cfJSString
);
755 CFRelease(cfJSEmptyString
);
758 CFRelease(cfEmptyString
);
760 jsGlobalValue
= JSObjectMake(context
, NULL
, NULL
);
761 JSValueProtect(context
, jsGlobalValue
);
762 JSGarbageCollect(context
);
763 ASSERT(JSValueIsObject(context
, jsGlobalValue
));
764 JSValueUnprotect(context
, jsGlobalValue
);
766 JSStringRef goodSyntax
= JSStringCreateWithUTF8CString("x = 1;");
767 JSStringRef badSyntax
= JSStringCreateWithUTF8CString("x := 1;");
768 ASSERT(JSCheckScriptSyntax(context
, goodSyntax
, NULL
, 0, NULL
));
769 ASSERT(!JSCheckScriptSyntax(context
, badSyntax
, NULL
, 0, NULL
));
776 result
= JSEvaluateScript(context
, goodSyntax
, NULL
, NULL
, 1, NULL
);
778 ASSERT(JSValueIsEqual(context
, result
, jsOne
, NULL
));
781 result
= JSEvaluateScript(context
, badSyntax
, NULL
, NULL
, 1, &exception
);
783 ASSERT(JSValueIsObject(context
, exception
));
785 JSStringRef array
= JSStringCreateWithUTF8CString("Array");
786 JSObjectRef arrayConstructor
= JSValueToObject(context
, JSObjectGetProperty(context
, globalObject
, array
, NULL
), NULL
);
787 JSStringRelease(array
);
788 result
= JSObjectCallAsConstructor(context
, arrayConstructor
, 0, NULL
, NULL
);
790 ASSERT(JSValueIsObject(context
, result
));
791 ASSERT(JSValueIsInstanceOfConstructor(context
, result
, arrayConstructor
, NULL
));
792 ASSERT(!JSValueIsInstanceOfConstructor(context
, JSValueMakeNull(context
), arrayConstructor
, NULL
));
794 o
= JSValueToObject(context
, result
, NULL
);
796 ASSERT(JSValueIsUndefined(context
, JSObjectGetPropertyAtIndex(context
, o
, 0, &exception
)));
799 JSObjectSetPropertyAtIndex(context
, o
, 0, JSValueMakeNumber(context
, 1), &exception
);
803 ASSERT(1 == JSValueToNumber(context
, JSObjectGetPropertyAtIndex(context
, o
, 0, &exception
), &exception
));
806 JSStringRef functionBody
;
807 JSObjectRef function
;
810 functionBody
= JSStringCreateWithUTF8CString("rreturn Array;");
811 JSStringRef line
= JSStringCreateWithUTF8CString("line");
812 ASSERT(!JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, &exception
));
813 ASSERT(JSValueIsObject(context
, exception
));
814 v
= JSObjectGetProperty(context
, JSValueToObject(context
, exception
, NULL
), line
, NULL
);
815 assertEqualsAsNumber(v
, 1);
816 JSStringRelease(functionBody
);
817 JSStringRelease(line
);
820 functionBody
= JSStringCreateWithUTF8CString("return Array;");
821 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, &exception
);
822 JSStringRelease(functionBody
);
824 ASSERT(JSObjectIsFunction(context
, function
));
825 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, NULL
);
827 ASSERT(JSValueIsEqual(context
, v
, arrayConstructor
, NULL
));
830 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, jsEmptyIString
, NULL
, 0, &exception
);
832 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, &exception
);
833 ASSERT(v
&& !exception
);
834 ASSERT(JSValueIsUndefined(context
, v
));
838 JSStringRef foo
= JSStringCreateWithUTF8CString("foo");
839 JSStringRef argumentNames
[] = { foo
};
840 functionBody
= JSStringCreateWithUTF8CString("return foo;");
841 function
= JSObjectMakeFunction(context
, foo
, 1, argumentNames
, functionBody
, NULL
, 1, &exception
);
842 ASSERT(function
&& !exception
);
843 JSValueRef arguments
[] = { JSValueMakeNumber(context
, 2) };
844 v
= JSObjectCallAsFunction(context
, function
, NULL
, 1, arguments
, &exception
);
845 JSStringRelease(foo
);
846 JSStringRelease(functionBody
);
848 string
= JSValueToStringCopy(context
, function
, NULL
);
849 assertEqualsAsUTF8String(JSValueMakeString(context
, string
), "function foo(foo) {return foo;}");
850 JSStringRelease(string
);
852 JSStringRef print
= JSStringCreateWithUTF8CString("print");
853 JSObjectRef printFunction
= JSObjectMakeFunctionWithCallback(context
, print
, print_callAsFunction
);
854 JSObjectSetProperty(context
, globalObject
, print
, printFunction
, kJSPropertyAttributeNone
, NULL
);
855 JSStringRelease(print
);
857 ASSERT(!JSObjectSetPrivate(printFunction
, (void*)1));
858 ASSERT(!JSObjectGetPrivate(printFunction
));
860 JSStringRef myConstructorIString
= JSStringCreateWithUTF8CString("MyConstructor");
861 JSObjectRef myConstructor
= JSObjectMakeConstructor(context
, NULL
, myConstructor_callAsConstructor
);
862 JSObjectSetProperty(context
, globalObject
, myConstructorIString
, myConstructor
, kJSPropertyAttributeNone
, NULL
);
863 JSStringRelease(myConstructorIString
);
865 ASSERT(!JSObjectSetPrivate(myConstructor
, (void*)1));
866 ASSERT(!JSObjectGetPrivate(myConstructor
));
868 string
= JSStringCreateWithUTF8CString("Derived");
869 JSObjectRef derivedConstructor
= JSObjectMakeConstructor(context
, Derived_class(context
), NULL
);
870 JSObjectSetProperty(context
, globalObject
, string
, derivedConstructor
, kJSPropertyAttributeNone
, NULL
);
871 JSStringRelease(string
);
873 o
= JSObjectMake(context
, NULL
, NULL
);
874 JSObjectSetProperty(context
, o
, jsOneIString
, JSValueMakeNumber(context
, 1), kJSPropertyAttributeNone
, NULL
);
875 JSObjectSetProperty(context
, o
, jsCFIString
, JSValueMakeNumber(context
, 1), kJSPropertyAttributeDontEnum
, NULL
);
876 JSPropertyNameArrayRef nameArray
= JSObjectCopyPropertyNames(context
, o
);
877 size_t expectedCount
= JSPropertyNameArrayGetCount(nameArray
);
879 for (count
= 0; count
< expectedCount
; ++count
)
880 JSPropertyNameArrayGetNameAtIndex(nameArray
, count
);
881 JSPropertyNameArrayRelease(nameArray
);
882 ASSERT(count
== 1); // jsCFString should not be enumerated
884 JSValueRef argumentsArrayValues
[] = { JSValueMakeNumber(context
, 10), JSValueMakeNumber(context
, 20) };
885 o
= JSObjectMakeArray(context
, sizeof(argumentsArrayValues
) / sizeof(JSValueRef
), argumentsArrayValues
, NULL
);
886 string
= JSStringCreateWithUTF8CString("length");
887 v
= JSObjectGetProperty(context
, o
, string
, NULL
);
888 assertEqualsAsNumber(v
, 2);
889 v
= JSObjectGetPropertyAtIndex(context
, o
, 0, NULL
);
890 assertEqualsAsNumber(v
, 10);
891 v
= JSObjectGetPropertyAtIndex(context
, o
, 1, NULL
);
892 assertEqualsAsNumber(v
, 20);
894 o
= JSObjectMakeArray(context
, 0, NULL
, NULL
);
895 v
= JSObjectGetProperty(context
, o
, string
, NULL
);
896 assertEqualsAsNumber(v
, 0);
897 JSStringRelease(string
);
899 JSValueRef argumentsDateValues
[] = { JSValueMakeNumber(context
, 0) };
900 o
= JSObjectMakeDate(context
, 1, argumentsDateValues
, NULL
);
901 assertEqualsAsUTF8String(o
, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)");
903 string
= JSStringCreateWithUTF8CString("an error message");
904 JSValueRef argumentsErrorValues
[] = { JSValueMakeString(context
, string
) };
905 o
= JSObjectMakeError(context
, 1, argumentsErrorValues
, NULL
);
906 assertEqualsAsUTF8String(o
, "Error: an error message");
907 JSStringRelease(string
);
909 string
= JSStringCreateWithUTF8CString("foo");
910 JSStringRef string2
= JSStringCreateWithUTF8CString("gi");
911 JSValueRef argumentsRegExpValues
[] = { JSValueMakeString(context
, string
), JSValueMakeString(context
, string2
) };
912 o
= JSObjectMakeRegExp(context
, 2, argumentsRegExpValues
, NULL
);
913 assertEqualsAsUTF8String(o
, "/foo/gi");
914 JSStringRelease(string
);
915 JSStringRelease(string2
);
917 JSClassDefinition nullDefinition
= kJSClassDefinitionEmpty
;
918 nullDefinition
.attributes
= kJSClassAttributeNoAutomaticPrototype
;
919 JSClassRef nullClass
= JSClassCreate(&nullDefinition
);
920 JSClassRelease(nullClass
);
922 nullDefinition
= kJSClassDefinitionEmpty
;
923 nullClass
= JSClassCreate(&nullDefinition
);
924 JSClassRelease(nullClass
);
926 functionBody
= JSStringCreateWithUTF8CString("return this;");
927 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, NULL
);
928 JSStringRelease(functionBody
);
929 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, NULL
);
930 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
931 v
= JSObjectCallAsFunction(context
, function
, o
, 0, NULL
, NULL
);
932 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
934 functionBody
= JSStringCreateWithUTF8CString("return eval(\"this\");");
935 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, NULL
);
936 JSStringRelease(functionBody
);
937 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, NULL
);
938 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
939 v
= JSObjectCallAsFunction(context
, function
, o
, 0, NULL
, NULL
);
940 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
942 JSStringRef script
= JSStringCreateWithUTF8CString("this;");
943 v
= JSEvaluateScript(context
, script
, NULL
, NULL
, 1, NULL
);
944 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
945 v
= JSEvaluateScript(context
, script
, o
, NULL
, 1, NULL
);
946 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
947 JSStringRelease(script
);
949 script
= JSStringCreateWithUTF8CString("eval(this);");
950 v
= JSEvaluateScript(context
, script
, NULL
, NULL
, 1, NULL
);
951 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
952 v
= JSEvaluateScript(context
, script
, o
, NULL
, 1, NULL
);
953 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
954 JSStringRelease(script
);
956 char* scriptUTF8
= createStringWithContentsOfFile(scriptPath
);
958 printf("FAIL: Test script could not be loaded.\n");
960 script
= JSStringCreateWithUTF8CString(scriptUTF8
);
961 result
= JSEvaluateScript(context
, script
, NULL
, NULL
, 1, &exception
);
962 if (JSValueIsUndefined(context
, result
))
963 printf("PASS: Test script executed successfully.\n");
965 printf("FAIL: Test script returned unexpected value:\n");
966 JSStringRef exceptionIString
= JSValueToStringCopy(context
, exception
, NULL
);
967 CFStringRef exceptionCF
= JSStringCopyCFString(kCFAllocatorDefault
, exceptionIString
);
969 CFRelease(exceptionCF
);
970 JSStringRelease(exceptionIString
);
972 JSStringRelease(script
);
976 // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
982 JSStringRelease(jsEmptyIString
);
983 JSStringRelease(jsOneIString
);
984 JSStringRelease(jsCFIString
);
985 JSStringRelease(jsCFEmptyIString
);
986 JSStringRelease(jsCFIStringWithCharacters
);
987 JSStringRelease(jsCFEmptyIStringWithCharacters
);
988 JSStringRelease(goodSyntax
);
989 JSStringRelease(badSyntax
);
991 JSGlobalContextRelease(context
);
992 JSClassRelease(globalObjectClass
);
994 printf("PASS: Program exited normally.\n");
998 static char* createStringWithContentsOfFile(const char* fileName
)
1002 size_t buffer_size
= 0;
1003 size_t buffer_capacity
= 1024;
1004 buffer
= (char*)malloc(buffer_capacity
);
1006 FILE* f
= fopen(fileName
, "r");
1008 fprintf(stderr
, "Could not open file: %s\n", fileName
);
1012 while (!feof(f
) && !ferror(f
)) {
1013 buffer_size
+= fread(buffer
+ buffer_size
, 1, buffer_capacity
- buffer_size
, f
);
1014 if (buffer_size
== buffer_capacity
) { // guarantees space for trailing '\0'
1015 buffer_capacity
*= 2;
1016 buffer
= (char*)realloc(buffer
, buffer_capacity
);
1020 ASSERT(buffer_size
< buffer_capacity
);
1023 buffer
[buffer_size
] = '\0';