1 // -*- mode: c++; c-basic-offset: 4 -*-
3 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "JavaScriptCore.h"
29 #include <wtf/Assertions.h>
30 #include <wtf/UnusedParam.h>
32 static JSGlobalContextRef context
= 0;
34 static void assertEqualsAsBoolean(JSValueRef value
, bool expectedValue
)
36 if (JSValueToBoolean(context
, value
) != expectedValue
)
37 fprintf(stderr
, "assertEqualsAsBoolean failed: %p, %d\n", value
, expectedValue
);
40 static void assertEqualsAsNumber(JSValueRef value
, double expectedValue
)
42 double number
= JSValueToNumber(context
, value
, NULL
);
44 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
45 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
46 // After that's resolved, we can remove these casts
47 if (number
!= expectedValue
&& !(isnan((float)number
) && isnan((float)expectedValue
)))
48 fprintf(stderr
, "assertEqualsAsNumber failed: %p, %lf\n", value
, expectedValue
);
51 static void assertEqualsAsUTF8String(JSValueRef value
, const char* expectedValue
)
53 JSStringRef valueAsString
= JSValueToStringCopy(context
, value
, NULL
);
55 size_t jsSize
= JSStringGetMaximumUTF8CStringSize(valueAsString
);
56 char jsBuffer
[jsSize
];
57 JSStringGetUTF8CString(valueAsString
, jsBuffer
, jsSize
);
60 for (i
= 0; jsBuffer
[i
]; i
++)
61 if (jsBuffer
[i
] != expectedValue
[i
])
62 fprintf(stderr
, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i
, jsBuffer
[i
], jsBuffer
[i
], expectedValue
[i
], expectedValue
[i
]);
64 if (jsSize
< strlen(jsBuffer
) + 1)
65 fprintf(stderr
, "assertEqualsAsUTF8String failed: jsSize was too small\n");
67 JSStringRelease(valueAsString
);
70 static void assertEqualsAsCharactersPtr(JSValueRef value
, const char* expectedValue
)
72 JSStringRef valueAsString
= JSValueToStringCopy(context
, value
, NULL
);
74 size_t jsLength
= JSStringGetLength(valueAsString
);
75 const JSChar
* jsBuffer
= JSStringGetCharactersPtr(valueAsString
);
77 CFStringRef expectedValueAsCFString
= CFStringCreateWithCString(kCFAllocatorDefault
,
79 kCFStringEncodingUTF8
);
80 CFIndex cfLength
= CFStringGetLength(expectedValueAsCFString
);
81 UniChar cfBuffer
[cfLength
];
82 CFStringGetCharacters(expectedValueAsCFString
, CFRangeMake(0, cfLength
), cfBuffer
);
83 CFRelease(expectedValueAsCFString
);
85 if (memcmp(jsBuffer
, cfBuffer
, cfLength
* sizeof(UniChar
)) != 0)
86 fprintf(stderr
, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n");
88 if (jsLength
!= (size_t)cfLength
)
89 fprintf(stderr
, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength
, cfLength
);
91 JSStringRelease(valueAsString
);
94 static JSValueRef jsGlobalValue
; // non-stack value for testing JSValueProtect()
96 /* MyObject pseudo-class */
98 static bool MyObject_hasProperty(JSContextRef context
, JSObjectRef object
, JSStringRef propertyName
)
100 UNUSED_PARAM(context
);
101 UNUSED_PARAM(object
);
103 if (JSStringIsEqualToUTF8CString(propertyName
, "alwaysOne")
104 || JSStringIsEqualToUTF8CString(propertyName
, "cantFind")
105 || JSStringIsEqualToUTF8CString(propertyName
, "myPropertyName")
106 || JSStringIsEqualToUTF8CString(propertyName
, "hasPropertyLie")
107 || JSStringIsEqualToUTF8CString(propertyName
, "0")) {
114 static JSValueRef
MyObject_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
116 UNUSED_PARAM(context
);
117 UNUSED_PARAM(object
);
119 if (JSStringIsEqualToUTF8CString(propertyName
, "alwaysOne")) {
120 return JSValueMakeNumber(context
, 1);
123 if (JSStringIsEqualToUTF8CString(propertyName
, "myPropertyName")) {
124 return JSValueMakeNumber(context
, 1);
127 if (JSStringIsEqualToUTF8CString(propertyName
, "cantFind")) {
128 return JSValueMakeUndefined(context
);
131 if (JSStringIsEqualToUTF8CString(propertyName
, "0")) {
132 *exception
= JSValueMakeNumber(context
, 1);
133 return JSValueMakeNumber(context
, 1);
139 static bool MyObject_setProperty(JSContextRef context
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
141 UNUSED_PARAM(context
);
142 UNUSED_PARAM(object
);
144 UNUSED_PARAM(exception
);
146 if (JSStringIsEqualToUTF8CString(propertyName
, "cantSet"))
147 return true; // pretend we set the property in order to swallow it
152 static bool MyObject_deleteProperty(JSContextRef context
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
154 UNUSED_PARAM(context
);
155 UNUSED_PARAM(object
);
157 if (JSStringIsEqualToUTF8CString(propertyName
, "cantDelete"))
160 if (JSStringIsEqualToUTF8CString(propertyName
, "throwOnDelete")) {
161 *exception
= JSValueMakeNumber(context
, 2);
168 static void MyObject_getPropertyNames(JSContextRef context
, JSObjectRef object
, JSPropertyNameAccumulatorRef propertyNames
)
170 UNUSED_PARAM(context
);
171 UNUSED_PARAM(object
);
173 JSStringRef propertyName
;
175 propertyName
= JSStringCreateWithUTF8CString("alwaysOne");
176 JSPropertyNameAccumulatorAddName(propertyNames
, propertyName
);
177 JSStringRelease(propertyName
);
179 propertyName
= JSStringCreateWithUTF8CString("myPropertyName");
180 JSPropertyNameAccumulatorAddName(propertyNames
, propertyName
);
181 JSStringRelease(propertyName
);
184 static JSValueRef
MyObject_callAsFunction(JSContextRef context
, JSObjectRef object
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
186 UNUSED_PARAM(context
);
187 UNUSED_PARAM(object
);
188 UNUSED_PARAM(thisObject
);
189 UNUSED_PARAM(exception
);
191 if (argumentCount
> 0 && JSValueIsStrictEqual(context
, arguments
[0], JSValueMakeNumber(context
, 0)))
192 return JSValueMakeNumber(context
, 1);
194 return JSValueMakeUndefined(context
);
197 static JSObjectRef
MyObject_callAsConstructor(JSContextRef context
, JSObjectRef object
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
199 UNUSED_PARAM(context
);
200 UNUSED_PARAM(object
);
202 if (argumentCount
> 0 && JSValueIsStrictEqual(context
, arguments
[0], JSValueMakeNumber(context
, 0)))
203 return JSValueToObject(context
, JSValueMakeNumber(context
, 1), exception
);
205 return JSValueToObject(context
, JSValueMakeNumber(context
, 0), exception
);
208 static bool MyObject_hasInstance(JSContextRef context
, JSObjectRef constructor
, JSValueRef possibleValue
, JSValueRef
* exception
)
210 UNUSED_PARAM(context
);
211 UNUSED_PARAM(constructor
);
213 JSStringRef numberString
= JSStringCreateWithUTF8CString("Number");
214 JSObjectRef numberConstructor
= JSValueToObject(context
, JSObjectGetProperty(context
, JSContextGetGlobalObject(context
), numberString
, exception
), exception
);
215 JSStringRelease(numberString
);
217 return JSValueIsInstanceOfConstructor(context
, possibleValue
, numberConstructor
, exception
);
220 static JSValueRef
MyObject_convertToType(JSContextRef context
, JSObjectRef object
, JSType type
, JSValueRef
* exception
)
222 UNUSED_PARAM(object
);
223 UNUSED_PARAM(exception
);
227 return JSValueMakeNumber(context
, 1);
232 // string conversion -- forward to default object class
236 static JSStaticValue evilStaticValues
[] = {
237 { "nullGetSet", 0, 0, kJSPropertyAttributeNone
},
241 static JSStaticFunction evilStaticFunctions
[] = {
242 { "nullCall", 0, kJSPropertyAttributeNone
},
246 JSClassDefinition MyObject_definition
= {
248 kJSClassAttributeNone
,
258 MyObject_hasProperty
,
259 MyObject_getProperty
,
260 MyObject_setProperty
,
261 MyObject_deleteProperty
,
262 MyObject_getPropertyNames
,
263 MyObject_callAsFunction
,
264 MyObject_callAsConstructor
,
265 MyObject_hasInstance
,
266 MyObject_convertToType
,
269 static JSClassRef
MyObject_class(JSContextRef context
)
271 UNUSED_PARAM(context
);
273 static JSClassRef jsClass
;
275 jsClass
= JSClassCreate(&MyObject_definition
);
280 static JSValueRef
Base_get(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
282 UNUSED_PARAM(object
);
283 UNUSED_PARAM(propertyName
);
284 UNUSED_PARAM(exception
);
286 return JSValueMakeNumber(ctx
, 1); // distinguish base get form derived get
289 static bool Base_set(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
291 UNUSED_PARAM(object
);
292 UNUSED_PARAM(propertyName
);
295 *exception
= JSValueMakeNumber(ctx
, 1); // distinguish base set from derived set
299 static JSValueRef
Base_callAsFunction(JSContextRef ctx
, JSObjectRef function
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
301 UNUSED_PARAM(function
);
302 UNUSED_PARAM(thisObject
);
303 UNUSED_PARAM(argumentCount
);
304 UNUSED_PARAM(arguments
);
305 UNUSED_PARAM(exception
);
307 return JSValueMakeNumber(ctx
, 1); // distinguish base call from derived call
310 static JSStaticFunction Base_staticFunctions
[] = {
311 { "baseProtoDup", NULL
, kJSPropertyAttributeNone
},
312 { "baseProto", Base_callAsFunction
, kJSPropertyAttributeNone
},
316 static JSStaticValue Base_staticValues
[] = {
317 { "baseDup", Base_get
, Base_set
, kJSPropertyAttributeNone
},
318 { "baseOnly", Base_get
, Base_set
, kJSPropertyAttributeNone
},
322 static bool TestInitializeFinalize
;
323 static void Base_initialize(JSContextRef context
, JSObjectRef object
)
325 UNUSED_PARAM(context
);
327 if (TestInitializeFinalize
) {
328 ASSERT((void*)1 == JSObjectGetPrivate(object
));
329 JSObjectSetPrivate(object
, (void*)2);
333 static unsigned Base_didFinalize
;
334 static void Base_finalize(JSObjectRef object
)
336 UNUSED_PARAM(object
);
337 if (TestInitializeFinalize
) {
338 ASSERT((void*)4 == JSObjectGetPrivate(object
));
339 Base_didFinalize
= true;
343 static JSClassRef
Base_class(JSContextRef context
)
345 UNUSED_PARAM(context
);
347 static JSClassRef jsClass
;
349 JSClassDefinition definition
= kJSClassDefinitionEmpty
;
350 definition
.staticValues
= Base_staticValues
;
351 definition
.staticFunctions
= Base_staticFunctions
;
352 definition
.initialize
= Base_initialize
;
353 definition
.finalize
= Base_finalize
;
354 jsClass
= JSClassCreate(&definition
);
359 static JSValueRef
Derived_get(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
361 UNUSED_PARAM(object
);
362 UNUSED_PARAM(propertyName
);
363 UNUSED_PARAM(exception
);
365 return JSValueMakeNumber(ctx
, 2); // distinguish base get form derived get
368 static bool Derived_set(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
371 UNUSED_PARAM(object
);
372 UNUSED_PARAM(propertyName
);
375 *exception
= JSValueMakeNumber(ctx
, 2); // distinguish base set from derived set
379 static JSValueRef
Derived_callAsFunction(JSContextRef ctx
, JSObjectRef function
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
381 UNUSED_PARAM(function
);
382 UNUSED_PARAM(thisObject
);
383 UNUSED_PARAM(argumentCount
);
384 UNUSED_PARAM(arguments
);
385 UNUSED_PARAM(exception
);
387 return JSValueMakeNumber(ctx
, 2); // distinguish base call from derived call
390 static JSStaticFunction Derived_staticFunctions
[] = {
391 { "protoOnly", Derived_callAsFunction
, kJSPropertyAttributeNone
},
392 { "protoDup", NULL
, kJSPropertyAttributeNone
},
393 { "baseProtoDup", Derived_callAsFunction
, kJSPropertyAttributeNone
},
397 static JSStaticValue Derived_staticValues
[] = {
398 { "derivedOnly", Derived_get
, Derived_set
, kJSPropertyAttributeNone
},
399 { "protoDup", Derived_get
, Derived_set
, kJSPropertyAttributeNone
},
400 { "baseDup", Derived_get
, Derived_set
, kJSPropertyAttributeNone
},
404 static void Derived_initialize(JSContextRef context
, JSObjectRef object
)
406 UNUSED_PARAM(context
);
408 if (TestInitializeFinalize
) {
409 ASSERT((void*)2 == JSObjectGetPrivate(object
));
410 JSObjectSetPrivate(object
, (void*)3);
414 static void Derived_finalize(JSObjectRef object
)
416 if (TestInitializeFinalize
) {
417 ASSERT((void*)3 == JSObjectGetPrivate(object
));
418 JSObjectSetPrivate(object
, (void*)4);
422 static JSClassRef
Derived_class(JSContextRef context
)
424 static JSClassRef jsClass
;
426 JSClassDefinition definition
= kJSClassDefinitionEmpty
;
427 definition
.parentClass
= Base_class(context
);
428 definition
.staticValues
= Derived_staticValues
;
429 definition
.staticFunctions
= Derived_staticFunctions
;
430 definition
.initialize
= Derived_initialize
;
431 definition
.finalize
= Derived_finalize
;
432 jsClass
= JSClassCreate(&definition
);
437 static JSValueRef
print_callAsFunction(JSContextRef context
, JSObjectRef functionObject
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
439 UNUSED_PARAM(functionObject
);
440 UNUSED_PARAM(thisObject
);
441 UNUSED_PARAM(exception
);
443 if (argumentCount
> 0) {
444 JSStringRef string
= JSValueToStringCopy(context
, arguments
[0], NULL
);
445 size_t sizeUTF8
= JSStringGetMaximumUTF8CStringSize(string
);
446 char stringUTF8
[sizeUTF8
];
447 JSStringGetUTF8CString(string
, stringUTF8
, sizeUTF8
);
448 printf("%s\n", stringUTF8
);
449 JSStringRelease(string
);
452 return JSValueMakeUndefined(context
);
455 static JSObjectRef
myConstructor_callAsConstructor(JSContextRef context
, JSObjectRef constructorObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
457 UNUSED_PARAM(constructorObject
);
458 UNUSED_PARAM(exception
);
460 JSObjectRef result
= JSObjectMake(context
, NULL
, NULL
);
461 if (argumentCount
> 0) {
462 JSStringRef value
= JSStringCreateWithUTF8CString("value");
463 JSObjectSetProperty(context
, result
, value
, arguments
[0], kJSPropertyAttributeNone
, NULL
);
464 JSStringRelease(value
);
471 static void globalObject_initialize(JSContextRef context
, JSObjectRef object
)
473 UNUSED_PARAM(object
);
474 // Ensure that an execution context is passed in
477 // Ensure that the global object is set to the object that we were passed
478 JSObjectRef globalObject
= JSContextGetGlobalObject(context
);
479 ASSERT(globalObject
);
480 ASSERT(object
== globalObject
);
482 // Ensure that the standard global properties have been set on the global object
483 JSStringRef array
= JSStringCreateWithUTF8CString("Array");
484 JSObjectRef arrayConstructor
= JSValueToObject(context
, JSObjectGetProperty(context
, globalObject
, array
, NULL
), NULL
);
485 JSStringRelease(array
);
487 UNUSED_PARAM(arrayConstructor
);
488 ASSERT(arrayConstructor
);
491 static JSValueRef
globalObject_get(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
493 UNUSED_PARAM(object
);
494 UNUSED_PARAM(propertyName
);
495 UNUSED_PARAM(exception
);
497 return JSValueMakeNumber(ctx
, 3);
500 static bool globalObject_set(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSValueRef
* exception
)
502 UNUSED_PARAM(object
);
503 UNUSED_PARAM(propertyName
);
506 *exception
= JSValueMakeNumber(ctx
, 3);
510 static JSValueRef
globalObject_call(JSContextRef ctx
, JSObjectRef function
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
512 UNUSED_PARAM(function
);
513 UNUSED_PARAM(thisObject
);
514 UNUSED_PARAM(argumentCount
);
515 UNUSED_PARAM(arguments
);
516 UNUSED_PARAM(exception
);
518 return JSValueMakeNumber(ctx
, 3);
521 static JSStaticValue globalObject_staticValues
[] = {
522 { "globalStaticValue", globalObject_get
, globalObject_set
, kJSPropertyAttributeNone
},
526 static JSStaticFunction globalObject_staticFunctions
[] = {
527 { "globalStaticFunction", globalObject_call
, kJSPropertyAttributeNone
},
531 static char* createStringWithContentsOfFile(const char* fileName
);
533 static void testInitializeFinalize()
535 JSObjectRef o
= JSObjectMake(context
, Derived_class(context
), (void*)1);
537 ASSERT(JSObjectGetPrivate(o
) == (void*)3);
540 int main(int argc
, char* argv
[])
542 const char *scriptPath
= "testapi.js";
544 scriptPath
= argv
[1];
547 // Test garbage collection with a fresh context
548 context
= JSGlobalContextCreate(NULL
);
549 TestInitializeFinalize
= true;
550 testInitializeFinalize();
551 JSGlobalContextRelease(context
);
552 JSGarbageCollect(context
);
553 TestInitializeFinalize
= false;
555 ASSERT(Base_didFinalize
);
557 JSClassDefinition globalObjectClassDefinition
= kJSClassDefinitionEmpty
;
558 globalObjectClassDefinition
.initialize
= globalObject_initialize
;
559 globalObjectClassDefinition
.staticValues
= globalObject_staticValues
;
560 globalObjectClassDefinition
.staticFunctions
= globalObject_staticFunctions
;
561 globalObjectClassDefinition
.attributes
= kJSClassAttributeNoAutomaticPrototype
;
562 JSClassRef globalObjectClass
= JSClassCreate(&globalObjectClassDefinition
);
563 context
= JSGlobalContextCreate(globalObjectClass
);
565 JSObjectRef globalObject
= JSContextGetGlobalObject(context
);
566 ASSERT(JSValueIsObject(context
, globalObject
));
568 JSValueRef jsUndefined
= JSValueMakeUndefined(context
);
569 JSValueRef jsNull
= JSValueMakeNull(context
);
570 JSValueRef jsTrue
= JSValueMakeBoolean(context
, true);
571 JSValueRef jsFalse
= JSValueMakeBoolean(context
, false);
572 JSValueRef jsZero
= JSValueMakeNumber(context
, 0);
573 JSValueRef jsOne
= JSValueMakeNumber(context
, 1);
574 JSValueRef jsOneThird
= JSValueMakeNumber(context
, 1.0 / 3.0);
575 JSObjectRef jsObjectNoProto
= JSObjectMake(context
, NULL
, NULL
);
576 JSObjectSetPrototype(context
, jsObjectNoProto
, JSValueMakeNull(context
));
578 // FIXME: test funny utf8 characters
579 JSStringRef jsEmptyIString
= JSStringCreateWithUTF8CString("");
580 JSValueRef jsEmptyString
= JSValueMakeString(context
, jsEmptyIString
);
582 JSStringRef jsOneIString
= JSStringCreateWithUTF8CString("1");
583 JSValueRef jsOneString
= JSValueMakeString(context
, jsOneIString
);
585 UniChar singleUniChar
= 65; // Capital A
586 CFMutableStringRef cfString
=
587 CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault
,
593 JSStringRef jsCFIString
= JSStringCreateWithCFString(cfString
);
594 JSValueRef jsCFString
= JSValueMakeString(context
, jsCFIString
);
596 CFStringRef cfEmptyString
= CFStringCreateWithCString(kCFAllocatorDefault
, "", kCFStringEncodingUTF8
);
598 JSStringRef jsCFEmptyIString
= JSStringCreateWithCFString(cfEmptyString
);
599 JSValueRef jsCFEmptyString
= JSValueMakeString(context
, jsCFEmptyIString
);
601 CFIndex cfStringLength
= CFStringGetLength(cfString
);
602 UniChar buffer
[cfStringLength
];
603 CFStringGetCharacters(cfString
,
604 CFRangeMake(0, cfStringLength
),
606 JSStringRef jsCFIStringWithCharacters
= JSStringCreateWithCharacters(buffer
, cfStringLength
);
607 JSValueRef jsCFStringWithCharacters
= JSValueMakeString(context
, jsCFIStringWithCharacters
);
609 JSStringRef jsCFEmptyIStringWithCharacters
= JSStringCreateWithCharacters(buffer
, CFStringGetLength(cfEmptyString
));
610 JSValueRef jsCFEmptyStringWithCharacters
= JSValueMakeString(context
, jsCFEmptyIStringWithCharacters
);
612 ASSERT(JSValueGetType(context
, jsUndefined
) == kJSTypeUndefined
);
613 ASSERT(JSValueGetType(context
, jsNull
) == kJSTypeNull
);
614 ASSERT(JSValueGetType(context
, jsTrue
) == kJSTypeBoolean
);
615 ASSERT(JSValueGetType(context
, jsFalse
) == kJSTypeBoolean
);
616 ASSERT(JSValueGetType(context
, jsZero
) == kJSTypeNumber
);
617 ASSERT(JSValueGetType(context
, jsOne
) == kJSTypeNumber
);
618 ASSERT(JSValueGetType(context
, jsOneThird
) == kJSTypeNumber
);
619 ASSERT(JSValueGetType(context
, jsEmptyString
) == kJSTypeString
);
620 ASSERT(JSValueGetType(context
, jsOneString
) == kJSTypeString
);
621 ASSERT(JSValueGetType(context
, jsCFString
) == kJSTypeString
);
622 ASSERT(JSValueGetType(context
, jsCFStringWithCharacters
) == kJSTypeString
);
623 ASSERT(JSValueGetType(context
, jsCFEmptyString
) == kJSTypeString
);
624 ASSERT(JSValueGetType(context
, jsCFEmptyStringWithCharacters
) == kJSTypeString
);
626 JSObjectRef myObject
= JSObjectMake(context
, MyObject_class(context
), NULL
);
627 JSStringRef myObjectIString
= JSStringCreateWithUTF8CString("MyObject");
628 JSObjectSetProperty(context
, globalObject
, myObjectIString
, myObject
, kJSPropertyAttributeNone
, NULL
);
629 JSStringRelease(myObjectIString
);
631 JSValueRef exception
;
633 // Conversions that throw exceptions
635 ASSERT(NULL
== JSValueToObject(context
, jsNull
, &exception
));
639 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
640 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
641 // After that's resolved, we can remove these casts
642 ASSERT(isnan((float)JSValueToNumber(context
, jsObjectNoProto
, &exception
)));
646 ASSERT(!JSValueToStringCopy(context
, jsObjectNoProto
, &exception
));
649 ASSERT(JSValueToBoolean(context
, myObject
));
652 ASSERT(!JSValueIsEqual(context
, jsObjectNoProto
, JSValueMakeNumber(context
, 1), &exception
));
656 JSObjectGetPropertyAtIndex(context
, myObject
, 0, &exception
);
657 ASSERT(1 == JSValueToNumber(context
, exception
, NULL
));
659 assertEqualsAsBoolean(jsUndefined
, false);
660 assertEqualsAsBoolean(jsNull
, false);
661 assertEqualsAsBoolean(jsTrue
, true);
662 assertEqualsAsBoolean(jsFalse
, false);
663 assertEqualsAsBoolean(jsZero
, false);
664 assertEqualsAsBoolean(jsOne
, true);
665 assertEqualsAsBoolean(jsOneThird
, true);
666 assertEqualsAsBoolean(jsEmptyString
, false);
667 assertEqualsAsBoolean(jsOneString
, true);
668 assertEqualsAsBoolean(jsCFString
, true);
669 assertEqualsAsBoolean(jsCFStringWithCharacters
, true);
670 assertEqualsAsBoolean(jsCFEmptyString
, false);
671 assertEqualsAsBoolean(jsCFEmptyStringWithCharacters
, false);
673 assertEqualsAsNumber(jsUndefined
, nan(""));
674 assertEqualsAsNumber(jsNull
, 0);
675 assertEqualsAsNumber(jsTrue
, 1);
676 assertEqualsAsNumber(jsFalse
, 0);
677 assertEqualsAsNumber(jsZero
, 0);
678 assertEqualsAsNumber(jsOne
, 1);
679 assertEqualsAsNumber(jsOneThird
, 1.0 / 3.0);
680 assertEqualsAsNumber(jsEmptyString
, 0);
681 assertEqualsAsNumber(jsOneString
, 1);
682 assertEqualsAsNumber(jsCFString
, nan(""));
683 assertEqualsAsNumber(jsCFStringWithCharacters
, nan(""));
684 assertEqualsAsNumber(jsCFEmptyString
, 0);
685 assertEqualsAsNumber(jsCFEmptyStringWithCharacters
, 0);
686 ASSERT(sizeof(JSChar
) == sizeof(UniChar
));
688 assertEqualsAsCharactersPtr(jsUndefined
, "undefined");
689 assertEqualsAsCharactersPtr(jsNull
, "null");
690 assertEqualsAsCharactersPtr(jsTrue
, "true");
691 assertEqualsAsCharactersPtr(jsFalse
, "false");
692 assertEqualsAsCharactersPtr(jsZero
, "0");
693 assertEqualsAsCharactersPtr(jsOne
, "1");
694 assertEqualsAsCharactersPtr(jsOneThird
, "0.3333333333333333");
695 assertEqualsAsCharactersPtr(jsEmptyString
, "");
696 assertEqualsAsCharactersPtr(jsOneString
, "1");
697 assertEqualsAsCharactersPtr(jsCFString
, "A");
698 assertEqualsAsCharactersPtr(jsCFStringWithCharacters
, "A");
699 assertEqualsAsCharactersPtr(jsCFEmptyString
, "");
700 assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters
, "");
702 assertEqualsAsUTF8String(jsUndefined
, "undefined");
703 assertEqualsAsUTF8String(jsNull
, "null");
704 assertEqualsAsUTF8String(jsTrue
, "true");
705 assertEqualsAsUTF8String(jsFalse
, "false");
706 assertEqualsAsUTF8String(jsZero
, "0");
707 assertEqualsAsUTF8String(jsOne
, "1");
708 assertEqualsAsUTF8String(jsOneThird
, "0.3333333333333333");
709 assertEqualsAsUTF8String(jsEmptyString
, "");
710 assertEqualsAsUTF8String(jsOneString
, "1");
711 assertEqualsAsUTF8String(jsCFString
, "A");
712 assertEqualsAsUTF8String(jsCFStringWithCharacters
, "A");
713 assertEqualsAsUTF8String(jsCFEmptyString
, "");
714 assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters
, "");
716 ASSERT(JSValueIsStrictEqual(context
, jsTrue
, jsTrue
));
717 ASSERT(!JSValueIsStrictEqual(context
, jsOne
, jsOneString
));
719 ASSERT(JSValueIsEqual(context
, jsOne
, jsOneString
, NULL
));
720 ASSERT(!JSValueIsEqual(context
, jsTrue
, jsFalse
, NULL
));
722 CFStringRef cfJSString
= JSStringCopyCFString(kCFAllocatorDefault
, jsCFIString
);
723 CFStringRef cfJSEmptyString
= JSStringCopyCFString(kCFAllocatorDefault
, jsCFEmptyIString
);
724 ASSERT(CFEqual(cfJSString
, cfString
));
725 ASSERT(CFEqual(cfJSEmptyString
, cfEmptyString
));
726 CFRelease(cfJSString
);
727 CFRelease(cfJSEmptyString
);
730 CFRelease(cfEmptyString
);
732 jsGlobalValue
= JSObjectMake(context
, NULL
, NULL
);
733 JSValueProtect(context
, jsGlobalValue
);
734 JSGarbageCollect(context
);
735 ASSERT(JSValueIsObject(context
, jsGlobalValue
));
736 JSValueUnprotect(context
, jsGlobalValue
);
738 JSStringRef goodSyntax
= JSStringCreateWithUTF8CString("x = 1;");
739 JSStringRef badSyntax
= JSStringCreateWithUTF8CString("x := 1;");
740 ASSERT(JSCheckScriptSyntax(context
, goodSyntax
, NULL
, 0, NULL
));
741 ASSERT(!JSCheckScriptSyntax(context
, badSyntax
, NULL
, 0, NULL
));
748 result
= JSEvaluateScript(context
, goodSyntax
, NULL
, NULL
, 1, NULL
);
750 ASSERT(JSValueIsEqual(context
, result
, jsOne
, NULL
));
753 result
= JSEvaluateScript(context
, badSyntax
, NULL
, NULL
, 1, &exception
);
755 ASSERT(JSValueIsObject(context
, exception
));
757 JSStringRef array
= JSStringCreateWithUTF8CString("Array");
758 JSObjectRef arrayConstructor
= JSValueToObject(context
, JSObjectGetProperty(context
, globalObject
, array
, NULL
), NULL
);
759 JSStringRelease(array
);
760 result
= JSObjectCallAsConstructor(context
, arrayConstructor
, 0, NULL
, NULL
);
762 ASSERT(JSValueIsObject(context
, result
));
763 ASSERT(JSValueIsInstanceOfConstructor(context
, result
, arrayConstructor
, NULL
));
764 ASSERT(!JSValueIsInstanceOfConstructor(context
, JSValueMakeNull(context
), arrayConstructor
, NULL
));
766 o
= JSValueToObject(context
, result
, NULL
);
768 ASSERT(JSValueIsUndefined(context
, JSObjectGetPropertyAtIndex(context
, o
, 0, &exception
)));
771 JSObjectSetPropertyAtIndex(context
, o
, 0, JSValueMakeNumber(context
, 1), &exception
);
775 ASSERT(1 == JSValueToNumber(context
, JSObjectGetPropertyAtIndex(context
, o
, 0, &exception
), &exception
));
778 JSStringRef functionBody
;
779 JSObjectRef function
;
782 functionBody
= JSStringCreateWithUTF8CString("rreturn Array;");
783 JSStringRef line
= JSStringCreateWithUTF8CString("line");
784 ASSERT(!JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, &exception
));
785 ASSERT(JSValueIsObject(context
, exception
));
786 v
= JSObjectGetProperty(context
, JSValueToObject(context
, exception
, NULL
), line
, NULL
);
787 assertEqualsAsNumber(v
, 2); // FIXME: Lexer::setCode bumps startingLineNumber by 1 -- we need to change internal callers so that it doesn't have to (saying '0' to mean '1' in the API would be really confusing -- it's really confusing internally, in fact)
788 JSStringRelease(functionBody
);
789 JSStringRelease(line
);
792 functionBody
= JSStringCreateWithUTF8CString("return Array;");
793 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, &exception
);
794 JSStringRelease(functionBody
);
796 ASSERT(JSObjectIsFunction(context
, function
));
797 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, NULL
);
799 ASSERT(JSValueIsEqual(context
, v
, arrayConstructor
, NULL
));
802 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, jsEmptyIString
, NULL
, 0, &exception
);
804 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, &exception
);
805 ASSERT(v
&& !exception
);
806 ASSERT(JSValueIsUndefined(context
, v
));
810 JSStringRef foo
= JSStringCreateWithUTF8CString("foo");
811 JSStringRef argumentNames
[] = { foo
};
812 functionBody
= JSStringCreateWithUTF8CString("return foo;");
813 function
= JSObjectMakeFunction(context
, foo
, 1, argumentNames
, functionBody
, NULL
, 1, &exception
);
814 ASSERT(function
&& !exception
);
815 JSValueRef arguments
[] = { JSValueMakeNumber(context
, 2) };
816 v
= JSObjectCallAsFunction(context
, function
, NULL
, 1, arguments
, &exception
);
817 JSStringRelease(foo
);
818 JSStringRelease(functionBody
);
820 string
= JSValueToStringCopy(context
, function
, NULL
);
821 assertEqualsAsUTF8String(JSValueMakeString(context
, string
), "function foo(foo) \n{\n return foo;\n}");
822 JSStringRelease(string
);
824 JSStringRef print
= JSStringCreateWithUTF8CString("print");
825 JSObjectRef printFunction
= JSObjectMakeFunctionWithCallback(context
, print
, print_callAsFunction
);
826 JSObjectSetProperty(context
, globalObject
, print
, printFunction
, kJSPropertyAttributeNone
, NULL
);
827 JSStringRelease(print
);
829 ASSERT(!JSObjectSetPrivate(printFunction
, (void*)1));
830 ASSERT(!JSObjectGetPrivate(printFunction
));
832 JSStringRef myConstructorIString
= JSStringCreateWithUTF8CString("MyConstructor");
833 JSObjectRef myConstructor
= JSObjectMakeConstructor(context
, NULL
, myConstructor_callAsConstructor
);
834 JSObjectSetProperty(context
, globalObject
, myConstructorIString
, myConstructor
, kJSPropertyAttributeNone
, NULL
);
835 JSStringRelease(myConstructorIString
);
837 ASSERT(!JSObjectSetPrivate(myConstructor
, (void*)1));
838 ASSERT(!JSObjectGetPrivate(myConstructor
));
840 string
= JSStringCreateWithUTF8CString("Derived");
841 JSObjectRef derivedConstructor
= JSObjectMakeConstructor(context
, Derived_class(context
), NULL
);
842 JSObjectSetProperty(context
, globalObject
, string
, derivedConstructor
, kJSPropertyAttributeNone
, NULL
);
843 JSStringRelease(string
);
845 o
= JSObjectMake(context
, NULL
, NULL
);
846 JSObjectSetProperty(context
, o
, jsOneIString
, JSValueMakeNumber(context
, 1), kJSPropertyAttributeNone
, NULL
);
847 JSObjectSetProperty(context
, o
, jsCFIString
, JSValueMakeNumber(context
, 1), kJSPropertyAttributeDontEnum
, NULL
);
848 JSPropertyNameArrayRef nameArray
= JSObjectCopyPropertyNames(context
, o
);
849 size_t expectedCount
= JSPropertyNameArrayGetCount(nameArray
);
851 for (count
= 0; count
< expectedCount
; ++count
)
852 JSPropertyNameArrayGetNameAtIndex(nameArray
, count
);
853 JSPropertyNameArrayRelease(nameArray
);
854 ASSERT(count
== 1); // jsCFString should not be enumerated
856 JSClassDefinition nullDefinition
= kJSClassDefinitionEmpty
;
857 nullDefinition
.attributes
= kJSClassAttributeNoAutomaticPrototype
;
858 JSClassRef nullClass
= JSClassCreate(&nullDefinition
);
859 JSClassRelease(nullClass
);
861 nullDefinition
= kJSClassDefinitionEmpty
;
862 nullClass
= JSClassCreate(&nullDefinition
);
863 JSClassRelease(nullClass
);
865 functionBody
= JSStringCreateWithUTF8CString("return this;");
866 function
= JSObjectMakeFunction(context
, NULL
, 0, NULL
, functionBody
, NULL
, 1, NULL
);
867 JSStringRelease(functionBody
);
868 v
= JSObjectCallAsFunction(context
, function
, NULL
, 0, NULL
, NULL
);
869 ASSERT(JSValueIsEqual(context
, v
, globalObject
, NULL
));
870 v
= JSObjectCallAsFunction(context
, function
, o
, 0, NULL
, NULL
);
871 ASSERT(JSValueIsEqual(context
, v
, o
, NULL
));
873 char* scriptUTF8
= createStringWithContentsOfFile(scriptPath
);
875 printf("FAIL: Test script could not be loaded.\n");
877 JSStringRef script
= JSStringCreateWithUTF8CString(scriptUTF8
);
878 result
= JSEvaluateScript(context
, script
, NULL
, NULL
, 1, &exception
);
879 if (JSValueIsUndefined(context
, result
))
880 printf("PASS: Test script executed successfully.\n");
882 printf("FAIL: Test script returned unexpected value:\n");
883 JSStringRef exceptionIString
= JSValueToStringCopy(context
, exception
, NULL
);
884 CFStringRef exceptionCF
= JSStringCopyCFString(kCFAllocatorDefault
, exceptionIString
);
886 CFRelease(exceptionCF
);
887 JSStringRelease(exceptionIString
);
889 JSStringRelease(script
);
893 // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
899 JSStringRelease(jsEmptyIString
);
900 JSStringRelease(jsOneIString
);
901 JSStringRelease(jsCFIString
);
902 JSStringRelease(jsCFEmptyIString
);
903 JSStringRelease(jsCFIStringWithCharacters
);
904 JSStringRelease(jsCFEmptyIStringWithCharacters
);
905 JSStringRelease(goodSyntax
);
906 JSStringRelease(badSyntax
);
908 JSGlobalContextRelease(context
);
909 JSGarbageCollect(context
);
910 JSClassRelease(globalObjectClass
);
912 printf("PASS: Program exited normally.\n");
916 static char* createStringWithContentsOfFile(const char* fileName
)
920 size_t buffer_size
= 0;
921 size_t buffer_capacity
= 1024;
922 buffer
= (char*)malloc(buffer_capacity
);
924 FILE* f
= fopen(fileName
, "r");
926 fprintf(stderr
, "Could not open file: %s\n", fileName
);
930 while (!feof(f
) && !ferror(f
)) {
931 buffer_size
+= fread(buffer
+ buffer_size
, 1, buffer_capacity
- buffer_size
, f
);
932 if (buffer_size
== buffer_capacity
) { // guarantees space for trailing '\0'
933 buffer_capacity
*= 2;
934 buffer
= (char*)realloc(buffer
, buffer_capacity
);
938 ASSERT(buffer_size
< buffer_capacity
);
941 buffer
[buffer_size
] = '\0';