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