]> git.saurik.com Git - apple/javascriptcore.git/blob - API/tests/testapi.c
1f413e184365f76562bfbcb8fe4d406060a94f6e
[apple/javascriptcore.git] / API / tests / testapi.c
1 /*
2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "JavaScriptCore.h"
27 #include "JSBasePrivate.h"
28 #include <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
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;
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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;
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;
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }