initial import
[vuplus_webkit] / Source / JavaScriptCore / API / tests / testapi.c
1 /*
2  * Copyright (C) 2006 Apple Computer, 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 COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "JavaScriptCore.h"
27 #include "JSBasePrivate.h"
28 #include "JSContextRefPrivate.h"
29 #include "JSObjectRefPrivate.h"
30 #include <math.h>
31 #define ASSERT_DISABLED 0
32 #include <wtf/Assertions.h>
33 #include <wtf/UnusedParam.h>
34
35 #if OS(WINDOWS)
36 #include <windows.h>
37 #endif
38
39 #if COMPILER(MSVC)
40
41 #include <wtf/MathExtras.h>
42
43 static double nan(const char*)
44 {
45     return std::numeric_limits<double>::quiet_NaN();
46 }
47
48 #endif
49
50 static JSGlobalContextRef context;
51 static int failed;
52 static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue)
53 {
54     if (JSValueToBoolean(context, value) != expectedValue) {
55         fprintf(stderr, "assertEqualsAsBoolean failed: %p, %d\n", value, expectedValue);
56         failed = 1;
57     }
58 }
59
60 static void assertEqualsAsNumber(JSValueRef value, double expectedValue)
61 {
62     double number = JSValueToNumber(context, value, NULL);
63
64     // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
65     // causing a build break with -Wshorten-64-to-32 enabled.  The issue is known by the appropriate team.
66     // After that's resolved, we can remove these casts
67     if (number != expectedValue && !(isnan((float)number) && isnan((float)expectedValue))) {
68         fprintf(stderr, "assertEqualsAsNumber failed: %p, %lf\n", value, expectedValue);
69         failed = 1;
70     }
71 }
72
73 static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue)
74 {
75     JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
76
77     size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString);
78     char* jsBuffer = (char*)malloc(jsSize);
79     JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize);
80     
81     unsigned i;
82     for (i = 0; jsBuffer[i]; i++) {
83         if (jsBuffer[i] != expectedValue[i]) {
84             fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]);
85             failed = 1;
86         }
87     }
88
89     if (jsSize < strlen(jsBuffer) + 1) {
90         fprintf(stderr, "assertEqualsAsUTF8String failed: jsSize was too small\n");
91         failed = 1;
92     }
93
94     free(jsBuffer);
95     JSStringRelease(valueAsString);
96 }
97
98 static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedValue)
99 {
100     JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
101
102     size_t jsLength = JSStringGetLength(valueAsString);
103     const JSChar* jsBuffer = JSStringGetCharactersPtr(valueAsString);
104
105     CFStringRef expectedValueAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, 
106                                                                     expectedValue,
107                                                                     kCFStringEncodingUTF8);    
108     CFIndex cfLength = CFStringGetLength(expectedValueAsCFString);
109     UniChar* cfBuffer = (UniChar*)malloc(cfLength * sizeof(UniChar));
110     CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer);
111     CFRelease(expectedValueAsCFString);
112
113     if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0) {
114         fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n");
115         failed = 1;
116     }
117     
118     if (jsLength != (size_t)cfLength) {
119         fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength);
120         failed = 1;
121     }
122
123     free(cfBuffer);
124     JSStringRelease(valueAsString);
125 }
126
127 static bool timeZoneIsPST()
128 {
129     char timeZoneName[70];
130     struct tm gtm;
131     memset(&gtm, 0, sizeof(gtm));
132     strftime(timeZoneName, sizeof(timeZoneName), "%Z", &gtm);
133
134     return 0 == strcmp("PST", timeZoneName);
135 }
136
137 static JSValueRef jsGlobalValue; // non-stack value for testing JSValueProtect()
138
139 /* MyObject pseudo-class */
140
141 static bool MyObject_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName)
142 {
143     UNUSED_PARAM(context);
144     UNUSED_PARAM(object);
145
146     if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")
147         || JSStringIsEqualToUTF8CString(propertyName, "cantFind")
148         || JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")
149         || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")
150         || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")
151         || JSStringIsEqualToUTF8CString(propertyName, "0")) {
152         return true;
153     }
154     
155     return false;
156 }
157
158 static JSValueRef MyObject_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
159 {
160     UNUSED_PARAM(context);
161     UNUSED_PARAM(object);
162     
163     if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")) {
164         return JSValueMakeNumber(context, 1);
165     }
166     
167     if (JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")) {
168         return JSValueMakeNumber(context, 1);
169     }
170
171     if (JSStringIsEqualToUTF8CString(propertyName, "cantFind")) {
172         return JSValueMakeUndefined(context);
173     }
174     
175     if (JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")) {
176         return 0;
177     }
178
179     if (JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")) {
180         return JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
181     }
182
183     if (JSStringIsEqualToUTF8CString(propertyName, "0")) {
184         *exception = JSValueMakeNumber(context, 1);
185         return JSValueMakeNumber(context, 1);
186     }
187     
188     return JSValueMakeNull(context);
189 }
190
191 static bool MyObject_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
192 {
193     UNUSED_PARAM(context);
194     UNUSED_PARAM(object);
195     UNUSED_PARAM(value);
196     UNUSED_PARAM(exception);
197
198     if (JSStringIsEqualToUTF8CString(propertyName, "cantSet"))
199         return true; // pretend we set the property in order to swallow it
200     
201     if (JSStringIsEqualToUTF8CString(propertyName, "throwOnSet")) {
202         JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
203     }
204     
205     return false;
206 }
207
208 static bool MyObject_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
209 {
210     UNUSED_PARAM(context);
211     UNUSED_PARAM(object);
212     
213     if (JSStringIsEqualToUTF8CString(propertyName, "cantDelete"))
214         return true;
215     
216     if (JSStringIsEqualToUTF8CString(propertyName, "throwOnDelete")) {
217         JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
218         return false;
219     }
220
221     return false;
222 }
223
224 static void MyObject_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
225 {
226     UNUSED_PARAM(context);
227     UNUSED_PARAM(object);
228     
229     JSStringRef propertyName;
230     
231     propertyName = JSStringCreateWithUTF8CString("alwaysOne");
232     JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
233     JSStringRelease(propertyName);
234     
235     propertyName = JSStringCreateWithUTF8CString("myPropertyName");
236     JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
237     JSStringRelease(propertyName);
238 }
239
240 static JSValueRef MyObject_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
241 {
242     UNUSED_PARAM(context);
243     UNUSED_PARAM(object);
244     UNUSED_PARAM(thisObject);
245     UNUSED_PARAM(exception);
246
247     if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnCall")) {
248         JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
249         return JSValueMakeUndefined(context);
250     }
251
252     if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
253         return JSValueMakeNumber(context, 1);
254     
255     return JSValueMakeUndefined(context);
256 }
257
258 static JSObjectRef MyObject_callAsConstructor(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
259 {
260     UNUSED_PARAM(context);
261     UNUSED_PARAM(object);
262
263     if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnConstruct")) {
264         JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
265         return object;
266     }
267
268     if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
269         return JSValueToObject(context, JSValueMakeNumber(context, 1), exception);
270     
271     return JSValueToObject(context, JSValueMakeNumber(context, 0), exception);
272 }
273
274 static bool MyObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
275 {
276     UNUSED_PARAM(context);
277     UNUSED_PARAM(constructor);
278
279     if (JSValueIsString(context, possibleValue) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, possibleValue, 0), "throwOnHasInstance")) {
280         JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), constructor, JSStringCreateWithUTF8CString("test script"), 1, exception);
281         return false;
282     }
283
284     JSStringRef numberString = JSStringCreateWithUTF8CString("Number");
285     JSObjectRef numberConstructor = JSValueToObject(context, JSObjectGetProperty(context, JSContextGetGlobalObject(context), numberString, exception), exception);
286     JSStringRelease(numberString);
287
288     return JSValueIsInstanceOfConstructor(context, possibleValue, numberConstructor, exception);
289 }
290
291 static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
292 {
293     UNUSED_PARAM(object);
294     UNUSED_PARAM(exception);
295     
296     switch (type) {
297     case kJSTypeNumber:
298         return JSValueMakeNumber(context, 1);
299     case kJSTypeString:
300         {
301             JSStringRef string = JSStringCreateWithUTF8CString("MyObjectAsString");
302             JSValueRef result = JSValueMakeString(context, string);
303             JSStringRelease(string);
304             return result;
305         }
306     default:
307         break;
308     }
309
310     // string conversion -- forward to default object class
311     return JSValueMakeNull(context);
312 }
313
314 static bool MyObject_set_nullGetForwardSet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
315 {
316     UNUSED_PARAM(ctx);
317     UNUSED_PARAM(object);
318     UNUSED_PARAM(propertyName);
319     UNUSED_PARAM(value);
320     UNUSED_PARAM(exception);
321     return false; // Forward to parent class.
322 }
323
324 static JSStaticValue evilStaticValues[] = {
325     { "nullGetSet", 0, 0, kJSPropertyAttributeNone },
326     { "nullGetForwardSet", 0, MyObject_set_nullGetForwardSet, kJSPropertyAttributeNone },
327     { 0, 0, 0, 0 }
328 };
329
330 static JSStaticFunction evilStaticFunctions[] = {
331     { "nullCall", 0, kJSPropertyAttributeNone },
332     { 0, 0, 0 }
333 };
334
335 JSClassDefinition MyObject_definition = {
336     0,
337     kJSClassAttributeNone,
338     
339     "MyObject",
340     NULL,
341     
342     evilStaticValues,
343     evilStaticFunctions,
344     
345     NULL,
346     NULL,
347     MyObject_hasProperty,
348     MyObject_getProperty,
349     MyObject_setProperty,
350     MyObject_deleteProperty,
351     MyObject_getPropertyNames,
352     MyObject_callAsFunction,
353     MyObject_callAsConstructor,
354     MyObject_hasInstance,
355     MyObject_convertToType,
356 };
357
358 static JSClassRef MyObject_class(JSContextRef context)
359 {
360     UNUSED_PARAM(context);
361
362     static JSClassRef jsClass;
363     if (!jsClass)
364         jsClass = JSClassCreate(&MyObject_definition);
365     
366     return jsClass;
367 }
368
369 static JSValueRef PropertyCatchalls_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
370 {
371     UNUSED_PARAM(context);
372     UNUSED_PARAM(object);
373     UNUSED_PARAM(propertyName);
374     UNUSED_PARAM(exception);
375
376     if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
377         static size_t count;
378         if (count++ < 5)
379             return NULL;
380
381         // Swallow all .x gets after 5, returning null.
382         return JSValueMakeNull(context);
383     }
384
385     if (JSStringIsEqualToUTF8CString(propertyName, "y")) {
386         static size_t count;
387         if (count++ < 5)
388             return NULL;
389
390         // Swallow all .y gets after 5, returning null.
391         return JSValueMakeNull(context);
392     }
393     
394     if (JSStringIsEqualToUTF8CString(propertyName, "z")) {
395         static size_t count;
396         if (count++ < 5)
397             return NULL;
398
399         // Swallow all .y gets after 5, returning null.
400         return JSValueMakeNull(context);
401     }
402
403     return NULL;
404 }
405
406 static bool PropertyCatchalls_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
407 {
408     UNUSED_PARAM(context);
409     UNUSED_PARAM(object);
410     UNUSED_PARAM(propertyName);
411     UNUSED_PARAM(value);
412     UNUSED_PARAM(exception);
413
414     if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
415         static size_t count;
416         if (count++ < 5)
417             return false;
418
419         // Swallow all .x sets after 4.
420         return true;
421     }
422
423     return false;
424 }
425
426 static void PropertyCatchalls_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
427 {
428     UNUSED_PARAM(context);
429     UNUSED_PARAM(object);
430
431     static size_t count;
432     static const char* numbers[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
433     
434     // Provide a property of a different name every time.
435     JSStringRef propertyName = JSStringCreateWithUTF8CString(numbers[count++ % 10]);
436     JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
437     JSStringRelease(propertyName);
438 }
439
440 JSClassDefinition PropertyCatchalls_definition = {
441     0,
442     kJSClassAttributeNone,
443     
444     "PropertyCatchalls",
445     NULL,
446     
447     NULL,
448     NULL,
449     
450     NULL,
451     NULL,
452     NULL,
453     PropertyCatchalls_getProperty,
454     PropertyCatchalls_setProperty,
455     NULL,
456     PropertyCatchalls_getPropertyNames,
457     NULL,
458     NULL,
459     NULL,
460     NULL,
461 };
462
463 static JSClassRef PropertyCatchalls_class(JSContextRef context)
464 {
465     UNUSED_PARAM(context);
466
467     static JSClassRef jsClass;
468     if (!jsClass)
469         jsClass = JSClassCreate(&PropertyCatchalls_definition);
470     
471     return jsClass;
472 }
473
474 static bool EvilExceptionObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
475 {
476     UNUSED_PARAM(context);
477     UNUSED_PARAM(constructor);
478     
479     JSStringRef hasInstanceName = JSStringCreateWithUTF8CString("hasInstance");
480     JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception);
481     JSStringRelease(hasInstanceName);
482     if (!hasInstance)
483         return false;
484     JSObjectRef function = JSValueToObject(context, hasInstance, exception);
485     JSValueRef result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception);
486     return result && JSValueToBoolean(context, result);
487 }
488
489 static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
490 {
491     UNUSED_PARAM(object);
492     UNUSED_PARAM(exception);
493     JSStringRef funcName;
494     switch (type) {
495     case kJSTypeNumber:
496         funcName = JSStringCreateWithUTF8CString("toNumber");
497         break;
498     case kJSTypeString:
499         funcName = JSStringCreateWithUTF8CString("toStringExplicit");
500         break;
501     default:
502         return JSValueMakeNull(context);
503         break;
504     }
505     
506     JSValueRef func = JSObjectGetProperty(context, object, funcName, exception);
507     JSStringRelease(funcName);    
508     JSObjectRef function = JSValueToObject(context, func, exception);
509     if (!function)
510         return JSValueMakeNull(context);
511     JSValueRef value = JSObjectCallAsFunction(context, function, object, 0, NULL, exception);
512     if (!value) {
513         JSStringRef errorString = JSStringCreateWithUTF8CString("convertToType failed"); 
514         JSValueRef errorStringRef = JSValueMakeString(context, errorString);
515         JSStringRelease(errorString);
516         return errorStringRef;
517     }
518     return value;
519 }
520
521 JSClassDefinition EvilExceptionObject_definition = {
522     0,
523     kJSClassAttributeNone,
524
525     "EvilExceptionObject",
526     NULL,
527
528     NULL,
529     NULL,
530
531     NULL,
532     NULL,
533     NULL,
534     NULL,
535     NULL,
536     NULL,
537     NULL,
538     NULL,
539     NULL,
540     EvilExceptionObject_hasInstance,
541     EvilExceptionObject_convertToType,
542 };
543
544 static JSClassRef EvilExceptionObject_class(JSContextRef context)
545 {
546     UNUSED_PARAM(context);
547     
548     static JSClassRef jsClass;
549     if (!jsClass)
550         jsClass = JSClassCreate(&EvilExceptionObject_definition);
551     
552     return jsClass;
553 }
554
555 JSClassDefinition EmptyObject_definition = {
556     0,
557     kJSClassAttributeNone,
558     
559     NULL,
560     NULL,
561     
562     NULL,
563     NULL,
564     
565     NULL,
566     NULL,
567     NULL,
568     NULL,
569     NULL,
570     NULL,
571     NULL,
572     NULL,
573     NULL,
574     NULL,
575     NULL,
576 };
577
578 static JSClassRef EmptyObject_class(JSContextRef context)
579 {
580     UNUSED_PARAM(context);
581     
582     static JSClassRef jsClass;
583     if (!jsClass)
584         jsClass = JSClassCreate(&EmptyObject_definition);
585     
586     return jsClass;
587 }
588
589
590 static JSValueRef Base_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
591 {
592     UNUSED_PARAM(object);
593     UNUSED_PARAM(propertyName);
594     UNUSED_PARAM(exception);
595
596     return JSValueMakeNumber(ctx, 1); // distinguish base get form derived get
597 }
598
599 static bool Base_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
600 {
601     UNUSED_PARAM(object);
602     UNUSED_PARAM(propertyName);
603     UNUSED_PARAM(value);
604
605     *exception = JSValueMakeNumber(ctx, 1); // distinguish base set from derived set
606     return true;
607 }
608
609 static JSValueRef Base_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
610 {
611     UNUSED_PARAM(function);
612     UNUSED_PARAM(thisObject);
613     UNUSED_PARAM(argumentCount);
614     UNUSED_PARAM(arguments);
615     UNUSED_PARAM(exception);
616     
617     return JSValueMakeNumber(ctx, 1); // distinguish base call from derived call
618 }
619
620 static JSStaticFunction Base_staticFunctions[] = {
621     { "baseProtoDup", NULL, kJSPropertyAttributeNone },
622     { "baseProto", Base_callAsFunction, kJSPropertyAttributeNone },
623     { 0, 0, 0 }
624 };
625
626 static JSStaticValue Base_staticValues[] = {
627     { "baseDup", Base_get, Base_set, kJSPropertyAttributeNone },
628     { "baseOnly", Base_get, Base_set, kJSPropertyAttributeNone },
629     { 0, 0, 0, 0 }
630 };
631
632 static bool TestInitializeFinalize;
633 static void Base_initialize(JSContextRef context, JSObjectRef object)
634 {
635     UNUSED_PARAM(context);
636
637     if (TestInitializeFinalize) {
638         ASSERT((void*)1 == JSObjectGetPrivate(object));
639         JSObjectSetPrivate(object, (void*)2);
640     }
641 }
642
643 static unsigned Base_didFinalize;
644 static void Base_finalize(JSObjectRef object)
645 {
646     UNUSED_PARAM(object);
647     if (TestInitializeFinalize) {
648         ASSERT((void*)4 == JSObjectGetPrivate(object));
649         Base_didFinalize = true;
650     }
651 }
652
653 static JSClassRef Base_class(JSContextRef context)
654 {
655     UNUSED_PARAM(context);
656
657     static JSClassRef jsClass;
658     if (!jsClass) {
659         JSClassDefinition definition = kJSClassDefinitionEmpty;
660         definition.staticValues = Base_staticValues;
661         definition.staticFunctions = Base_staticFunctions;
662         definition.initialize = Base_initialize;
663         definition.finalize = Base_finalize;
664         jsClass = JSClassCreate(&definition);
665     }
666     return jsClass;
667 }
668
669 static JSValueRef Derived_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
670 {
671     UNUSED_PARAM(object);
672     UNUSED_PARAM(propertyName);
673     UNUSED_PARAM(exception);
674
675     return JSValueMakeNumber(ctx, 2); // distinguish base get form derived get
676 }
677
678 static bool Derived_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
679 {
680     UNUSED_PARAM(ctx);
681     UNUSED_PARAM(object);
682     UNUSED_PARAM(propertyName);
683     UNUSED_PARAM(value);
684
685     *exception = JSValueMakeNumber(ctx, 2); // distinguish base set from derived set
686     return true;
687 }
688
689 static JSValueRef Derived_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, 2); // distinguish base call from derived call
698 }
699
700 static JSStaticFunction Derived_staticFunctions[] = {
701     { "protoOnly", Derived_callAsFunction, kJSPropertyAttributeNone },
702     { "protoDup", NULL, kJSPropertyAttributeNone },
703     { "baseProtoDup", Derived_callAsFunction, kJSPropertyAttributeNone },
704     { 0, 0, 0 }
705 };
706
707 static JSStaticValue Derived_staticValues[] = {
708     { "derivedOnly", Derived_get, Derived_set, kJSPropertyAttributeNone },
709     { "protoDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
710     { "baseDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
711     { 0, 0, 0, 0 }
712 };
713
714 static void Derived_initialize(JSContextRef context, JSObjectRef object)
715 {
716     UNUSED_PARAM(context);
717
718     if (TestInitializeFinalize) {
719         ASSERT((void*)2 == JSObjectGetPrivate(object));
720         JSObjectSetPrivate(object, (void*)3);
721     }
722 }
723
724 static void Derived_finalize(JSObjectRef object)
725 {
726     if (TestInitializeFinalize) {
727         ASSERT((void*)3 == JSObjectGetPrivate(object));
728         JSObjectSetPrivate(object, (void*)4);
729     }
730 }
731
732 static JSClassRef Derived_class(JSContextRef context)
733 {
734     static JSClassRef jsClass;
735     if (!jsClass) {
736         JSClassDefinition definition = kJSClassDefinitionEmpty;
737         definition.parentClass = Base_class(context);
738         definition.staticValues = Derived_staticValues;
739         definition.staticFunctions = Derived_staticFunctions;
740         definition.initialize = Derived_initialize;
741         definition.finalize = Derived_finalize;
742         jsClass = JSClassCreate(&definition);
743     }
744     return jsClass;
745 }
746
747 static JSClassRef Derived2_class(JSContextRef context)
748 {
749     static JSClassRef jsClass;
750     if (!jsClass) {
751         JSClassDefinition definition = kJSClassDefinitionEmpty;
752         definition.parentClass = Derived_class(context);
753         jsClass = JSClassCreate(&definition);
754     }
755     return jsClass;
756 }
757
758 static JSValueRef print_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
759 {
760     UNUSED_PARAM(functionObject);
761     UNUSED_PARAM(thisObject);
762     UNUSED_PARAM(exception);
763
764     ASSERT(JSContextGetGlobalContext(ctx) == context);
765     
766     if (argumentCount > 0) {
767         JSStringRef string = JSValueToStringCopy(ctx, arguments[0], NULL);
768         size_t sizeUTF8 = JSStringGetMaximumUTF8CStringSize(string);
769         char* stringUTF8 = (char*)malloc(sizeUTF8);
770         JSStringGetUTF8CString(string, stringUTF8, sizeUTF8);
771         printf("%s\n", stringUTF8);
772         free(stringUTF8);
773         JSStringRelease(string);
774     }
775     
776     return JSValueMakeUndefined(ctx);
777 }
778
779 static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
780 {
781     UNUSED_PARAM(constructorObject);
782     UNUSED_PARAM(exception);
783     
784     JSObjectRef result = JSObjectMake(context, NULL, NULL);
785     if (argumentCount > 0) {
786         JSStringRef value = JSStringCreateWithUTF8CString("value");
787         JSObjectSetProperty(context, result, value, arguments[0], kJSPropertyAttributeNone, NULL);
788         JSStringRelease(value);
789     }
790     
791     return result;
792 }
793
794
795 static void globalObject_initialize(JSContextRef context, JSObjectRef object)
796 {
797     UNUSED_PARAM(object);
798     // Ensure that an execution context is passed in
799     ASSERT(context);
800
801     // Ensure that the global object is set to the object that we were passed
802     JSObjectRef globalObject = JSContextGetGlobalObject(context);
803     ASSERT(globalObject);
804     ASSERT(object == globalObject);
805
806     // Ensure that the standard global properties have been set on the global object
807     JSStringRef array = JSStringCreateWithUTF8CString("Array");
808     JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
809     JSStringRelease(array);
810
811     UNUSED_PARAM(arrayConstructor);
812     ASSERT(arrayConstructor);
813 }
814
815 static JSValueRef globalObject_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
816 {
817     UNUSED_PARAM(object);
818     UNUSED_PARAM(propertyName);
819     UNUSED_PARAM(exception);
820
821     return JSValueMakeNumber(ctx, 3);
822 }
823
824 static bool globalObject_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
825 {
826     UNUSED_PARAM(object);
827     UNUSED_PARAM(propertyName);
828     UNUSED_PARAM(value);
829
830     *exception = JSValueMakeNumber(ctx, 3);
831     return true;
832 }
833
834 static JSValueRef globalObject_call(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
835 {
836     UNUSED_PARAM(function);
837     UNUSED_PARAM(thisObject);
838     UNUSED_PARAM(argumentCount);
839     UNUSED_PARAM(arguments);
840     UNUSED_PARAM(exception);
841
842     return JSValueMakeNumber(ctx, 3);
843 }
844
845 static JSValueRef functionGC(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
846 {
847     UNUSED_PARAM(function);
848     UNUSED_PARAM(thisObject);
849     UNUSED_PARAM(argumentCount);
850     UNUSED_PARAM(arguments);
851     UNUSED_PARAM(exception);
852     JSGarbageCollect(context);
853     return JSValueMakeUndefined(context);
854 }
855
856 static JSStaticValue globalObject_staticValues[] = {
857     { "globalStaticValue", globalObject_get, globalObject_set, kJSPropertyAttributeNone },
858     { 0, 0, 0, 0 }
859 };
860
861 static JSStaticFunction globalObject_staticFunctions[] = {
862     { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone },
863     { "gc", functionGC, kJSPropertyAttributeNone },
864     { 0, 0, 0 }
865 };
866
867 static char* createStringWithContentsOfFile(const char* fileName);
868
869 static void testInitializeFinalize()
870 {
871     JSObjectRef o = JSObjectMake(context, Derived_class(context), (void*)1);
872     UNUSED_PARAM(o);
873     ASSERT(JSObjectGetPrivate(o) == (void*)3);
874 }
875
876 static JSValueRef jsNumberValue =  NULL;
877
878 static JSObjectRef aHeapRef = NULL;
879
880 static void makeGlobalNumberValue(JSContextRef context) {
881     JSValueRef v = JSValueMakeNumber(context, 420);
882     JSValueProtect(context, v);
883     jsNumberValue = v;
884     v = NULL;
885 }
886
887 static bool assertTrue(bool value, const char* message)
888 {
889     if (!value) {
890         if (message)
891             fprintf(stderr, "assertTrue failed: '%s'\n", message);
892         else
893             fprintf(stderr, "assertTrue failed.\n");
894         failed = 1;
895     }
896     return value;
897 }
898
899 static bool checkForCycleInPrototypeChain()
900 {
901     bool result = true;
902     JSGlobalContextRef context = JSGlobalContextCreate(0);
903     JSObjectRef object1 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
904     JSObjectRef object2 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
905     JSObjectRef object3 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
906
907     JSObjectSetPrototype(context, object1, JSValueMakeNull(context));
908     ASSERT(JSValueIsNull(context, JSObjectGetPrototype(context, object1)));
909
910     // object1 -> object1
911     JSObjectSetPrototype(context, object1, object1);
912     result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to assign self as a prototype");
913
914     // object1 -> object2 -> object1
915     JSObjectSetPrototype(context, object2, object1);
916     ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object1));
917     JSObjectSetPrototype(context, object1, object2);
918     result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to close a prototype chain cycle");
919
920     // object1 -> object2 -> object3 -> object1
921     JSObjectSetPrototype(context, object2, object3);
922     ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object3));
923     JSObjectSetPrototype(context, object1, object2);
924     ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object1), object2));
925     JSObjectSetPrototype(context, object3, object1);
926     result &= assertTrue(!JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object3), object1), "It is possible to close a prototype chain cycle");
927
928     JSValueRef exception;
929     JSStringRef code = JSStringCreateWithUTF8CString("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o");
930     JSStringRef file = JSStringCreateWithUTF8CString("");
931     result &= assertTrue(!JSEvaluateScript(context, code, /* thisObject*/ 0, file, 1, &exception)
932                          , "An exception should be thrown");
933
934     JSStringRelease(code);
935     JSStringRelease(file);
936     JSGlobalContextRelease(context);
937     return result;
938 }
939
940 static void checkConstnessInJSObjectNames()
941 {
942     JSStaticFunction fun;
943     fun.name = "something";
944     JSStaticValue val;
945     val.name = "something";
946 }
947
948 int main(int argc, char* argv[])
949 {
950 #if OS(WINDOWS)
951     // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
952     // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
953     // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
954     ::SetErrorMode(0);
955 #endif
956
957     const char *scriptPath = "testapi.js";
958     if (argc > 1) {
959         scriptPath = argv[1];
960     }
961     
962     // Test garbage collection with a fresh context
963     context = JSGlobalContextCreateInGroup(NULL, NULL);
964     TestInitializeFinalize = true;
965     testInitializeFinalize();
966     JSGlobalContextRelease(context);
967     TestInitializeFinalize = false;
968
969     ASSERT(Base_didFinalize);
970
971     JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty;
972     globalObjectClassDefinition.initialize = globalObject_initialize;
973     globalObjectClassDefinition.staticValues = globalObject_staticValues;
974     globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions;
975     globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
976     JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition);
977     context = JSGlobalContextCreateInGroup(NULL, globalObjectClass);
978
979     JSGlobalContextRetain(context);
980     JSGlobalContextRelease(context);
981     ASSERT(JSContextGetGlobalContext(context) == context);
982     
983     JSReportExtraMemoryCost(context, 0);
984     JSReportExtraMemoryCost(context, 1);
985     JSReportExtraMemoryCost(context, 1024);
986
987     JSObjectRef globalObject = JSContextGetGlobalObject(context);
988     ASSERT(JSValueIsObject(context, globalObject));
989     
990     JSValueRef jsUndefined = JSValueMakeUndefined(context);
991     JSValueRef jsNull = JSValueMakeNull(context);
992     JSValueRef jsTrue = JSValueMakeBoolean(context, true);
993     JSValueRef jsFalse = JSValueMakeBoolean(context, false);
994     JSValueRef jsZero = JSValueMakeNumber(context, 0);
995     JSValueRef jsOne = JSValueMakeNumber(context, 1);
996     JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0);
997     JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, NULL);
998     JSObjectSetPrototype(context, jsObjectNoProto, JSValueMakeNull(context));
999
1000     // FIXME: test funny utf8 characters
1001     JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString("");
1002     JSValueRef jsEmptyString = JSValueMakeString(context, jsEmptyIString);
1003     
1004     JSStringRef jsOneIString = JSStringCreateWithUTF8CString("1");
1005     JSValueRef jsOneString = JSValueMakeString(context, jsOneIString);
1006
1007     UniChar singleUniChar = 65; // Capital A
1008     CFMutableStringRef cfString = 
1009         CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault,
1010                                                           &singleUniChar,
1011                                                           1,
1012                                                           1,
1013                                                           kCFAllocatorNull);
1014
1015     JSStringRef jsCFIString = JSStringCreateWithCFString(cfString);
1016     JSValueRef jsCFString = JSValueMakeString(context, jsCFIString);
1017     
1018     CFStringRef cfEmptyString = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8);
1019     
1020     JSStringRef jsCFEmptyIString = JSStringCreateWithCFString(cfEmptyString);
1021     JSValueRef jsCFEmptyString = JSValueMakeString(context, jsCFEmptyIString);
1022
1023     CFIndex cfStringLength = CFStringGetLength(cfString);
1024     UniChar* buffer = (UniChar*)malloc(cfStringLength * sizeof(UniChar));
1025     CFStringGetCharacters(cfString, 
1026                           CFRangeMake(0, cfStringLength), 
1027                           buffer);
1028     JSStringRef jsCFIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, cfStringLength);
1029     JSValueRef jsCFStringWithCharacters = JSValueMakeString(context, jsCFIStringWithCharacters);
1030     
1031     JSStringRef jsCFEmptyIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, CFStringGetLength(cfEmptyString));
1032     free(buffer);
1033     JSValueRef jsCFEmptyStringWithCharacters = JSValueMakeString(context, jsCFEmptyIStringWithCharacters);
1034
1035     ASSERT(JSValueGetType(context, jsUndefined) == kJSTypeUndefined);
1036     ASSERT(JSValueGetType(context, jsNull) == kJSTypeNull);
1037     ASSERT(JSValueGetType(context, jsTrue) == kJSTypeBoolean);
1038     ASSERT(JSValueGetType(context, jsFalse) == kJSTypeBoolean);
1039     ASSERT(JSValueGetType(context, jsZero) == kJSTypeNumber);
1040     ASSERT(JSValueGetType(context, jsOne) == kJSTypeNumber);
1041     ASSERT(JSValueGetType(context, jsOneThird) == kJSTypeNumber);
1042     ASSERT(JSValueGetType(context, jsEmptyString) == kJSTypeString);
1043     ASSERT(JSValueGetType(context, jsOneString) == kJSTypeString);
1044     ASSERT(JSValueGetType(context, jsCFString) == kJSTypeString);
1045     ASSERT(JSValueGetType(context, jsCFStringWithCharacters) == kJSTypeString);
1046     ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString);
1047     ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);
1048
1049     JSObjectRef propertyCatchalls = JSObjectMake(context, PropertyCatchalls_class(context), NULL);
1050     JSStringRef propertyCatchallsString = JSStringCreateWithUTF8CString("PropertyCatchalls");
1051     JSObjectSetProperty(context, globalObject, propertyCatchallsString, propertyCatchalls, kJSPropertyAttributeNone, NULL);
1052     JSStringRelease(propertyCatchallsString);
1053
1054     JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
1055     JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
1056     JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
1057     JSStringRelease(myObjectIString);
1058     
1059     JSObjectRef EvilExceptionObject = JSObjectMake(context, EvilExceptionObject_class(context), NULL);
1060     JSStringRef EvilExceptionObjectIString = JSStringCreateWithUTF8CString("EvilExceptionObject");
1061     JSObjectSetProperty(context, globalObject, EvilExceptionObjectIString, EvilExceptionObject, kJSPropertyAttributeNone, NULL);
1062     JSStringRelease(EvilExceptionObjectIString);
1063     
1064     JSObjectRef EmptyObject = JSObjectMake(context, EmptyObject_class(context), NULL);
1065     JSStringRef EmptyObjectIString = JSStringCreateWithUTF8CString("EmptyObject");
1066     JSObjectSetProperty(context, globalObject, EmptyObjectIString, EmptyObject, kJSPropertyAttributeNone, NULL);
1067     JSStringRelease(EmptyObjectIString);
1068     
1069     JSStringRef lengthStr = JSStringCreateWithUTF8CString("length");
1070     JSObjectRef aStackRef = JSObjectMakeArray(context, 0, 0, 0);
1071     aHeapRef = aStackRef;
1072     JSObjectSetProperty(context, aHeapRef, lengthStr, JSValueMakeNumber(context, 10), 0, 0);
1073     JSStringRef privatePropertyName = JSStringCreateWithUTF8CString("privateProperty");
1074     if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, aHeapRef)) {
1075         printf("FAIL: Could not set private property.\n");
1076         failed = 1;
1077     } else
1078         printf("PASS: Set private property.\n");
1079     aStackRef = 0;
1080     if (JSObjectSetPrivateProperty(context, aHeapRef, privatePropertyName, aHeapRef)) {
1081         printf("FAIL: JSObjectSetPrivateProperty should fail on non-API objects.\n");
1082         failed = 1;
1083     } else
1084         printf("PASS: Did not allow JSObjectSetPrivateProperty on a non-API object.\n");
1085     if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName) != aHeapRef) {
1086         printf("FAIL: Could not retrieve private property.\n");
1087         failed = 1;
1088     } else
1089         printf("PASS: Retrieved private property.\n");
1090     if (JSObjectGetPrivateProperty(context, aHeapRef, privatePropertyName)) {
1091         printf("FAIL: JSObjectGetPrivateProperty should return NULL when called on a non-API object.\n");
1092         failed = 1;
1093     } else
1094         printf("PASS: JSObjectGetPrivateProperty return NULL.\n");
1095
1096     if (JSObjectGetProperty(context, myObject, privatePropertyName, 0) == aHeapRef) {
1097         printf("FAIL: Accessed private property through ordinary property lookup.\n");
1098         failed = 1;
1099     } else
1100         printf("PASS: Cannot access private property through ordinary property lookup.\n");
1101
1102     JSGarbageCollect(context);
1103
1104     for (int i = 0; i < 10000; i++)
1105         JSObjectMake(context, 0, 0);
1106
1107     aHeapRef = JSValueToObject(context, JSObjectGetPrivateProperty(context, myObject, privatePropertyName), 0);
1108     if (JSValueToNumber(context, JSObjectGetProperty(context, aHeapRef, lengthStr, 0), 0) != 10) {
1109         printf("FAIL: Private property has been collected.\n");
1110         failed = 1;
1111     } else
1112         printf("PASS: Private property does not appear to have been collected.\n");
1113     JSStringRelease(lengthStr);
1114
1115     if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, 0)) {
1116         printf("FAIL: Could not set private property to NULL.\n");
1117         failed = 1;
1118     } else
1119         printf("PASS: Set private property to NULL.\n");
1120     if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName)) {
1121         printf("FAIL: Could not retrieve private property.\n");
1122         failed = 1;
1123     } else
1124         printf("PASS: Retrieved private property.\n");
1125
1126     JSStringRef validJSON = JSStringCreateWithUTF8CString("{\"aProperty\":true}");
1127     JSValueRef jsonObject = JSValueMakeFromJSONString(context, validJSON);
1128     JSStringRelease(validJSON);
1129     if (!JSValueIsObject(context, jsonObject)) {
1130         printf("FAIL: Did not parse valid JSON correctly\n");
1131         failed = 1;
1132     } else
1133         printf("PASS: Parsed valid JSON string.\n");
1134     JSStringRef propertyName = JSStringCreateWithUTF8CString("aProperty");
1135     assertEqualsAsBoolean(JSObjectGetProperty(context, JSValueToObject(context, jsonObject, 0), propertyName, 0), true);
1136     JSStringRelease(propertyName);
1137     JSStringRef invalidJSON = JSStringCreateWithUTF8CString("fail!");
1138     if (JSValueMakeFromJSONString(context, invalidJSON)) {
1139         printf("FAIL: Should return null for invalid JSON data\n");
1140         failed = 1;
1141     } else
1142         printf("PASS: Correctly returned null for invalid JSON data.\n");
1143     JSValueRef exception;
1144     JSStringRef str = JSValueCreateJSONString(context, jsonObject, 0, 0);
1145     if (!JSStringIsEqualToUTF8CString(str, "{\"aProperty\":true}")) {
1146         printf("FAIL: Did not correctly serialise with indent of 0.\n");
1147         failed = 1;
1148     } else
1149         printf("PASS: Correctly serialised with indent of 0.\n");
1150     JSStringRelease(str);
1151
1152     str = JSValueCreateJSONString(context, jsonObject, 4, 0);
1153     if (!JSStringIsEqualToUTF8CString(str, "{\n    \"aProperty\": true\n}")) {
1154         printf("FAIL: Did not correctly serialise with indent of 4.\n");
1155         failed = 1;
1156     } else
1157         printf("PASS: Correctly serialised with indent of 4.\n");
1158     JSStringRelease(str);
1159     JSStringRef src = JSStringCreateWithUTF8CString("({get a(){ throw '';}})");
1160     JSValueRef unstringifiableObj = JSEvaluateScript(context, src, NULL, NULL, 1, NULL);
1161     
1162     str = JSValueCreateJSONString(context, unstringifiableObj, 4, 0);
1163     if (str) {
1164         printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
1165         JSStringRelease(str);
1166         failed = 1;
1167     } else
1168         printf("PASS: returned null when attempting to serialize unserializable value.\n");
1169     
1170     str = JSValueCreateJSONString(context, unstringifiableObj, 4, &exception);
1171     if (str) {
1172         printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
1173         JSStringRelease(str);
1174         failed = 1;
1175     } else
1176         printf("PASS: returned null when attempting to serialize unserializable value.\n");
1177     if (!exception) {
1178         printf("FAIL: Did not set exception on serialisation error\n");
1179         failed = 1;
1180     } else
1181         printf("PASS: set exception on serialisation error\n");
1182     // Conversions that throw exceptions
1183     exception = NULL;
1184     ASSERT(NULL == JSValueToObject(context, jsNull, &exception));
1185     ASSERT(exception);
1186     
1187     exception = NULL;
1188     // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
1189     // causing a build break with -Wshorten-64-to-32 enabled.  The issue is known by the appropriate team.
1190     // After that's resolved, we can remove these casts
1191     ASSERT(isnan((float)JSValueToNumber(context, jsObjectNoProto, &exception)));
1192     ASSERT(exception);
1193
1194     exception = NULL;
1195     ASSERT(!JSValueToStringCopy(context, jsObjectNoProto, &exception));
1196     ASSERT(exception);
1197     
1198     ASSERT(JSValueToBoolean(context, myObject));
1199     
1200     exception = NULL;
1201     ASSERT(!JSValueIsEqual(context, jsObjectNoProto, JSValueMakeNumber(context, 1), &exception));
1202     ASSERT(exception);
1203     
1204     exception = NULL;
1205     JSObjectGetPropertyAtIndex(context, myObject, 0, &exception);
1206     ASSERT(1 == JSValueToNumber(context, exception, NULL));
1207
1208     assertEqualsAsBoolean(jsUndefined, false);
1209     assertEqualsAsBoolean(jsNull, false);
1210     assertEqualsAsBoolean(jsTrue, true);
1211     assertEqualsAsBoolean(jsFalse, false);
1212     assertEqualsAsBoolean(jsZero, false);
1213     assertEqualsAsBoolean(jsOne, true);
1214     assertEqualsAsBoolean(jsOneThird, true);
1215     assertEqualsAsBoolean(jsEmptyString, false);
1216     assertEqualsAsBoolean(jsOneString, true);
1217     assertEqualsAsBoolean(jsCFString, true);
1218     assertEqualsAsBoolean(jsCFStringWithCharacters, true);
1219     assertEqualsAsBoolean(jsCFEmptyString, false);
1220     assertEqualsAsBoolean(jsCFEmptyStringWithCharacters, false);
1221     
1222     assertEqualsAsNumber(jsUndefined, nan(""));
1223     assertEqualsAsNumber(jsNull, 0);
1224     assertEqualsAsNumber(jsTrue, 1);
1225     assertEqualsAsNumber(jsFalse, 0);
1226     assertEqualsAsNumber(jsZero, 0);
1227     assertEqualsAsNumber(jsOne, 1);
1228     assertEqualsAsNumber(jsOneThird, 1.0 / 3.0);
1229     assertEqualsAsNumber(jsEmptyString, 0);
1230     assertEqualsAsNumber(jsOneString, 1);
1231     assertEqualsAsNumber(jsCFString, nan(""));
1232     assertEqualsAsNumber(jsCFStringWithCharacters, nan(""));
1233     assertEqualsAsNumber(jsCFEmptyString, 0);
1234     assertEqualsAsNumber(jsCFEmptyStringWithCharacters, 0);
1235     ASSERT(sizeof(JSChar) == sizeof(UniChar));
1236     
1237     assertEqualsAsCharactersPtr(jsUndefined, "undefined");
1238     assertEqualsAsCharactersPtr(jsNull, "null");
1239     assertEqualsAsCharactersPtr(jsTrue, "true");
1240     assertEqualsAsCharactersPtr(jsFalse, "false");
1241     assertEqualsAsCharactersPtr(jsZero, "0");
1242     assertEqualsAsCharactersPtr(jsOne, "1");
1243     assertEqualsAsCharactersPtr(jsOneThird, "0.3333333333333333");
1244     assertEqualsAsCharactersPtr(jsEmptyString, "");
1245     assertEqualsAsCharactersPtr(jsOneString, "1");
1246     assertEqualsAsCharactersPtr(jsCFString, "A");
1247     assertEqualsAsCharactersPtr(jsCFStringWithCharacters, "A");
1248     assertEqualsAsCharactersPtr(jsCFEmptyString, "");
1249     assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters, "");
1250     
1251     assertEqualsAsUTF8String(jsUndefined, "undefined");
1252     assertEqualsAsUTF8String(jsNull, "null");
1253     assertEqualsAsUTF8String(jsTrue, "true");
1254     assertEqualsAsUTF8String(jsFalse, "false");
1255     assertEqualsAsUTF8String(jsZero, "0");
1256     assertEqualsAsUTF8String(jsOne, "1");
1257     assertEqualsAsUTF8String(jsOneThird, "0.3333333333333333");
1258     assertEqualsAsUTF8String(jsEmptyString, "");
1259     assertEqualsAsUTF8String(jsOneString, "1");
1260     assertEqualsAsUTF8String(jsCFString, "A");
1261     assertEqualsAsUTF8String(jsCFStringWithCharacters, "A");
1262     assertEqualsAsUTF8String(jsCFEmptyString, "");
1263     assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters, "");
1264     
1265     checkConstnessInJSObjectNames();
1266     
1267     ASSERT(JSValueIsStrictEqual(context, jsTrue, jsTrue));
1268     ASSERT(!JSValueIsStrictEqual(context, jsOne, jsOneString));
1269
1270     ASSERT(JSValueIsEqual(context, jsOne, jsOneString, NULL));
1271     ASSERT(!JSValueIsEqual(context, jsTrue, jsFalse, NULL));
1272     
1273     CFStringRef cfJSString = JSStringCopyCFString(kCFAllocatorDefault, jsCFIString);
1274     CFStringRef cfJSEmptyString = JSStringCopyCFString(kCFAllocatorDefault, jsCFEmptyIString);
1275     ASSERT(CFEqual(cfJSString, cfString));
1276     ASSERT(CFEqual(cfJSEmptyString, cfEmptyString));
1277     CFRelease(cfJSString);
1278     CFRelease(cfJSEmptyString);
1279
1280     CFRelease(cfString);
1281     CFRelease(cfEmptyString);
1282     
1283     jsGlobalValue = JSObjectMake(context, NULL, NULL);
1284     makeGlobalNumberValue(context);
1285     JSValueProtect(context, jsGlobalValue);
1286     JSGarbageCollect(context);
1287     ASSERT(JSValueIsObject(context, jsGlobalValue));
1288     JSValueUnprotect(context, jsGlobalValue);
1289     JSValueUnprotect(context, jsNumberValue);
1290
1291     JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;");
1292     JSStringRef badSyntax = JSStringCreateWithUTF8CString("x := 1;");
1293     ASSERT(JSCheckScriptSyntax(context, goodSyntax, NULL, 0, NULL));
1294     ASSERT(!JSCheckScriptSyntax(context, badSyntax, NULL, 0, NULL));
1295
1296     JSValueRef result;
1297     JSValueRef v;
1298     JSObjectRef o;
1299     JSStringRef string;
1300
1301     result = JSEvaluateScript(context, goodSyntax, NULL, NULL, 1, NULL);
1302     ASSERT(result);
1303     ASSERT(JSValueIsEqual(context, result, jsOne, NULL));
1304
1305     exception = NULL;
1306     result = JSEvaluateScript(context, badSyntax, NULL, NULL, 1, &exception);
1307     ASSERT(!result);
1308     ASSERT(JSValueIsObject(context, exception));
1309     
1310     JSStringRef array = JSStringCreateWithUTF8CString("Array");
1311     JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
1312     JSStringRelease(array);
1313     result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL);
1314     ASSERT(result);
1315     ASSERT(JSValueIsObject(context, result));
1316     ASSERT(JSValueIsInstanceOfConstructor(context, result, arrayConstructor, NULL));
1317     ASSERT(!JSValueIsInstanceOfConstructor(context, JSValueMakeNull(context), arrayConstructor, NULL));
1318
1319     o = JSValueToObject(context, result, NULL);
1320     exception = NULL;
1321     ASSERT(JSValueIsUndefined(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception)));
1322     ASSERT(!exception);
1323     
1324     JSObjectSetPropertyAtIndex(context, o, 0, JSValueMakeNumber(context, 1), &exception);
1325     ASSERT(!exception);
1326     
1327     exception = NULL;
1328     ASSERT(1 == JSValueToNumber(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception), &exception));
1329     ASSERT(!exception);
1330
1331     JSStringRef functionBody;
1332     JSObjectRef function;
1333     
1334     exception = NULL;
1335     functionBody = JSStringCreateWithUTF8CString("rreturn Array;");
1336     JSStringRef line = JSStringCreateWithUTF8CString("line");
1337     ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception));
1338     ASSERT(JSValueIsObject(context, exception));
1339     v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL);
1340     assertEqualsAsNumber(v, 1);
1341     JSStringRelease(functionBody);
1342     JSStringRelease(line);
1343
1344     exception = NULL;
1345     functionBody = JSStringCreateWithUTF8CString("return Array;");
1346     function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception);
1347     JSStringRelease(functionBody);
1348     ASSERT(!exception);
1349     ASSERT(JSObjectIsFunction(context, function));
1350     v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1351     ASSERT(v);
1352     ASSERT(JSValueIsEqual(context, v, arrayConstructor, NULL));
1353     
1354     exception = NULL;
1355     function = JSObjectMakeFunction(context, NULL, 0, NULL, jsEmptyIString, NULL, 0, &exception);
1356     ASSERT(!exception);
1357     v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, &exception);
1358     ASSERT(v && !exception);
1359     ASSERT(JSValueIsUndefined(context, v));
1360     
1361     exception = NULL;
1362     v = NULL;
1363     JSStringRef foo = JSStringCreateWithUTF8CString("foo");
1364     JSStringRef argumentNames[] = { foo };
1365     functionBody = JSStringCreateWithUTF8CString("return foo;");
1366     function = JSObjectMakeFunction(context, foo, 1, argumentNames, functionBody, NULL, 1, &exception);
1367     ASSERT(function && !exception);
1368     JSValueRef arguments[] = { JSValueMakeNumber(context, 2) };
1369     JSObjectCallAsFunction(context, function, NULL, 1, arguments, &exception);
1370     JSStringRelease(foo);
1371     JSStringRelease(functionBody);
1372     
1373     string = JSValueToStringCopy(context, function, NULL);
1374     assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) { return foo;\n}");
1375     JSStringRelease(string);
1376
1377     JSStringRef print = JSStringCreateWithUTF8CString("print");
1378     JSObjectRef printFunction = JSObjectMakeFunctionWithCallback(context, print, print_callAsFunction);
1379     JSObjectSetProperty(context, globalObject, print, printFunction, kJSPropertyAttributeNone, NULL); 
1380     JSStringRelease(print);
1381     
1382     ASSERT(!JSObjectSetPrivate(printFunction, (void*)1));
1383     ASSERT(!JSObjectGetPrivate(printFunction));
1384
1385     JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor");
1386     JSObjectRef myConstructor = JSObjectMakeConstructor(context, NULL, myConstructor_callAsConstructor);
1387     JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL);
1388     JSStringRelease(myConstructorIString);
1389     
1390     ASSERT(!JSObjectSetPrivate(myConstructor, (void*)1));
1391     ASSERT(!JSObjectGetPrivate(myConstructor));
1392     
1393     string = JSStringCreateWithUTF8CString("Base");
1394     JSObjectRef baseConstructor = JSObjectMakeConstructor(context, Base_class(context), NULL);
1395     JSObjectSetProperty(context, globalObject, string, baseConstructor, kJSPropertyAttributeNone, NULL);
1396     JSStringRelease(string);
1397     
1398     string = JSStringCreateWithUTF8CString("Derived");
1399     JSObjectRef derivedConstructor = JSObjectMakeConstructor(context, Derived_class(context), NULL);
1400     JSObjectSetProperty(context, globalObject, string, derivedConstructor, kJSPropertyAttributeNone, NULL);
1401     JSStringRelease(string);
1402     
1403     string = JSStringCreateWithUTF8CString("Derived2");
1404     JSObjectRef derived2Constructor = JSObjectMakeConstructor(context, Derived2_class(context), NULL);
1405     JSObjectSetProperty(context, globalObject, string, derived2Constructor, kJSPropertyAttributeNone, NULL);
1406     JSStringRelease(string);
1407
1408     o = JSObjectMake(context, NULL, NULL);
1409     JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL);
1410     JSObjectSetProperty(context, o, jsCFIString,  JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL);
1411     JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o);
1412     size_t expectedCount = JSPropertyNameArrayGetCount(nameArray);
1413     size_t count;
1414     for (count = 0; count < expectedCount; ++count)
1415         JSPropertyNameArrayGetNameAtIndex(nameArray, count);
1416     JSPropertyNameArrayRelease(nameArray);
1417     ASSERT(count == 1); // jsCFString should not be enumerated
1418
1419     JSValueRef argumentsArrayValues[] = { JSValueMakeNumber(context, 10), JSValueMakeNumber(context, 20) };
1420     o = JSObjectMakeArray(context, sizeof(argumentsArrayValues) / sizeof(JSValueRef), argumentsArrayValues, NULL);
1421     string = JSStringCreateWithUTF8CString("length");
1422     v = JSObjectGetProperty(context, o, string, NULL);
1423     assertEqualsAsNumber(v, 2);
1424     v = JSObjectGetPropertyAtIndex(context, o, 0, NULL);
1425     assertEqualsAsNumber(v, 10);
1426     v = JSObjectGetPropertyAtIndex(context, o, 1, NULL);
1427     assertEqualsAsNumber(v, 20);
1428
1429     o = JSObjectMakeArray(context, 0, NULL, NULL);
1430     v = JSObjectGetProperty(context, o, string, NULL);
1431     assertEqualsAsNumber(v, 0);
1432     JSStringRelease(string);
1433
1434     JSValueRef argumentsDateValues[] = { JSValueMakeNumber(context, 0) };
1435     o = JSObjectMakeDate(context, 1, argumentsDateValues, NULL);
1436     if (timeZoneIsPST())
1437         assertEqualsAsUTF8String(o, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)");
1438
1439     string = JSStringCreateWithUTF8CString("an error message");
1440     JSValueRef argumentsErrorValues[] = { JSValueMakeString(context, string) };
1441     o = JSObjectMakeError(context, 1, argumentsErrorValues, NULL);
1442     assertEqualsAsUTF8String(o, "Error: an error message");
1443     JSStringRelease(string);
1444
1445     string = JSStringCreateWithUTF8CString("foo");
1446     JSStringRef string2 = JSStringCreateWithUTF8CString("gi");
1447     JSValueRef argumentsRegExpValues[] = { JSValueMakeString(context, string), JSValueMakeString(context, string2) };
1448     o = JSObjectMakeRegExp(context, 2, argumentsRegExpValues, NULL);
1449     assertEqualsAsUTF8String(o, "/foo/gi");
1450     JSStringRelease(string);
1451     JSStringRelease(string2);
1452
1453     JSClassDefinition nullDefinition = kJSClassDefinitionEmpty;
1454     nullDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
1455     JSClassRef nullClass = JSClassCreate(&nullDefinition);
1456     JSClassRelease(nullClass);
1457     
1458     nullDefinition = kJSClassDefinitionEmpty;
1459     nullClass = JSClassCreate(&nullDefinition);
1460     JSClassRelease(nullClass);
1461
1462     functionBody = JSStringCreateWithUTF8CString("return this;");
1463     function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
1464     JSStringRelease(functionBody);
1465     v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1466     ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1467     v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
1468     ASSERT(JSValueIsEqual(context, v, o, NULL));
1469
1470     functionBody = JSStringCreateWithUTF8CString("return eval(\"this\");");
1471     function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
1472     JSStringRelease(functionBody);
1473     v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1474     ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1475     v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
1476     ASSERT(JSValueIsEqual(context, v, o, NULL));
1477
1478     JSStringRef script = JSStringCreateWithUTF8CString("this;");
1479     v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
1480     ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1481     v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
1482     ASSERT(JSValueIsEqual(context, v, o, NULL));
1483     JSStringRelease(script);
1484
1485     script = JSStringCreateWithUTF8CString("eval(this);");
1486     v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
1487     ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1488     v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
1489     ASSERT(JSValueIsEqual(context, v, o, NULL));
1490     JSStringRelease(script);
1491
1492     // Verify that creating a constructor for a class with no static functions does not trigger
1493     // an assert inside putDirect or lead to a crash during GC. <https://bugs.webkit.org/show_bug.cgi?id=25785>
1494     nullDefinition = kJSClassDefinitionEmpty;
1495     nullClass = JSClassCreate(&nullDefinition);
1496     JSObjectMakeConstructor(context, nullClass, 0);
1497     JSClassRelease(nullClass);
1498
1499     char* scriptUTF8 = createStringWithContentsOfFile(scriptPath);
1500     if (!scriptUTF8) {
1501         printf("FAIL: Test script could not be loaded.\n");
1502         failed = 1;
1503     } else {
1504         script = JSStringCreateWithUTF8CString(scriptUTF8);
1505         result = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
1506         if (result && JSValueIsUndefined(context, result))
1507             printf("PASS: Test script executed successfully.\n");
1508         else {
1509             printf("FAIL: Test script returned unexpected value:\n");
1510             JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL);
1511             CFStringRef exceptionCF = JSStringCopyCFString(kCFAllocatorDefault, exceptionIString);
1512             CFShow(exceptionCF);
1513             CFRelease(exceptionCF);
1514             JSStringRelease(exceptionIString);
1515             failed = 1;
1516         }
1517         JSStringRelease(script);
1518         free(scriptUTF8);
1519     }
1520
1521     // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
1522     function = NULL;
1523     v = NULL;
1524     o = NULL;
1525     globalObject = NULL;
1526     myConstructor = NULL;
1527
1528     JSStringRelease(jsEmptyIString);
1529     JSStringRelease(jsOneIString);
1530     JSStringRelease(jsCFIString);
1531     JSStringRelease(jsCFEmptyIString);
1532     JSStringRelease(jsCFIStringWithCharacters);
1533     JSStringRelease(jsCFEmptyIStringWithCharacters);
1534     JSStringRelease(goodSyntax);
1535     JSStringRelease(badSyntax);
1536
1537     JSGlobalContextRelease(context);
1538     JSClassRelease(globalObjectClass);
1539
1540     // Test for an infinite prototype chain that used to be created. This test
1541     // passes if the call to JSObjectHasProperty() does not hang.
1542
1543     JSClassDefinition prototypeLoopClassDefinition = kJSClassDefinitionEmpty;
1544     prototypeLoopClassDefinition.staticFunctions = globalObject_staticFunctions;
1545     JSClassRef prototypeLoopClass = JSClassCreate(&prototypeLoopClassDefinition);
1546     JSGlobalContextRef prototypeLoopContext = JSGlobalContextCreateInGroup(NULL, prototypeLoopClass);
1547
1548     JSStringRef nameProperty = JSStringCreateWithUTF8CString("name");
1549     JSObjectHasProperty(prototypeLoopContext, JSContextGetGlobalObject(prototypeLoopContext), nameProperty);
1550
1551     JSGlobalContextRelease(prototypeLoopContext);
1552     JSClassRelease(prototypeLoopClass);
1553
1554     printf("PASS: Infinite prototype chain does not occur.\n");
1555
1556     if (checkForCycleInPrototypeChain())
1557         printf("PASS: A cycle in a prototype chain can't be created.\n");
1558     else {
1559         printf("FAIL: A cycle in a prototype chain can be created.\n");
1560         failed = true;
1561     }
1562
1563     if (failed) {
1564         printf("FAIL: Some tests failed.\n");
1565         return 1;
1566     }
1567
1568     printf("PASS: Program exited normally.\n");
1569     return 0;
1570 }
1571
1572 static char* createStringWithContentsOfFile(const char* fileName)
1573 {
1574     char* buffer;
1575     
1576     size_t buffer_size = 0;
1577     size_t buffer_capacity = 1024;
1578     buffer = (char*)malloc(buffer_capacity);
1579     
1580     FILE* f = fopen(fileName, "r");
1581     if (!f) {
1582         fprintf(stderr, "Could not open file: %s\n", fileName);
1583         return 0;
1584     }
1585     
1586     while (!feof(f) && !ferror(f)) {
1587         buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f);
1588         if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0'
1589             buffer_capacity *= 2;
1590             buffer = (char*)realloc(buffer, buffer_capacity);
1591             ASSERT(buffer);
1592         }
1593         
1594         ASSERT(buffer_size < buffer_capacity);
1595     }
1596     fclose(f);
1597     buffer[buffer_size] = '\0';
1598     
1599     return buffer;
1600 }