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