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