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