16b7418eee12e4c2fec3d70d08cfe3ae73196747
[WebKit-https.git] / Source / JavaScriptCore / API / tests / testapi.c
1 /*
2  * Copyright (C) 2006-2017 Apple Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
24  */
25
26 #include <wtf/Platform.h>
27
28 #include "JavaScriptCore.h"
29 #include "JSBasePrivate.h"
30 #include "JSContextRefPrivate.h"
31 #include "JSMarkingConstraintPrivate.h"
32 #include "JSObjectRefPrivate.h"
33 #include "JSScriptRefPrivate.h"
34 #include "JSStringRefPrivate.h"
35 #include "JSWeakPrivate.h"
36 #include <math.h>
37 #define ASSERT_DISABLED 0
38 #include <wtf/Assertions.h>
39
40 #if OS(WINDOWS)
41 #include <windows.h>
42 #endif
43
44 #include "CompareAndSwapTest.h"
45 #include "CustomGlobalObjectClassTest.h"
46 #include "ExecutionTimeLimitTest.h"
47 #include "FunctionOverridesTest.h"
48 #include "GlobalContextWithFinalizerTest.h"
49 #include "JSONParseTest.h"
50 #include "PingPongStackOverflowTest.h"
51 #include "TypedArrayCTest.h"
52
53 #if JSC_OBJC_API_ENABLED
54 void testObjectiveCAPI(void);
55 #endif
56
57 bool assertTrue(bool value, const char* message);
58
59 static JSGlobalContextRef context;
60 int failed;
61 static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue)
62 {
63     if (JSValueToBoolean(context, value) != expectedValue) {
64         fprintf(stderr, "assertEqualsAsBoolean failed: %p, %d\n", value, expectedValue);
65         failed = 1;
66     }
67 }
68
69 static void assertEqualsAsNumber(JSValueRef value, double expectedValue)
70 {
71     double number = JSValueToNumber(context, value, NULL);
72
73     // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
74     // causing a build break with -Wshorten-64-to-32 enabled.  The issue is known by the appropriate team.
75     // After that's resolved, we can remove these casts
76     if (number != expectedValue && !(isnan((float)number) && isnan((float)expectedValue))) {
77         fprintf(stderr, "assertEqualsAsNumber failed: %p, %lf\n", value, expectedValue);
78         failed = 1;
79     }
80 }
81
82 static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue)
83 {
84     JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
85
86     size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString);
87     char* jsBuffer = (char*)malloc(jsSize);
88     JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize);
89
90     unsigned i;
91     for (i = 0; jsBuffer[i]; i++) {
92         if (jsBuffer[i] != expectedValue[i]) {
93             fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]);
94             fprintf(stderr, "value: %s\n", jsBuffer);
95             fprintf(stderr, "expectedValue: %s\n", expectedValue);
96             failed = 1;
97         }
98     }
99
100     if (jsSize < strlen(jsBuffer) + 1) {
101         fprintf(stderr, "assertEqualsAsUTF8String failed: jsSize was too small\n");
102         failed = 1;
103     }
104
105     free(jsBuffer);
106     JSStringRelease(valueAsString);
107 }
108
109 static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedValue)
110 {
111     JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
112
113     size_t jsLength = JSStringGetLength(valueAsString);
114     const JSChar* jsBuffer = JSStringGetCharactersPtr(valueAsString);
115
116     CFStringRef expectedValueAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, 
117                                                                     expectedValue,
118                                                                     kCFStringEncodingUTF8);    
119     CFIndex cfLength = CFStringGetLength(expectedValueAsCFString);
120     UniChar* cfBuffer = (UniChar*)malloc(cfLength * sizeof(UniChar));
121     CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer);
122     CFRelease(expectedValueAsCFString);
123
124     if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0) {
125         fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n");
126         failed = 1;
127     }
128     
129     if (jsLength != (size_t)cfLength) {
130 #if OS(WINDOWS)
131         fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%Iu) != cfLength(%Iu)\n", jsLength, (size_t)cfLength);
132 #else
133         fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%zu) != cfLength(%zu)\n", jsLength, (size_t)cfLength);
134 #endif
135         failed = 1;
136     }
137
138     free(cfBuffer);
139     JSStringRelease(valueAsString);
140 }
141
142 static bool timeZoneIsPST()
143 {
144     char timeZoneName[70];
145     struct tm gtm;
146     memset(&gtm, 0, sizeof(gtm));
147     strftime(timeZoneName, sizeof(timeZoneName), "%Z", &gtm);
148
149     return 0 == strcmp("PST", timeZoneName);
150 }
151
152 static JSValueRef jsGlobalValue; // non-stack value for testing JSValueProtect()
153
154 /* MyObject pseudo-class */
155
156 static bool MyObject_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName)
157 {
158     UNUSED_PARAM(context);
159     UNUSED_PARAM(object);
160
161     if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")
162         || JSStringIsEqualToUTF8CString(propertyName, "cantFind")
163         || JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")
164         || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")
165         || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")
166         || JSStringIsEqualToUTF8CString(propertyName, "0")) {
167         return true;
168     }
169     
170     return false;
171 }
172
173 static JSValueRef MyObject_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
174 {
175     UNUSED_PARAM(context);
176     UNUSED_PARAM(object);
177     
178     if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")) {
179         return JSValueMakeNumber(context, 1);
180     }
181     
182     if (JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")) {
183         return JSValueMakeNumber(context, 1);
184     }
185
186     if (JSStringIsEqualToUTF8CString(propertyName, "cantFind")) {
187         return JSValueMakeUndefined(context);
188     }
189     
190     if (JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")) {
191         return 0;
192     }
193
194     if (JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")) {
195         return JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
196     }
197
198     if (JSStringIsEqualToUTF8CString(propertyName, "0")) {
199         *exception = JSValueMakeNumber(context, 1);
200         return JSValueMakeNumber(context, 1);
201     }
202     
203     return JSValueMakeNull(context);
204 }
205
206 static bool MyObject_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
207 {
208     UNUSED_PARAM(context);
209     UNUSED_PARAM(object);
210     UNUSED_PARAM(value);
211     UNUSED_PARAM(exception);
212
213     if (JSStringIsEqualToUTF8CString(propertyName, "cantSet"))
214         return true; // pretend we set the property in order to swallow it
215     
216     if (JSStringIsEqualToUTF8CString(propertyName, "throwOnSet")) {
217         JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
218     }
219     
220     return false;
221 }
222
223 static bool MyObject_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
224 {
225     UNUSED_PARAM(context);
226     UNUSED_PARAM(object);
227     
228     if (JSStringIsEqualToUTF8CString(propertyName, "cantDelete"))
229         return true;
230     
231     if (JSStringIsEqualToUTF8CString(propertyName, "throwOnDelete")) {
232         JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
233         return false;
234     }
235
236     return false;
237 }
238
239 static void MyObject_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
240 {
241     UNUSED_PARAM(context);
242     UNUSED_PARAM(object);
243     
244     JSStringRef propertyName;
245     
246     propertyName = JSStringCreateWithUTF8CString("alwaysOne");
247     JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
248     JSStringRelease(propertyName);
249     
250     propertyName = JSStringCreateWithUTF8CString("myPropertyName");
251     JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
252     JSStringRelease(propertyName);
253 }
254
255 static JSValueRef MyObject_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
256 {
257     UNUSED_PARAM(context);
258     UNUSED_PARAM(object);
259     UNUSED_PARAM(thisObject);
260     UNUSED_PARAM(exception);
261
262     if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnCall")) {
263         JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
264         return JSValueMakeUndefined(context);
265     }
266
267     if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
268         return JSValueMakeNumber(context, 1);
269     
270     return JSValueMakeUndefined(context);
271 }
272
273 static JSObjectRef MyObject_callAsConstructor(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
274 {
275     UNUSED_PARAM(context);
276     UNUSED_PARAM(object);
277
278     if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnConstruct")) {
279         JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
280         return object;
281     }
282
283     if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
284         return JSValueToObject(context, JSValueMakeNumber(context, 1), exception);
285     
286     return JSValueToObject(context, JSValueMakeNumber(context, 0), exception);
287 }
288
289 static bool MyObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
290 {
291     UNUSED_PARAM(context);
292     UNUSED_PARAM(constructor);
293
294     if (JSValueIsString(context, possibleValue) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, possibleValue, 0), "throwOnHasInstance")) {
295         JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), constructor, JSStringCreateWithUTF8CString("test script"), 1, exception);
296         return false;
297     }
298
299     JSStringRef numberString = JSStringCreateWithUTF8CString("Number");
300     JSObjectRef numberConstructor = JSValueToObject(context, JSObjectGetProperty(context, JSContextGetGlobalObject(context), numberString, exception), exception);
301     JSStringRelease(numberString);
302
303     return JSValueIsInstanceOfConstructor(context, possibleValue, numberConstructor, exception);
304 }
305
306 static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
307 {
308     UNUSED_PARAM(object);
309     UNUSED_PARAM(exception);
310     
311     switch (type) {
312     case kJSTypeNumber:
313         return JSValueMakeNumber(context, 1);
314     case kJSTypeString:
315         {
316             JSStringRef string = JSStringCreateWithUTF8CString("MyObjectAsString");
317             JSValueRef result = JSValueMakeString(context, string);
318             JSStringRelease(string);
319             return result;
320         }
321     default:
322         break;
323     }
324
325     // string conversion -- forward to default object class
326     return JSValueMakeNull(context);
327 }
328
329 static JSValueRef MyObject_convertToTypeWrapper(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
330 {
331     UNUSED_PARAM(context);
332     UNUSED_PARAM(object);
333     UNUSED_PARAM(type);
334     UNUSED_PARAM(exception);
335     // Forward to default object class
336     return 0;
337 }
338
339 static bool MyObject_set_nullGetForwardSet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
340 {
341     UNUSED_PARAM(ctx);
342     UNUSED_PARAM(object);
343     UNUSED_PARAM(propertyName);
344     UNUSED_PARAM(value);
345     UNUSED_PARAM(exception);
346     return false; // Forward to parent class.
347 }
348
349 static JSStaticValue evilStaticValues[] = {
350     { "nullGetSet", 0, 0, kJSPropertyAttributeNone },
351     { "nullGetForwardSet", 0, MyObject_set_nullGetForwardSet, kJSPropertyAttributeNone },
352     { 0, 0, 0, 0 }
353 };
354
355 static JSStaticFunction evilStaticFunctions[] = {
356     { "nullCall", 0, kJSPropertyAttributeNone },
357     { 0, 0, 0 }
358 };
359
360 JSClassDefinition MyObject_definition = {
361     0,
362     kJSClassAttributeNone,
363     
364     "MyObject",
365     NULL,
366     
367     evilStaticValues,
368     evilStaticFunctions,
369     
370     NULL,
371     NULL,
372     MyObject_hasProperty,
373     MyObject_getProperty,
374     MyObject_setProperty,
375     MyObject_deleteProperty,
376     MyObject_getPropertyNames,
377     MyObject_callAsFunction,
378     MyObject_callAsConstructor,
379     MyObject_hasInstance,
380     MyObject_convertToType,
381 };
382
383 JSClassDefinition MyObject_convertToTypeWrapperDefinition = {
384     0,
385     kJSClassAttributeNone,
386     
387     "MyObject",
388     NULL,
389     
390     NULL,
391     NULL,
392     
393     NULL,
394     NULL,
395     NULL,
396     NULL,
397     NULL,
398     NULL,
399     NULL,
400     NULL,
401     NULL,
402     NULL,
403     MyObject_convertToTypeWrapper,
404 };
405
406 JSClassDefinition MyObject_nullWrapperDefinition = {
407     0,
408     kJSClassAttributeNone,
409     
410     "MyObject",
411     NULL,
412     
413     NULL,
414     NULL,
415     
416     NULL,
417     NULL,
418     NULL,
419     NULL,
420     NULL,
421     NULL,
422     NULL,
423     NULL,
424     NULL,
425     NULL,
426     NULL,
427 };
428
429 static JSClassRef MyObject_class(JSContextRef context)
430 {
431     UNUSED_PARAM(context);
432
433     static JSClassRef jsClass;
434     if (!jsClass) {
435         JSClassRef baseClass = JSClassCreate(&MyObject_definition);
436         MyObject_convertToTypeWrapperDefinition.parentClass = baseClass;
437         JSClassRef wrapperClass = JSClassCreate(&MyObject_convertToTypeWrapperDefinition);
438         MyObject_nullWrapperDefinition.parentClass = wrapperClass;
439         jsClass = JSClassCreate(&MyObject_nullWrapperDefinition);
440     }
441
442     return jsClass;
443 }
444
445 static JSValueRef PropertyCatchalls_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
446 {
447     UNUSED_PARAM(context);
448     UNUSED_PARAM(object);
449     UNUSED_PARAM(propertyName);
450     UNUSED_PARAM(exception);
451
452     if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
453         static size_t count;
454         if (count++ < 5)
455             return NULL;
456
457         // Swallow all .x gets after 5, returning null.
458         return JSValueMakeNull(context);
459     }
460
461     if (JSStringIsEqualToUTF8CString(propertyName, "y")) {
462         static size_t count;
463         if (count++ < 5)
464             return NULL;
465
466         // Swallow all .y gets after 5, returning null.
467         return JSValueMakeNull(context);
468     }
469     
470     if (JSStringIsEqualToUTF8CString(propertyName, "z")) {
471         static size_t count;
472         if (count++ < 5)
473             return NULL;
474
475         // Swallow all .y gets after 5, returning null.
476         return JSValueMakeNull(context);
477     }
478
479     return NULL;
480 }
481
482 static bool PropertyCatchalls_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
483 {
484     UNUSED_PARAM(context);
485     UNUSED_PARAM(object);
486     UNUSED_PARAM(propertyName);
487     UNUSED_PARAM(value);
488     UNUSED_PARAM(exception);
489
490     if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
491         static size_t count;
492         if (count++ < 5)
493             return false;
494
495         // Swallow all .x sets after 4.
496         return true;
497     }
498
499     if (JSStringIsEqualToUTF8CString(propertyName, "make_throw") || JSStringIsEqualToUTF8CString(propertyName, "0")) {
500         *exception = JSValueMakeNumber(context, 5);
501         return true;
502     }
503
504     return false;
505 }
506
507 static void PropertyCatchalls_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
508 {
509     UNUSED_PARAM(context);
510     UNUSED_PARAM(object);
511
512     static size_t count;
513     static const char* numbers[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
514     
515     // Provide a property of a different name every time.
516     JSStringRef propertyName = JSStringCreateWithUTF8CString(numbers[count++ % 10]);
517     JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
518     JSStringRelease(propertyName);
519 }
520
521 JSClassDefinition PropertyCatchalls_definition = {
522     0,
523     kJSClassAttributeNone,
524     
525     "PropertyCatchalls",
526     NULL,
527     
528     NULL,
529     NULL,
530     
531     NULL,
532     NULL,
533     NULL,
534     PropertyCatchalls_getProperty,
535     PropertyCatchalls_setProperty,
536     NULL,
537     PropertyCatchalls_getPropertyNames,
538     NULL,
539     NULL,
540     NULL,
541     NULL,
542 };
543
544 static JSClassRef PropertyCatchalls_class(JSContextRef context)
545 {
546     UNUSED_PARAM(context);
547
548     static JSClassRef jsClass;
549     if (!jsClass)
550         jsClass = JSClassCreate(&PropertyCatchalls_definition);
551     
552     return jsClass;
553 }
554
555 static bool EvilExceptionObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
556 {
557     UNUSED_PARAM(context);
558     UNUSED_PARAM(constructor);
559     
560     JSStringRef hasInstanceName = JSStringCreateWithUTF8CString("hasInstance");
561     JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception);
562     JSStringRelease(hasInstanceName);
563     if (!hasInstance)
564         return false;
565     JSObjectRef function = JSValueToObject(context, hasInstance, exception);
566     JSValueRef result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception);
567     return result && JSValueToBoolean(context, result);
568 }
569
570 static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
571 {
572     UNUSED_PARAM(object);
573     UNUSED_PARAM(exception);
574     JSStringRef funcName;
575     switch (type) {
576     case kJSTypeNumber:
577         funcName = JSStringCreateWithUTF8CString("toNumber");
578         break;
579     case kJSTypeString:
580         funcName = JSStringCreateWithUTF8CString("toStringExplicit");
581         break;
582     default:
583         return JSValueMakeNull(context);
584     }
585     
586     JSValueRef func = JSObjectGetProperty(context, object, funcName, exception);
587     JSStringRelease(funcName);    
588     JSObjectRef function = JSValueToObject(context, func, exception);
589     if (!function)
590         return JSValueMakeNull(context);
591     JSValueRef value = JSObjectCallAsFunction(context, function, object, 0, NULL, exception);
592     if (!value) {
593         JSStringRef errorString = JSStringCreateWithUTF8CString("convertToType failed"); 
594         JSValueRef errorStringRef = JSValueMakeString(context, errorString);
595         JSStringRelease(errorString);
596         return errorStringRef;
597     }
598     return value;
599 }
600
601 JSClassDefinition EvilExceptionObject_definition = {
602     0,
603     kJSClassAttributeNone,
604
605     "EvilExceptionObject",
606     NULL,
607
608     NULL,
609     NULL,
610
611     NULL,
612     NULL,
613     NULL,
614     NULL,
615     NULL,
616     NULL,
617     NULL,
618     NULL,
619     NULL,
620     EvilExceptionObject_hasInstance,
621     EvilExceptionObject_convertToType,
622 };
623
624 static JSClassRef EvilExceptionObject_class(JSContextRef context)
625 {
626     UNUSED_PARAM(context);
627     
628     static JSClassRef jsClass;
629     if (!jsClass)
630         jsClass = JSClassCreate(&EvilExceptionObject_definition);
631     
632     return jsClass;
633 }
634
635 JSClassDefinition EmptyObject_definition = {
636     0,
637     kJSClassAttributeNone,
638     
639     NULL,
640     NULL,
641     
642     NULL,
643     NULL,
644     
645     NULL,
646     NULL,
647     NULL,
648     NULL,
649     NULL,
650     NULL,
651     NULL,
652     NULL,
653     NULL,
654     NULL,
655     NULL,
656 };
657
658 static JSClassRef EmptyObject_class(JSContextRef context)
659 {
660     UNUSED_PARAM(context);
661     
662     static JSClassRef jsClass;
663     if (!jsClass)
664         jsClass = JSClassCreate(&EmptyObject_definition);
665     
666     return jsClass;
667 }
668
669
670 static JSValueRef Base_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
671 {
672     UNUSED_PARAM(object);
673     UNUSED_PARAM(propertyName);
674     UNUSED_PARAM(exception);
675
676     return JSValueMakeNumber(ctx, 1); // distinguish base get form derived get
677 }
678
679 static bool Base_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
680 {
681     UNUSED_PARAM(object);
682     UNUSED_PARAM(propertyName);
683     UNUSED_PARAM(value);
684
685     *exception = JSValueMakeNumber(ctx, 1); // distinguish base set from derived set
686     return true;
687 }
688
689 static JSValueRef Base_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
690 {
691     UNUSED_PARAM(function);
692     UNUSED_PARAM(thisObject);
693     UNUSED_PARAM(argumentCount);
694     UNUSED_PARAM(arguments);
695     UNUSED_PARAM(exception);
696     
697     return JSValueMakeNumber(ctx, 1); // distinguish base call from derived call
698 }
699
700 static JSValueRef Base_returnHardNull(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
701 {
702     UNUSED_PARAM(ctx);
703     UNUSED_PARAM(function);
704     UNUSED_PARAM(thisObject);
705     UNUSED_PARAM(argumentCount);
706     UNUSED_PARAM(arguments);
707     UNUSED_PARAM(exception);
708     
709     return 0; // should convert to undefined!
710 }
711
712 static JSStaticFunction Base_staticFunctions[] = {
713     { "baseProtoDup", NULL, kJSPropertyAttributeNone },
714     { "baseProto", Base_callAsFunction, kJSPropertyAttributeNone },
715     { "baseHardNull", Base_returnHardNull, kJSPropertyAttributeNone },
716     { 0, 0, 0 }
717 };
718
719 static JSStaticValue Base_staticValues[] = {
720     { "baseDup", Base_get, Base_set, kJSPropertyAttributeNone },
721     { "baseOnly", Base_get, Base_set, kJSPropertyAttributeNone },
722     { 0, 0, 0, 0 }
723 };
724
725 static bool TestInitializeFinalize;
726 static void Base_initialize(JSContextRef context, JSObjectRef object)
727 {
728     UNUSED_PARAM(context);
729
730     if (TestInitializeFinalize) {
731         ASSERT((void*)1 == JSObjectGetPrivate(object));
732         JSObjectSetPrivate(object, (void*)2);
733     }
734 }
735
736 static unsigned Base_didFinalize;
737 static void Base_finalize(JSObjectRef object)
738 {
739     UNUSED_PARAM(object);
740     if (TestInitializeFinalize) {
741         ASSERT((void*)4 == JSObjectGetPrivate(object));
742         Base_didFinalize = true;
743     }
744 }
745
746 static JSClassRef Base_class(JSContextRef context)
747 {
748     UNUSED_PARAM(context);
749
750     static JSClassRef jsClass;
751     if (!jsClass) {
752         JSClassDefinition definition = kJSClassDefinitionEmpty;
753         definition.staticValues = Base_staticValues;
754         definition.staticFunctions = Base_staticFunctions;
755         definition.initialize = Base_initialize;
756         definition.finalize = Base_finalize;
757         jsClass = JSClassCreate(&definition);
758     }
759     return jsClass;
760 }
761
762 static JSValueRef Derived_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
763 {
764     UNUSED_PARAM(object);
765     UNUSED_PARAM(propertyName);
766     UNUSED_PARAM(exception);
767
768     return JSValueMakeNumber(ctx, 2); // distinguish base get form derived get
769 }
770
771 static bool Derived_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
772 {
773     UNUSED_PARAM(ctx);
774     UNUSED_PARAM(object);
775     UNUSED_PARAM(propertyName);
776     UNUSED_PARAM(value);
777
778     *exception = JSValueMakeNumber(ctx, 2); // distinguish base set from derived set
779     return true;
780 }
781
782 static JSValueRef Derived_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
783 {
784     UNUSED_PARAM(function);
785     UNUSED_PARAM(thisObject);
786     UNUSED_PARAM(argumentCount);
787     UNUSED_PARAM(arguments);
788     UNUSED_PARAM(exception);
789     
790     return JSValueMakeNumber(ctx, 2); // distinguish base call from derived call
791 }
792
793 static JSStaticFunction Derived_staticFunctions[] = {
794     { "protoOnly", Derived_callAsFunction, kJSPropertyAttributeNone },
795     { "protoDup", NULL, kJSPropertyAttributeNone },
796     { "baseProtoDup", Derived_callAsFunction, kJSPropertyAttributeNone },
797     { 0, 0, 0 }
798 };
799
800 static JSStaticValue Derived_staticValues[] = {
801     { "derivedOnly", Derived_get, Derived_set, kJSPropertyAttributeNone },
802     { "protoDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
803     { "baseDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
804     { 0, 0, 0, 0 }
805 };
806
807 static void Derived_initialize(JSContextRef context, JSObjectRef object)
808 {
809     UNUSED_PARAM(context);
810
811     if (TestInitializeFinalize) {
812         ASSERT((void*)2 == JSObjectGetPrivate(object));
813         JSObjectSetPrivate(object, (void*)3);
814     }
815 }
816
817 static void Derived_finalize(JSObjectRef object)
818 {
819     if (TestInitializeFinalize) {
820         ASSERT((void*)3 == JSObjectGetPrivate(object));
821         JSObjectSetPrivate(object, (void*)4);
822     }
823 }
824
825 static JSClassRef Derived_class(JSContextRef context)
826 {
827     static JSClassRef jsClass;
828     if (!jsClass) {
829         JSClassDefinition definition = kJSClassDefinitionEmpty;
830         definition.parentClass = Base_class(context);
831         definition.staticValues = Derived_staticValues;
832         definition.staticFunctions = Derived_staticFunctions;
833         definition.initialize = Derived_initialize;
834         definition.finalize = Derived_finalize;
835         jsClass = JSClassCreate(&definition);
836     }
837     return jsClass;
838 }
839
840 static JSClassRef Derived2_class(JSContextRef context)
841 {
842     static JSClassRef jsClass;
843     if (!jsClass) {
844         JSClassDefinition definition = kJSClassDefinitionEmpty;
845         definition.parentClass = Derived_class(context);
846         jsClass = JSClassCreate(&definition);
847     }
848     return jsClass;
849 }
850
851 static JSValueRef print_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
852 {
853     UNUSED_PARAM(functionObject);
854     UNUSED_PARAM(thisObject);
855     UNUSED_PARAM(exception);
856
857     ASSERT(JSContextGetGlobalContext(ctx) == context);
858     
859     if (argumentCount > 0) {
860         JSStringRef string = JSValueToStringCopy(ctx, arguments[0], NULL);
861         size_t sizeUTF8 = JSStringGetMaximumUTF8CStringSize(string);
862         char* stringUTF8 = (char*)malloc(sizeUTF8);
863         JSStringGetUTF8CString(string, stringUTF8, sizeUTF8);
864         printf("%s\n", stringUTF8);
865         free(stringUTF8);
866         JSStringRelease(string);
867     }
868     
869     return JSValueMakeUndefined(ctx);
870 }
871
872 static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
873 {
874     UNUSED_PARAM(constructorObject);
875     UNUSED_PARAM(exception);
876     
877     JSObjectRef result = JSObjectMake(context, NULL, NULL);
878     if (argumentCount > 0) {
879         JSStringRef value = JSStringCreateWithUTF8CString("value");
880         JSObjectSetProperty(context, result, value, arguments[0], kJSPropertyAttributeNone, NULL);
881         JSStringRelease(value);
882     }
883     
884     return result;
885 }
886
887 static JSObjectRef myBadConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
888 {
889     UNUSED_PARAM(context);
890     UNUSED_PARAM(constructorObject);
891     UNUSED_PARAM(argumentCount);
892     UNUSED_PARAM(arguments);
893     UNUSED_PARAM(exception);
894     
895     return 0;
896 }
897
898
899 static void globalObject_initialize(JSContextRef context, JSObjectRef object)
900 {
901     UNUSED_PARAM(object);
902     // Ensure that an execution context is passed in
903     ASSERT(context);
904
905     JSObjectRef globalObject = JSContextGetGlobalObject(context);
906     ASSERT(globalObject);
907
908     // Ensure that the standard global properties have been set on the global object
909     JSStringRef array = JSStringCreateWithUTF8CString("Array");
910     JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
911     JSStringRelease(array);
912
913     UNUSED_PARAM(arrayConstructor);
914     ASSERT(arrayConstructor);
915 }
916
917 static JSValueRef globalObject_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
918 {
919     UNUSED_PARAM(object);
920     UNUSED_PARAM(propertyName);
921     UNUSED_PARAM(exception);
922
923     return JSValueMakeNumber(ctx, 3);
924 }
925
926 static bool globalObject_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
927 {
928     UNUSED_PARAM(object);
929     UNUSED_PARAM(propertyName);
930     UNUSED_PARAM(value);
931
932     *exception = JSValueMakeNumber(ctx, 3);
933     return true;
934 }
935
936 static JSValueRef globalObject_call(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
937 {
938     UNUSED_PARAM(function);
939     UNUSED_PARAM(thisObject);
940     UNUSED_PARAM(argumentCount);
941     UNUSED_PARAM(arguments);
942     UNUSED_PARAM(exception);
943
944     return JSValueMakeNumber(ctx, 3);
945 }
946
947 static JSValueRef functionGC(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
948 {
949     UNUSED_PARAM(function);
950     UNUSED_PARAM(thisObject);
951     UNUSED_PARAM(argumentCount);
952     UNUSED_PARAM(arguments);
953     UNUSED_PARAM(exception);
954     JSGarbageCollect(context);
955     return JSValueMakeUndefined(context);
956 }
957
958 static JSStaticValue globalObject_staticValues[] = {
959     { "globalStaticValue", globalObject_get, globalObject_set, kJSPropertyAttributeNone },
960     { 0, 0, 0, 0 }
961 };
962
963 static JSStaticFunction globalObject_staticFunctions[] = {
964     { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone },
965     { "globalStaticFunction2", globalObject_call, kJSPropertyAttributeNone },
966     { "gc", functionGC, kJSPropertyAttributeNone },
967     { 0, 0, 0 }
968 };
969
970 static char* createStringWithContentsOfFile(const char* fileName);
971
972 static void testInitializeFinalize()
973 {
974     JSObjectRef o = JSObjectMake(context, Derived_class(context), (void*)1);
975     UNUSED_PARAM(o);
976     ASSERT(JSObjectGetPrivate(o) == (void*)3);
977 }
978
979 static JSValueRef jsNumberValue =  NULL;
980
981 static JSObjectRef aHeapRef = NULL;
982
983 static void makeGlobalNumberValue(JSContextRef context) {
984     JSValueRef v = JSValueMakeNumber(context, 420);
985     JSValueProtect(context, v);
986     jsNumberValue = v;
987     v = NULL;
988 }
989
990 bool assertTrue(bool value, const char* message)
991 {
992     if (!value) {
993         if (message)
994             fprintf(stderr, "assertTrue failed: '%s'\n", message);
995         else
996             fprintf(stderr, "assertTrue failed.\n");
997         failed = 1;
998     }
999     return value;
1000 }
1001
1002 static bool checkForCycleInPrototypeChain()
1003 {
1004     bool result = true;
1005     JSGlobalContextRef context = JSGlobalContextCreate(0);
1006     JSObjectRef object1 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
1007     JSObjectRef object2 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
1008     JSObjectRef object3 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
1009
1010     JSObjectSetPrototype(context, object1, JSValueMakeNull(context));
1011     ASSERT(JSValueIsNull(context, JSObjectGetPrototype(context, object1)));
1012
1013     // object1 -> object1
1014     JSObjectSetPrototype(context, object1, object1);
1015     result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to assign self as a prototype");
1016
1017     // object1 -> object2 -> object1
1018     JSObjectSetPrototype(context, object2, object1);
1019     ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object1));
1020     JSObjectSetPrototype(context, object1, object2);
1021     result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to close a prototype chain cycle");
1022
1023     // object1 -> object2 -> object3 -> object1
1024     JSObjectSetPrototype(context, object2, object3);
1025     ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object3));
1026     JSObjectSetPrototype(context, object1, object2);
1027     ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object1), object2));
1028     JSObjectSetPrototype(context, object3, object1);
1029     result &= assertTrue(!JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object3), object1), "It is possible to close a prototype chain cycle");
1030
1031     JSValueRef exception;
1032     JSStringRef code = JSStringCreateWithUTF8CString("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o");
1033     JSStringRef file = JSStringCreateWithUTF8CString("");
1034     result &= assertTrue(!JSEvaluateScript(context, code, /* thisObject*/ 0, file, 1, &exception)
1035                          , "An exception should be thrown");
1036
1037     JSStringRelease(code);
1038     JSStringRelease(file);
1039     JSGlobalContextRelease(context);
1040     return result;
1041 }
1042
1043 static JSValueRef valueToObjectExceptionCallAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
1044 {
1045     UNUSED_PARAM(function);
1046     UNUSED_PARAM(thisObject);
1047     UNUSED_PARAM(argumentCount);
1048     UNUSED_PARAM(arguments);
1049     JSValueRef jsUndefined = JSValueMakeUndefined(JSContextGetGlobalContext(ctx));
1050     JSValueToObject(JSContextGetGlobalContext(ctx), jsUndefined, exception);
1051     
1052     return JSValueMakeUndefined(ctx);
1053 }
1054 static bool valueToObjectExceptionTest()
1055 {
1056     JSGlobalContextRef testContext;
1057     JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty;
1058     globalObjectClassDefinition.initialize = globalObject_initialize;
1059     globalObjectClassDefinition.staticValues = globalObject_staticValues;
1060     globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions;
1061     globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
1062     JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition);
1063     testContext = JSGlobalContextCreateInGroup(NULL, globalObjectClass);
1064     JSObjectRef globalObject = JSContextGetGlobalObject(testContext);
1065
1066     JSStringRef valueToObject = JSStringCreateWithUTF8CString("valueToObject");
1067     JSObjectRef valueToObjectFunction = JSObjectMakeFunctionWithCallback(testContext, valueToObject, valueToObjectExceptionCallAsFunction);
1068     JSObjectSetProperty(testContext, globalObject, valueToObject, valueToObjectFunction, kJSPropertyAttributeNone, NULL);
1069     JSStringRelease(valueToObject);
1070
1071     JSStringRef test = JSStringCreateWithUTF8CString("valueToObject();");
1072     JSEvaluateScript(testContext, test, NULL, NULL, 1, NULL);
1073     
1074     JSStringRelease(test);
1075     JSClassRelease(globalObjectClass);
1076     JSGlobalContextRelease(testContext);
1077     
1078     return true;
1079 }
1080
1081 static bool globalContextNameTest()
1082 {
1083     bool result = true;
1084     JSGlobalContextRef context = JSGlobalContextCreate(0);
1085
1086     JSStringRef str = JSGlobalContextCopyName(context);
1087     result &= assertTrue(!str, "Default context name is NULL");
1088
1089     JSStringRef name1 = JSStringCreateWithUTF8CString("name1");
1090     JSStringRef name2 = JSStringCreateWithUTF8CString("name2");
1091
1092     JSGlobalContextSetName(context, name1);
1093     JSStringRef fetchName1 = JSGlobalContextCopyName(context);
1094     JSGlobalContextSetName(context, name2);
1095     JSStringRef fetchName2 = JSGlobalContextCopyName(context);
1096     JSGlobalContextSetName(context, NULL);
1097     JSStringRef fetchName3 = JSGlobalContextCopyName(context);
1098
1099     result &= assertTrue(JSStringIsEqual(name1, fetchName1), "Unexpected Context name");
1100     result &= assertTrue(JSStringIsEqual(name2, fetchName2), "Unexpected Context name");
1101     result &= assertTrue(!JSStringIsEqual(fetchName1, fetchName2), "Unexpected Context name");
1102     result &= assertTrue(!fetchName3, "Unexpected Context name");
1103
1104     JSStringRelease(name1);
1105     JSStringRelease(name2);
1106     JSStringRelease(fetchName1);
1107     JSStringRelease(fetchName2);
1108
1109     return result;
1110 }
1111
1112 static void checkConstnessInJSObjectNames()
1113 {
1114     JSStaticFunction fun;
1115     fun.name = "something";
1116     JSStaticValue val;
1117     val.name = "something";
1118 }
1119
1120 #ifdef __cplusplus
1121 extern "C" {
1122 #endif
1123 void JSSynchronousGarbageCollectForDebugging(JSContextRef);
1124 #ifdef __cplusplus
1125 }
1126 #endif
1127
1128 static const unsigned numWeakRefs = 10000;
1129
1130 static void markingConstraint(JSMarkerRef marker, void *userData)
1131 {
1132     JSWeakRef *weakRefs;
1133     unsigned i;
1134     
1135     weakRefs = (JSWeakRef*)userData;
1136     
1137     for (i = 0; i < numWeakRefs; i += 2) {
1138         JSObjectRef object = JSWeakGetObject(weakRefs[i]);
1139         marker->Mark(marker, object);
1140         assertTrue(marker->IsMarked(marker, object), "A marked object is marked");
1141     }
1142 }
1143
1144 static void testMarkingConstraints(void)
1145 {
1146     JSContextGroupRef group;
1147     JSContextRef context;
1148     JSWeakRef *weakRefs;
1149     unsigned i;
1150     unsigned deadCount;
1151     
1152     printf("Testing Marking Constraints.\n");
1153     
1154     group = JSContextGroupCreate();
1155     context = JSGlobalContextCreateInGroup(group, NULL);
1156
1157     weakRefs = (JSWeakRef*)calloc(numWeakRefs, sizeof(JSWeakRef));
1158
1159     JSContextGroupAddMarkingConstraint(group, markingConstraint, weakRefs);
1160     
1161     for (i = numWeakRefs; i--;)
1162         weakRefs[i] = JSWeakCreate(context, JSObjectMakeArray(context, 0, NULL, NULL));
1163     
1164     JSSynchronousGarbageCollectForDebugging(context);
1165     
1166     deadCount = 0;
1167     for (i = 0; i < numWeakRefs; i += 2) {
1168         assertTrue(JSWeakGetObject(weakRefs[i]), "Marked objects stayed alive");
1169         if (!JSWeakGetObject(weakRefs[i + 1]))
1170             deadCount++;
1171     }
1172     
1173     assertTrue(deadCount != 0, "At least some objects died");
1174     
1175     for (i = numWeakRefs; i--;)
1176         JSWeakRelease(context, weakRefs[i]);
1177     
1178     JSContextGroupRelease(group);
1179
1180     printf("PASS: Marking Constraints.\n");
1181 }
1182
1183 int main(int argc, char* argv[])
1184 {
1185 #if OS(WINDOWS)
1186     // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
1187     // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
1188     // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
1189     ::SetErrorMode(0);
1190 #endif
1191
1192     testCompareAndSwap();
1193
1194 #if JSC_OBJC_API_ENABLED
1195     testObjectiveCAPI();
1196 #endif
1197
1198     const char *scriptPath = "testapi.js";
1199     if (argc > 1) {
1200         scriptPath = argv[1];
1201     }
1202     
1203     // Test garbage collection with a fresh context
1204     context = JSGlobalContextCreateInGroup(NULL, NULL);
1205     TestInitializeFinalize = true;
1206     testInitializeFinalize();
1207     JSGlobalContextRelease(context);
1208     TestInitializeFinalize = false;
1209
1210     ASSERT(Base_didFinalize);
1211
1212     testMarkingConstraints();
1213
1214     JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty;
1215     globalObjectClassDefinition.initialize = globalObject_initialize;
1216     globalObjectClassDefinition.staticValues = globalObject_staticValues;
1217     globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions;
1218     globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
1219     JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition);
1220     context = JSGlobalContextCreateInGroup(NULL, globalObjectClass);
1221
1222     JSContextGroupRef contextGroup = JSContextGetGroup(context);
1223     
1224     JSGlobalContextRetain(context);
1225     JSGlobalContextRelease(context);
1226     ASSERT(JSContextGetGlobalContext(context) == context);
1227     
1228     JSReportExtraMemoryCost(context, 0);
1229     JSReportExtraMemoryCost(context, 1);
1230     JSReportExtraMemoryCost(context, 1024);
1231
1232     JSObjectRef globalObject = JSContextGetGlobalObject(context);
1233     ASSERT(JSValueIsObject(context, globalObject));
1234     
1235     JSValueRef jsUndefined = JSValueMakeUndefined(context);
1236     JSValueRef jsNull = JSValueMakeNull(context);
1237     JSValueRef jsTrue = JSValueMakeBoolean(context, true);
1238     JSValueRef jsFalse = JSValueMakeBoolean(context, false);
1239     JSValueRef jsZero = JSValueMakeNumber(context, 0);
1240     JSValueRef jsOne = JSValueMakeNumber(context, 1);
1241     JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0);
1242     JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, NULL);
1243     JSObjectSetPrototype(context, jsObjectNoProto, JSValueMakeNull(context));
1244
1245     JSObjectSetPrivate(globalObject, (void*)123);
1246     if (JSObjectGetPrivate(globalObject) != (void*)123) {
1247         printf("FAIL: Didn't return private data when set by JSObjectSetPrivate().\n");
1248         failed = 1;
1249     } else
1250         printf("PASS: returned private data when set by JSObjectSetPrivate().\n");
1251
1252     // FIXME: test funny utf8 characters
1253     JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString("");
1254     JSValueRef jsEmptyString = JSValueMakeString(context, jsEmptyIString);
1255     
1256     JSStringRef jsOneIString = JSStringCreateWithUTF8CString("1");
1257     JSValueRef jsOneString = JSValueMakeString(context, jsOneIString);
1258
1259     UniChar singleUniChar = 65; // Capital A
1260     CFMutableStringRef cfString = 
1261         CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault,
1262                                                           &singleUniChar,
1263                                                           1,
1264                                                           1,
1265                                                           kCFAllocatorNull);
1266
1267     JSStringRef jsCFIString = JSStringCreateWithCFString(cfString);
1268     JSValueRef jsCFString = JSValueMakeString(context, jsCFIString);
1269     
1270     CFStringRef cfEmptyString = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8);
1271     
1272     JSStringRef jsCFEmptyIString = JSStringCreateWithCFString(cfEmptyString);
1273     JSValueRef jsCFEmptyString = JSValueMakeString(context, jsCFEmptyIString);
1274
1275     CFIndex cfStringLength = CFStringGetLength(cfString);
1276     UniChar* buffer = (UniChar*)malloc(cfStringLength * sizeof(UniChar));
1277     CFStringGetCharacters(cfString, 
1278                           CFRangeMake(0, cfStringLength), 
1279                           buffer);
1280     JSStringRef jsCFIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, cfStringLength);
1281     JSValueRef jsCFStringWithCharacters = JSValueMakeString(context, jsCFIStringWithCharacters);
1282     
1283     JSStringRef jsCFEmptyIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, CFStringGetLength(cfEmptyString));
1284     free(buffer);
1285     JSValueRef jsCFEmptyStringWithCharacters = JSValueMakeString(context, jsCFEmptyIStringWithCharacters);
1286
1287     JSChar constantString[] = { 'H', 'e', 'l', 'l', 'o', };
1288     JSStringRef constantStringRef = JSStringCreateWithCharactersNoCopy(constantString, sizeof(constantString) / sizeof(constantString[0]));
1289     ASSERT(JSStringGetCharactersPtr(constantStringRef) == constantString);
1290     JSStringRelease(constantStringRef);
1291
1292     ASSERT(JSValueGetType(context, NULL) == kJSTypeNull);
1293     ASSERT(JSValueGetType(context, jsUndefined) == kJSTypeUndefined);
1294     ASSERT(JSValueGetType(context, jsNull) == kJSTypeNull);
1295     ASSERT(JSValueGetType(context, jsTrue) == kJSTypeBoolean);
1296     ASSERT(JSValueGetType(context, jsFalse) == kJSTypeBoolean);
1297     ASSERT(JSValueGetType(context, jsZero) == kJSTypeNumber);
1298     ASSERT(JSValueGetType(context, jsOne) == kJSTypeNumber);
1299     ASSERT(JSValueGetType(context, jsOneThird) == kJSTypeNumber);
1300     ASSERT(JSValueGetType(context, jsEmptyString) == kJSTypeString);
1301     ASSERT(JSValueGetType(context, jsOneString) == kJSTypeString);
1302     ASSERT(JSValueGetType(context, jsCFString) == kJSTypeString);
1303     ASSERT(JSValueGetType(context, jsCFStringWithCharacters) == kJSTypeString);
1304     ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString);
1305     ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);
1306
1307     ASSERT(!JSValueIsBoolean(context, NULL));
1308     ASSERT(!JSValueIsObject(context, NULL));
1309     ASSERT(!JSValueIsArray(context, NULL));
1310     ASSERT(!JSValueIsDate(context, NULL));
1311     ASSERT(!JSValueIsString(context, NULL));
1312     ASSERT(!JSValueIsNumber(context, NULL));
1313     ASSERT(!JSValueIsUndefined(context, NULL));
1314     ASSERT(JSValueIsNull(context, NULL));
1315     ASSERT(!JSObjectCallAsFunction(context, NULL, NULL, 0, NULL, NULL));
1316     ASSERT(!JSObjectCallAsConstructor(context, NULL, 0, NULL, NULL));
1317     ASSERT(!JSObjectIsConstructor(context, NULL));
1318     ASSERT(!JSObjectIsFunction(context, NULL));
1319
1320     JSStringRef nullString = JSStringCreateWithUTF8CString(0);
1321     const JSChar* characters = JSStringGetCharactersPtr(nullString);
1322     if (characters) {
1323         printf("FAIL: Didn't return null when accessing character pointer of a null String.\n");
1324         failed = 1;
1325     } else
1326         printf("PASS: returned null when accessing character pointer of a null String.\n");
1327
1328     JSStringRef emptyString = JSStringCreateWithCFString(CFSTR(""));
1329     characters = JSStringGetCharactersPtr(emptyString);
1330     if (!characters) {
1331         printf("FAIL: Returned null when accessing character pointer of an empty String.\n");
1332         failed = 1;
1333     } else
1334         printf("PASS: returned empty when accessing character pointer of an empty String.\n");
1335
1336     size_t length = JSStringGetLength(nullString);
1337     if (length) {
1338         printf("FAIL: Didn't return 0 length for null String.\n");
1339         failed = 1;
1340     } else
1341         printf("PASS: returned 0 length for null String.\n");
1342     JSStringRelease(nullString);
1343
1344     length = JSStringGetLength(emptyString);
1345     if (length) {
1346         printf("FAIL: Didn't return 0 length for empty String.\n");
1347         failed = 1;
1348     } else
1349         printf("PASS: returned 0 length for empty String.\n");
1350     JSStringRelease(emptyString);
1351
1352     JSObjectRef propertyCatchalls = JSObjectMake(context, PropertyCatchalls_class(context), NULL);
1353     JSStringRef propertyCatchallsString = JSStringCreateWithUTF8CString("PropertyCatchalls");
1354     JSObjectSetProperty(context, globalObject, propertyCatchallsString, propertyCatchalls, kJSPropertyAttributeNone, NULL);
1355     JSStringRelease(propertyCatchallsString);
1356
1357     JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
1358     JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
1359     JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
1360     JSStringRelease(myObjectIString);
1361     
1362     JSObjectRef EvilExceptionObject = JSObjectMake(context, EvilExceptionObject_class(context), NULL);
1363     JSStringRef EvilExceptionObjectIString = JSStringCreateWithUTF8CString("EvilExceptionObject");
1364     JSObjectSetProperty(context, globalObject, EvilExceptionObjectIString, EvilExceptionObject, kJSPropertyAttributeNone, NULL);
1365     JSStringRelease(EvilExceptionObjectIString);
1366     
1367     JSObjectRef EmptyObject = JSObjectMake(context, EmptyObject_class(context), NULL);
1368     JSStringRef EmptyObjectIString = JSStringCreateWithUTF8CString("EmptyObject");
1369     JSObjectSetProperty(context, globalObject, EmptyObjectIString, EmptyObject, kJSPropertyAttributeNone, NULL);
1370     JSStringRelease(EmptyObjectIString);
1371     
1372     JSStringRef lengthStr = JSStringCreateWithUTF8CString("length");
1373     JSObjectRef aStackRef = JSObjectMakeArray(context, 0, 0, 0);
1374     aHeapRef = aStackRef;
1375     JSObjectSetProperty(context, aHeapRef, lengthStr, JSValueMakeNumber(context, 10), 0, 0);
1376     JSStringRef privatePropertyName = JSStringCreateWithUTF8CString("privateProperty");
1377     if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, aHeapRef)) {
1378         printf("FAIL: Could not set private property.\n");
1379         failed = 1;
1380     } else
1381         printf("PASS: Set private property.\n");
1382     aStackRef = 0;
1383     if (JSObjectSetPrivateProperty(context, aHeapRef, privatePropertyName, aHeapRef)) {
1384         printf("FAIL: JSObjectSetPrivateProperty should fail on non-API objects.\n");
1385         failed = 1;
1386     } else
1387         printf("PASS: Did not allow JSObjectSetPrivateProperty on a non-API object.\n");
1388     if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName) != aHeapRef) {
1389         printf("FAIL: Could not retrieve private property.\n");
1390         failed = 1;
1391     } else
1392         printf("PASS: Retrieved private property.\n");
1393     if (JSObjectGetPrivateProperty(context, aHeapRef, privatePropertyName)) {
1394         printf("FAIL: JSObjectGetPrivateProperty should return NULL when called on a non-API object.\n");
1395         failed = 1;
1396     } else
1397         printf("PASS: JSObjectGetPrivateProperty return NULL.\n");
1398
1399     if (JSObjectGetProperty(context, myObject, privatePropertyName, 0) == aHeapRef) {
1400         printf("FAIL: Accessed private property through ordinary property lookup.\n");
1401         failed = 1;
1402     } else
1403         printf("PASS: Cannot access private property through ordinary property lookup.\n");
1404
1405     JSGarbageCollect(context);
1406
1407     for (int i = 0; i < 10000; i++)
1408         JSObjectMake(context, 0, 0);
1409
1410     aHeapRef = JSValueToObject(context, JSObjectGetPrivateProperty(context, myObject, privatePropertyName), 0);
1411     if (JSValueToNumber(context, JSObjectGetProperty(context, aHeapRef, lengthStr, 0), 0) != 10) {
1412         printf("FAIL: Private property has been collected.\n");
1413         failed = 1;
1414     } else
1415         printf("PASS: Private property does not appear to have been collected.\n");
1416     JSStringRelease(lengthStr);
1417
1418     if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, 0)) {
1419         printf("FAIL: Could not set private property to NULL.\n");
1420         failed = 1;
1421     } else
1422         printf("PASS: Set private property to NULL.\n");
1423     if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName)) {
1424         printf("FAIL: Could not retrieve private property.\n");
1425         failed = 1;
1426     } else
1427         printf("PASS: Retrieved private property.\n");
1428
1429     JSStringRef nullJSON = JSStringCreateWithUTF8CString(0);
1430     JSValueRef nullJSONObject = JSValueMakeFromJSONString(context, nullJSON);
1431     if (nullJSONObject) {
1432         printf("FAIL: Did not parse null String as JSON correctly\n");
1433         failed = 1;
1434     } else
1435         printf("PASS: Parsed null String as JSON correctly.\n");
1436     JSStringRelease(nullJSON);
1437
1438     JSStringRef validJSON = JSStringCreateWithUTF8CString("{\"aProperty\":true}");
1439     JSValueRef jsonObject = JSValueMakeFromJSONString(context, validJSON);
1440     JSStringRelease(validJSON);
1441     if (!JSValueIsObject(context, jsonObject)) {
1442         printf("FAIL: Did not parse valid JSON correctly\n");
1443         failed = 1;
1444     } else
1445         printf("PASS: Parsed valid JSON string.\n");
1446     JSStringRef propertyName = JSStringCreateWithUTF8CString("aProperty");
1447     assertEqualsAsBoolean(JSObjectGetProperty(context, JSValueToObject(context, jsonObject, 0), propertyName, 0), true);
1448     JSStringRelease(propertyName);
1449     JSStringRef invalidJSON = JSStringCreateWithUTF8CString("fail!");
1450     if (JSValueMakeFromJSONString(context, invalidJSON)) {
1451         printf("FAIL: Should return null for invalid JSON data\n");
1452         failed = 1;
1453     } else
1454         printf("PASS: Correctly returned null for invalid JSON data.\n");
1455     JSValueRef exception;
1456     JSStringRef str = JSValueCreateJSONString(context, jsonObject, 0, 0);
1457     if (!JSStringIsEqualToUTF8CString(str, "{\"aProperty\":true}")) {
1458         printf("FAIL: Did not correctly serialise with indent of 0.\n");
1459         failed = 1;
1460     } else
1461         printf("PASS: Correctly serialised with indent of 0.\n");
1462     JSStringRelease(str);
1463
1464     str = JSValueCreateJSONString(context, jsonObject, 4, 0);
1465     if (!JSStringIsEqualToUTF8CString(str, "{\n    \"aProperty\": true\n}")) {
1466         printf("FAIL: Did not correctly serialise with indent of 4.\n");
1467         failed = 1;
1468     } else
1469         printf("PASS: Correctly serialised with indent of 4.\n");
1470     JSStringRelease(str);
1471
1472     str = JSStringCreateWithUTF8CString("({get a(){ throw '';}})");
1473     JSValueRef unstringifiableObj = JSEvaluateScript(context, str, NULL, NULL, 1, NULL);
1474     JSStringRelease(str);
1475     
1476     str = JSValueCreateJSONString(context, unstringifiableObj, 4, 0);
1477     if (str) {
1478         printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
1479         JSStringRelease(str);
1480         failed = 1;
1481     } else
1482         printf("PASS: returned null when attempting to serialize unserializable value.\n");
1483     
1484     str = JSValueCreateJSONString(context, unstringifiableObj, 4, &exception);
1485     if (str) {
1486         printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
1487         JSStringRelease(str);
1488         failed = 1;
1489     } else
1490         printf("PASS: returned null when attempting to serialize unserializable value.\n");
1491     if (!exception) {
1492         printf("FAIL: Did not set exception on serialisation error\n");
1493         failed = 1;
1494     } else
1495         printf("PASS: set exception on serialisation error\n");
1496     // Conversions that throw exceptions
1497     exception = NULL;
1498     ASSERT(NULL == JSValueToObject(context, jsNull, &exception));
1499     ASSERT(exception);
1500     
1501     exception = NULL;
1502     // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
1503     // causing a build break with -Wshorten-64-to-32 enabled.  The issue is known by the appropriate team.
1504     // After that's resolved, we can remove these casts
1505     ASSERT(isnan((float)JSValueToNumber(context, jsObjectNoProto, &exception)));
1506     ASSERT(exception);
1507
1508     exception = NULL;
1509     ASSERT(!JSValueToStringCopy(context, jsObjectNoProto, &exception));
1510     ASSERT(exception);
1511     
1512     ASSERT(JSValueToBoolean(context, myObject));
1513     
1514     exception = NULL;
1515     ASSERT(!JSValueIsEqual(context, jsObjectNoProto, JSValueMakeNumber(context, 1), &exception));
1516     ASSERT(exception);
1517     
1518     exception = NULL;
1519     JSObjectGetPropertyAtIndex(context, myObject, 0, &exception);
1520     ASSERT(1 == JSValueToNumber(context, exception, NULL));
1521
1522     assertEqualsAsBoolean(jsUndefined, false);
1523     assertEqualsAsBoolean(jsNull, false);
1524     assertEqualsAsBoolean(jsTrue, true);
1525     assertEqualsAsBoolean(jsFalse, false);
1526     assertEqualsAsBoolean(jsZero, false);
1527     assertEqualsAsBoolean(jsOne, true);
1528     assertEqualsAsBoolean(jsOneThird, true);
1529     assertEqualsAsBoolean(jsEmptyString, false);
1530     assertEqualsAsBoolean(jsOneString, true);
1531     assertEqualsAsBoolean(jsCFString, true);
1532     assertEqualsAsBoolean(jsCFStringWithCharacters, true);
1533     assertEqualsAsBoolean(jsCFEmptyString, false);
1534     assertEqualsAsBoolean(jsCFEmptyStringWithCharacters, false);
1535     
1536     assertEqualsAsNumber(jsUndefined, nan(""));
1537     assertEqualsAsNumber(jsNull, 0);
1538     assertEqualsAsNumber(jsTrue, 1);
1539     assertEqualsAsNumber(jsFalse, 0);
1540     assertEqualsAsNumber(jsZero, 0);
1541     assertEqualsAsNumber(jsOne, 1);
1542     assertEqualsAsNumber(jsOneThird, 1.0 / 3.0);
1543     assertEqualsAsNumber(jsEmptyString, 0);
1544     assertEqualsAsNumber(jsOneString, 1);
1545     assertEqualsAsNumber(jsCFString, nan(""));
1546     assertEqualsAsNumber(jsCFStringWithCharacters, nan(""));
1547     assertEqualsAsNumber(jsCFEmptyString, 0);
1548     assertEqualsAsNumber(jsCFEmptyStringWithCharacters, 0);
1549     ASSERT(sizeof(JSChar) == sizeof(UniChar));
1550     
1551     assertEqualsAsCharactersPtr(jsUndefined, "undefined");
1552     assertEqualsAsCharactersPtr(jsNull, "null");
1553     assertEqualsAsCharactersPtr(jsTrue, "true");
1554     assertEqualsAsCharactersPtr(jsFalse, "false");
1555     assertEqualsAsCharactersPtr(jsZero, "0");
1556     assertEqualsAsCharactersPtr(jsOne, "1");
1557     assertEqualsAsCharactersPtr(jsOneThird, "0.3333333333333333");
1558     assertEqualsAsCharactersPtr(jsEmptyString, "");
1559     assertEqualsAsCharactersPtr(jsOneString, "1");
1560     assertEqualsAsCharactersPtr(jsCFString, "A");
1561     assertEqualsAsCharactersPtr(jsCFStringWithCharacters, "A");
1562     assertEqualsAsCharactersPtr(jsCFEmptyString, "");
1563     assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters, "");
1564     
1565     assertEqualsAsUTF8String(jsUndefined, "undefined");
1566     assertEqualsAsUTF8String(jsNull, "null");
1567     assertEqualsAsUTF8String(jsTrue, "true");
1568     assertEqualsAsUTF8String(jsFalse, "false");
1569     assertEqualsAsUTF8String(jsZero, "0");
1570     assertEqualsAsUTF8String(jsOne, "1");
1571     assertEqualsAsUTF8String(jsOneThird, "0.3333333333333333");
1572     assertEqualsAsUTF8String(jsEmptyString, "");
1573     assertEqualsAsUTF8String(jsOneString, "1");
1574     assertEqualsAsUTF8String(jsCFString, "A");
1575     assertEqualsAsUTF8String(jsCFStringWithCharacters, "A");
1576     assertEqualsAsUTF8String(jsCFEmptyString, "");
1577     assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters, "");
1578     
1579     checkConstnessInJSObjectNames();
1580     
1581     ASSERT(JSValueIsStrictEqual(context, jsTrue, jsTrue));
1582     ASSERT(!JSValueIsStrictEqual(context, jsOne, jsOneString));
1583
1584     ASSERT(JSValueIsEqual(context, jsOne, jsOneString, NULL));
1585     ASSERT(!JSValueIsEqual(context, jsTrue, jsFalse, NULL));
1586     
1587     CFStringRef cfJSString = JSStringCopyCFString(kCFAllocatorDefault, jsCFIString);
1588     CFStringRef cfJSEmptyString = JSStringCopyCFString(kCFAllocatorDefault, jsCFEmptyIString);
1589     ASSERT(CFEqual(cfJSString, cfString));
1590     ASSERT(CFEqual(cfJSEmptyString, cfEmptyString));
1591     CFRelease(cfJSString);
1592     CFRelease(cfJSEmptyString);
1593
1594     CFRelease(cfString);
1595     CFRelease(cfEmptyString);
1596     
1597     jsGlobalValue = JSObjectMake(context, NULL, NULL);
1598     makeGlobalNumberValue(context);
1599     JSValueProtect(context, jsGlobalValue);
1600     JSGarbageCollect(context);
1601     ASSERT(JSValueIsObject(context, jsGlobalValue));
1602     JSValueUnprotect(context, jsGlobalValue);
1603     JSValueUnprotect(context, jsNumberValue);
1604
1605     JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;");
1606     const char* badSyntaxConstant = "x := 1;";
1607     JSStringRef badSyntax = JSStringCreateWithUTF8CString(badSyntaxConstant);
1608     ASSERT(JSCheckScriptSyntax(context, goodSyntax, NULL, 0, NULL));
1609     ASSERT(!JSCheckScriptSyntax(context, badSyntax, NULL, 0, NULL));
1610     ASSERT(!JSScriptCreateFromString(contextGroup, 0, 0, badSyntax, 0, 0));
1611     ASSERT(!JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, badSyntaxConstant, strlen(badSyntaxConstant), 0, 0));
1612
1613     JSValueRef result;
1614     JSValueRef v;
1615     JSObjectRef o;
1616     JSStringRef string;
1617
1618     result = JSEvaluateScript(context, goodSyntax, NULL, NULL, 1, NULL);
1619     ASSERT(result);
1620     ASSERT(JSValueIsEqual(context, result, jsOne, NULL));
1621
1622     exception = NULL;
1623     result = JSEvaluateScript(context, badSyntax, NULL, NULL, 1, &exception);
1624     ASSERT(!result);
1625     ASSERT(JSValueIsObject(context, exception));
1626     
1627     JSStringRef array = JSStringCreateWithUTF8CString("Array");
1628     JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
1629     JSStringRelease(array);
1630     result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL);
1631     ASSERT(result);
1632     ASSERT(JSValueIsObject(context, result));
1633     ASSERT(JSValueIsInstanceOfConstructor(context, result, arrayConstructor, NULL));
1634     ASSERT(!JSValueIsInstanceOfConstructor(context, JSValueMakeNull(context), arrayConstructor, NULL));
1635
1636     o = JSValueToObject(context, result, NULL);
1637     exception = NULL;
1638     ASSERT(JSValueIsUndefined(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception)));
1639     ASSERT(!exception);
1640     
1641     JSObjectSetPropertyAtIndex(context, o, 0, JSValueMakeNumber(context, 1), &exception);
1642     ASSERT(!exception);
1643     
1644     exception = NULL;
1645     ASSERT(1 == JSValueToNumber(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception), &exception));
1646     ASSERT(!exception);
1647
1648     JSStringRef functionBody;
1649     JSObjectRef function;
1650     
1651     exception = NULL;
1652     functionBody = JSStringCreateWithUTF8CString("rreturn Array;");
1653     JSStringRef line = JSStringCreateWithUTF8CString("line");
1654     ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception));
1655     ASSERT(JSValueIsObject(context, exception));
1656     v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL);
1657     assertEqualsAsNumber(v, 2);
1658     JSStringRelease(functionBody);
1659     JSStringRelease(line);
1660
1661     exception = NULL;
1662     functionBody = JSStringCreateWithUTF8CString("rreturn Array;");
1663     line = JSStringCreateWithUTF8CString("line");
1664     ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, -42, &exception));
1665     ASSERT(JSValueIsObject(context, exception));
1666     v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL);
1667     assertEqualsAsNumber(v, 2);
1668     JSStringRelease(functionBody);
1669     JSStringRelease(line);
1670
1671     exception = NULL;
1672     functionBody = JSStringCreateWithUTF8CString("// Line one.\nrreturn Array;");
1673     line = JSStringCreateWithUTF8CString("line");
1674     ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception));
1675     ASSERT(JSValueIsObject(context, exception));
1676     v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL);
1677     assertEqualsAsNumber(v, 3);
1678     JSStringRelease(functionBody);
1679     JSStringRelease(line);
1680
1681     exception = NULL;
1682     functionBody = JSStringCreateWithUTF8CString("return Array;");
1683     function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception);
1684     JSStringRelease(functionBody);
1685     ASSERT(!exception);
1686     ASSERT(JSObjectIsFunction(context, function));
1687     v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1688     ASSERT(v);
1689     ASSERT(JSValueIsEqual(context, v, arrayConstructor, NULL));
1690     
1691     exception = NULL;
1692     function = JSObjectMakeFunction(context, NULL, 0, NULL, jsEmptyIString, NULL, 0, &exception);
1693     ASSERT(!exception);
1694     v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, &exception);
1695     ASSERT(v && !exception);
1696     ASSERT(JSValueIsUndefined(context, v));
1697     
1698     exception = NULL;
1699     v = NULL;
1700     JSStringRef foo = JSStringCreateWithUTF8CString("foo");
1701     JSStringRef argumentNames[] = { foo };
1702     functionBody = JSStringCreateWithUTF8CString("return foo;");
1703     function = JSObjectMakeFunction(context, foo, 1, argumentNames, functionBody, NULL, 1, &exception);
1704     ASSERT(function && !exception);
1705     JSValueRef arguments[] = { JSValueMakeNumber(context, 2) };
1706     JSObjectCallAsFunction(context, function, NULL, 1, arguments, &exception);
1707     JSStringRelease(foo);
1708     JSStringRelease(functionBody);
1709     
1710     string = JSValueToStringCopy(context, function, NULL);
1711     assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) {\nreturn foo;\n}");
1712     JSStringRelease(string);
1713
1714     JSStringRef print = JSStringCreateWithUTF8CString("print");
1715     JSObjectRef printFunction = JSObjectMakeFunctionWithCallback(context, print, print_callAsFunction);
1716     JSObjectSetProperty(context, globalObject, print, printFunction, kJSPropertyAttributeNone, NULL); 
1717     JSStringRelease(print);
1718     
1719     ASSERT(!JSObjectSetPrivate(printFunction, (void*)1));
1720     ASSERT(!JSObjectGetPrivate(printFunction));
1721
1722     JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor");
1723     JSObjectRef myConstructor = JSObjectMakeConstructor(context, NULL, myConstructor_callAsConstructor);
1724     JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL);
1725     JSStringRelease(myConstructorIString);
1726     
1727     JSStringRef myBadConstructorIString = JSStringCreateWithUTF8CString("MyBadConstructor");
1728     JSObjectRef myBadConstructor = JSObjectMakeConstructor(context, NULL, myBadConstructor_callAsConstructor);
1729     JSObjectSetProperty(context, globalObject, myBadConstructorIString, myBadConstructor, kJSPropertyAttributeNone, NULL);
1730     JSStringRelease(myBadConstructorIString);
1731     
1732     ASSERT(!JSObjectSetPrivate(myConstructor, (void*)1));
1733     ASSERT(!JSObjectGetPrivate(myConstructor));
1734     
1735     string = JSStringCreateWithUTF8CString("Base");
1736     JSObjectRef baseConstructor = JSObjectMakeConstructor(context, Base_class(context), NULL);
1737     JSObjectSetProperty(context, globalObject, string, baseConstructor, kJSPropertyAttributeNone, NULL);
1738     JSStringRelease(string);
1739     
1740     string = JSStringCreateWithUTF8CString("Derived");
1741     JSObjectRef derivedConstructor = JSObjectMakeConstructor(context, Derived_class(context), NULL);
1742     JSObjectSetProperty(context, globalObject, string, derivedConstructor, kJSPropertyAttributeNone, NULL);
1743     JSStringRelease(string);
1744     
1745     string = JSStringCreateWithUTF8CString("Derived2");
1746     JSObjectRef derived2Constructor = JSObjectMakeConstructor(context, Derived2_class(context), NULL);
1747     JSObjectSetProperty(context, globalObject, string, derived2Constructor, kJSPropertyAttributeNone, NULL);
1748     JSStringRelease(string);
1749
1750     o = JSObjectMake(context, NULL, NULL);
1751     JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL);
1752     JSObjectSetProperty(context, o, jsCFIString,  JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL);
1753     JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o);
1754     size_t expectedCount = JSPropertyNameArrayGetCount(nameArray);
1755     size_t count;
1756     for (count = 0; count < expectedCount; ++count)
1757         JSPropertyNameArrayGetNameAtIndex(nameArray, count);
1758     JSPropertyNameArrayRelease(nameArray);
1759     ASSERT(count == 1); // jsCFString should not be enumerated
1760
1761     JSValueRef argumentsArrayValues[] = { JSValueMakeNumber(context, 10), JSValueMakeNumber(context, 20) };
1762     o = JSObjectMakeArray(context, sizeof(argumentsArrayValues) / sizeof(JSValueRef), argumentsArrayValues, NULL);
1763     string = JSStringCreateWithUTF8CString("length");
1764     v = JSObjectGetProperty(context, o, string, NULL);
1765     assertEqualsAsNumber(v, 2);
1766     v = JSObjectGetPropertyAtIndex(context, o, 0, NULL);
1767     assertEqualsAsNumber(v, 10);
1768     v = JSObjectGetPropertyAtIndex(context, o, 1, NULL);
1769     assertEqualsAsNumber(v, 20);
1770
1771     o = JSObjectMakeArray(context, 0, NULL, NULL);
1772     v = JSObjectGetProperty(context, o, string, NULL);
1773     assertEqualsAsNumber(v, 0);
1774     JSStringRelease(string);
1775
1776     JSValueRef argumentsDateValues[] = { JSValueMakeNumber(context, 0) };
1777     o = JSObjectMakeDate(context, 1, argumentsDateValues, NULL);
1778     if (timeZoneIsPST())
1779         assertEqualsAsUTF8String(o, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)");
1780
1781     string = JSStringCreateWithUTF8CString("an error message");
1782     JSValueRef argumentsErrorValues[] = { JSValueMakeString(context, string) };
1783     o = JSObjectMakeError(context, 1, argumentsErrorValues, NULL);
1784     assertEqualsAsUTF8String(o, "Error: an error message");
1785     JSStringRelease(string);
1786
1787     string = JSStringCreateWithUTF8CString("foo");
1788     JSStringRef string2 = JSStringCreateWithUTF8CString("gi");
1789     JSValueRef argumentsRegExpValues[] = { JSValueMakeString(context, string), JSValueMakeString(context, string2) };
1790     o = JSObjectMakeRegExp(context, 2, argumentsRegExpValues, NULL);
1791     assertEqualsAsUTF8String(o, "/foo/gi");
1792     JSStringRelease(string);
1793     JSStringRelease(string2);
1794
1795     JSClassDefinition nullDefinition = kJSClassDefinitionEmpty;
1796     nullDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
1797     JSClassRef nullClass = JSClassCreate(&nullDefinition);
1798     JSClassRelease(nullClass);
1799     
1800     nullDefinition = kJSClassDefinitionEmpty;
1801     nullClass = JSClassCreate(&nullDefinition);
1802     JSClassRelease(nullClass);
1803
1804     functionBody = JSStringCreateWithUTF8CString("return this;");
1805     function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
1806     JSStringRelease(functionBody);
1807     v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1808     ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1809     v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
1810     ASSERT(JSValueIsEqual(context, v, o, NULL));
1811
1812     functionBody = JSStringCreateWithUTF8CString("return eval(\"this\");");
1813     function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
1814     JSStringRelease(functionBody);
1815     v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1816     ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1817     v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
1818     ASSERT(JSValueIsEqual(context, v, o, NULL));
1819
1820     const char* thisScript = "this;";
1821     JSStringRef script = JSStringCreateWithUTF8CString(thisScript);
1822     v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
1823     ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1824     v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
1825     ASSERT(JSValueIsEqual(context, v, o, NULL));
1826     JSStringRelease(script);
1827
1828     JSScriptRef scriptObject = JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, thisScript, strlen(thisScript), 0, 0);
1829     v = JSScriptEvaluate(context, scriptObject, NULL, NULL);
1830     ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1831     v = JSScriptEvaluate(context, scriptObject, o, NULL);
1832     ASSERT(JSValueIsEqual(context, v, o, NULL));
1833     JSScriptRelease(scriptObject);
1834
1835     script = JSStringCreateWithUTF8CString("eval(this);");
1836     v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
1837     ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1838     v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
1839     ASSERT(JSValueIsEqual(context, v, o, NULL));
1840     JSStringRelease(script);
1841
1842     script = JSStringCreateWithUTF8CString("[ ]");
1843     v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
1844     ASSERT(JSValueIsArray(context, v));
1845     JSStringRelease(script);
1846
1847     script = JSStringCreateWithUTF8CString("new Date");
1848     v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
1849     ASSERT(JSValueIsDate(context, v));
1850     JSStringRelease(script);
1851
1852     exception = NULL;
1853     script = JSStringCreateWithUTF8CString("rreturn Array;");
1854     JSStringRef sourceURL = JSStringCreateWithUTF8CString("file:///foo/bar.js");
1855     JSStringRef sourceURLKey = JSStringCreateWithUTF8CString("sourceURL");
1856     JSEvaluateScript(context, script, NULL, sourceURL, 1, &exception);
1857     ASSERT(exception);
1858     v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), sourceURLKey, NULL);
1859     assertEqualsAsUTF8String(v, "file:///foo/bar.js");
1860     JSStringRelease(script);
1861     JSStringRelease(sourceURL);
1862     JSStringRelease(sourceURLKey);
1863
1864     // Verify that creating a constructor for a class with no static functions does not trigger
1865     // an assert inside putDirect or lead to a crash during GC. <https://bugs.webkit.org/show_bug.cgi?id=25785>
1866     nullDefinition = kJSClassDefinitionEmpty;
1867     nullClass = JSClassCreate(&nullDefinition);
1868     JSObjectMakeConstructor(context, nullClass, 0);
1869     JSClassRelease(nullClass);
1870
1871     char* scriptUTF8 = createStringWithContentsOfFile(scriptPath);
1872     if (!scriptUTF8) {
1873         printf("FAIL: Test script could not be loaded.\n");
1874         failed = 1;
1875     } else {
1876         JSStringRef url = JSStringCreateWithUTF8CString(scriptPath);
1877         JSStringRef script = JSStringCreateWithUTF8CString(scriptUTF8);
1878         JSStringRef errorMessage = 0;
1879         int errorLine = 0;
1880         JSScriptRef scriptObject = JSScriptCreateFromString(contextGroup, url, 1, script, &errorMessage, &errorLine);
1881         ASSERT((!scriptObject) != (!errorMessage));
1882         if (!scriptObject) {
1883             printf("FAIL: Test script did not parse\n\t%s:%d\n\t", scriptPath, errorLine);
1884             CFStringRef errorCF = JSStringCopyCFString(kCFAllocatorDefault, errorMessage);
1885             CFShow(errorCF);
1886             CFRelease(errorCF);
1887             JSStringRelease(errorMessage);
1888             failed = 1;
1889         }
1890
1891         JSStringRelease(script);
1892         exception = NULL;
1893         result = scriptObject ? JSScriptEvaluate(context, scriptObject, 0, &exception) : 0;
1894         if (result && JSValueIsUndefined(context, result))
1895             printf("PASS: Test script executed successfully.\n");
1896         else {
1897             printf("FAIL: Test script returned unexpected value:\n");
1898             JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL);
1899             CFStringRef exceptionCF = JSStringCopyCFString(kCFAllocatorDefault, exceptionIString);
1900             CFShow(exceptionCF);
1901             CFRelease(exceptionCF);
1902             JSStringRelease(exceptionIString);
1903             failed = 1;
1904         }
1905         JSScriptRelease(scriptObject);
1906         free(scriptUTF8);
1907     }
1908
1909     // Check Promise is not exposed.
1910     {
1911         JSObjectRef globalObject = JSContextGetGlobalObject(context);
1912         {
1913             JSStringRef promiseProperty = JSStringCreateWithUTF8CString("Promise");
1914             ASSERT(JSObjectHasProperty(context, globalObject, promiseProperty));
1915             JSStringRelease(promiseProperty);
1916         }
1917         {
1918             JSStringRef script = JSStringCreateWithUTF8CString("typeof Promise");
1919             JSStringRef function = JSStringCreateWithUTF8CString("function");
1920             JSValueRef value = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
1921             ASSERT(JSValueIsString(context, value));
1922             JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
1923             ASSERT(JSStringIsEqual(valueAsString, function));
1924             JSStringRelease(valueAsString);
1925             JSStringRelease(function);
1926             JSStringRelease(script);
1927         }
1928         printf("PASS: Promise is exposed under JSContext API.\n");
1929     }
1930
1931     // Check microtasks.
1932     {
1933         JSGlobalContextRef context = JSGlobalContextCreateInGroup(NULL, NULL);
1934         {
1935             JSObjectRef globalObject = JSContextGetGlobalObject(context);
1936             JSValueRef exception;
1937             JSStringRef code = JSStringCreateWithUTF8CString("result = 0; Promise.resolve(42).then(function (value) { result = value; });");
1938             JSStringRef file = JSStringCreateWithUTF8CString("");
1939             assertTrue(JSEvaluateScript(context, code, globalObject, file, 1, &exception), "An exception should not be thrown");
1940             JSStringRelease(code);
1941             JSStringRelease(file);
1942
1943             JSStringRef resultProperty = JSStringCreateWithUTF8CString("result");
1944             ASSERT(JSObjectHasProperty(context, globalObject, resultProperty));
1945
1946             JSValueRef resultValue = JSObjectGetProperty(context, globalObject, resultProperty, &exception);
1947             assertEqualsAsNumber(resultValue, 42);
1948             JSStringRelease(resultProperty);
1949         }
1950         JSGlobalContextRelease(context);
1951     }
1952
1953     failed = testTypedArrayCAPI() || failed;
1954     failed = testExecutionTimeLimit() || failed;
1955     failed = testFunctionOverrides() || failed;
1956     failed = testGlobalContextWithFinalizer() || failed;
1957     failed = testPingPongStackOverflow() || failed;
1958     failed = testJSONParse() || failed;
1959
1960     // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
1961     function = NULL;
1962     v = NULL;
1963     o = NULL;
1964     globalObject = NULL;
1965     myConstructor = NULL;
1966
1967     JSStringRelease(jsEmptyIString);
1968     JSStringRelease(jsOneIString);
1969     JSStringRelease(jsCFIString);
1970     JSStringRelease(jsCFEmptyIString);
1971     JSStringRelease(jsCFIStringWithCharacters);
1972     JSStringRelease(jsCFEmptyIStringWithCharacters);
1973     JSStringRelease(goodSyntax);
1974     JSStringRelease(badSyntax);
1975
1976     JSGlobalContextRelease(context);
1977     JSClassRelease(globalObjectClass);
1978
1979     // Test for an infinite prototype chain that used to be created. This test
1980     // passes if the call to JSObjectHasProperty() does not hang.
1981
1982     JSClassDefinition prototypeLoopClassDefinition = kJSClassDefinitionEmpty;
1983     prototypeLoopClassDefinition.staticFunctions = globalObject_staticFunctions;
1984     JSClassRef prototypeLoopClass = JSClassCreate(&prototypeLoopClassDefinition);
1985     JSGlobalContextRef prototypeLoopContext = JSGlobalContextCreateInGroup(NULL, prototypeLoopClass);
1986
1987     JSStringRef nameProperty = JSStringCreateWithUTF8CString("name");
1988     JSObjectHasProperty(prototypeLoopContext, JSContextGetGlobalObject(prototypeLoopContext), nameProperty);
1989
1990     JSGlobalContextRelease(prototypeLoopContext);
1991     JSClassRelease(prototypeLoopClass);
1992
1993     printf("PASS: Infinite prototype chain does not occur.\n");
1994
1995     if (checkForCycleInPrototypeChain())
1996         printf("PASS: A cycle in a prototype chain can't be created.\n");
1997     else {
1998         printf("FAIL: A cycle in a prototype chain can be created.\n");
1999         failed = true;
2000     }
2001     if (valueToObjectExceptionTest())
2002         printf("PASS: throwException did not crash when handling an error with appendMessageToError set and no codeBlock available.\n");
2003
2004     if (globalContextNameTest())
2005         printf("PASS: global context name behaves as expected.\n");
2006
2007     customGlobalObjectClassTest();
2008     globalObjectSetPrototypeTest();
2009     globalObjectPrivatePropertyTest();
2010
2011     if (failed) {
2012         printf("FAIL: Some tests failed.\n");
2013         return 1;
2014     }
2015
2016     printf("PASS: Program exited normally.\n");
2017     return 0;
2018 }
2019
2020 static char* createStringWithContentsOfFile(const char* fileName)
2021 {
2022     char* buffer;
2023     
2024     size_t buffer_size = 0;
2025     size_t buffer_capacity = 1024;
2026     buffer = (char*)malloc(buffer_capacity);
2027     
2028     FILE* f = fopen(fileName, "r");
2029     if (!f) {
2030         fprintf(stderr, "Could not open file: %s\n", fileName);
2031         free(buffer);
2032         return 0;
2033     }
2034     
2035     while (!feof(f) && !ferror(f)) {
2036         buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f);
2037         if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0'
2038             buffer_capacity *= 2;
2039             buffer = (char*)realloc(buffer, buffer_capacity);
2040             ASSERT(buffer);
2041         }
2042         
2043         ASSERT(buffer_size < buffer_capacity);
2044     }
2045     fclose(f);
2046     buffer[buffer_size] = '\0';
2047     
2048     return buffer;
2049 }
2050
2051 #if OS(WINDOWS)
2052 extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
2053 {
2054     return main(argc, const_cast<char**>(argv));
2055 }
2056 #endif