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