]> git.saurik.com Git - apple/javascriptcore.git/blob - API/tests/testapi.c
JavaScriptCore-7600.1.4.17.5.tar.gz
[apple/javascriptcore.git] / API / tests / testapi.c
1 /*
2 * Copyright (C) 2006 Apple 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 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 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 <wtf/Platform.h>
27
28 #include "JavaScriptCore.h"
29 #include "JSBasePrivate.h"
30 #include "JSContextRefPrivate.h"
31 #include "JSObjectRefPrivate.h"
32 #include "JSScriptRefPrivate.h"
33 #include "JSStringRefPrivate.h"
34 #include <math.h>
35 #define ASSERT_DISABLED 0
36 #include <wtf/Assertions.h>
37
38 #if OS(DARWIN)
39 #include <mach/mach.h>
40 #include <mach/mach_time.h>
41 #include <sys/time.h>
42 #endif
43
44 #if OS(WINDOWS)
45 #include <windows.h>
46 #endif
47
48 #include "CustomGlobalObjectClassTest.h"
49
50 #if JSC_OBJC_API_ENABLED
51 void testObjectiveCAPI(void);
52 #endif
53
54 bool assertTrue(bool value, const char* message);
55 extern void JSSynchronousGarbageCollectForDebugging(JSContextRef);
56
57 static JSGlobalContextRef context;
58 int failed;
59 static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue)
60 {
61 if (JSValueToBoolean(context, value) != expectedValue) {
62 fprintf(stderr, "assertEqualsAsBoolean failed: %p, %d\n", value, expectedValue);
63 failed = 1;
64 }
65 }
66
67 static void assertEqualsAsNumber(JSValueRef value, double expectedValue)
68 {
69 double number = JSValueToNumber(context, value, NULL);
70
71 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
72 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
73 // After that's resolved, we can remove these casts
74 if (number != expectedValue && !(isnan((float)number) && isnan((float)expectedValue))) {
75 fprintf(stderr, "assertEqualsAsNumber failed: %p, %lf\n", value, expectedValue);
76 failed = 1;
77 }
78 }
79
80 static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue)
81 {
82 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
83
84 size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString);
85 char* jsBuffer = (char*)malloc(jsSize);
86 JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize);
87
88 unsigned i;
89 for (i = 0; jsBuffer[i]; i++) {
90 if (jsBuffer[i] != expectedValue[i]) {
91 fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]);
92 failed = 1;
93 }
94 }
95
96 if (jsSize < strlen(jsBuffer) + 1) {
97 fprintf(stderr, "assertEqualsAsUTF8String failed: jsSize was too small\n");
98 failed = 1;
99 }
100
101 free(jsBuffer);
102 JSStringRelease(valueAsString);
103 }
104
105 static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedValue)
106 {
107 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
108
109 size_t jsLength = JSStringGetLength(valueAsString);
110 const JSChar* jsBuffer = JSStringGetCharactersPtr(valueAsString);
111
112 CFStringRef expectedValueAsCFString = CFStringCreateWithCString(kCFAllocatorDefault,
113 expectedValue,
114 kCFStringEncodingUTF8);
115 CFIndex cfLength = CFStringGetLength(expectedValueAsCFString);
116 UniChar* cfBuffer = (UniChar*)malloc(cfLength * sizeof(UniChar));
117 CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer);
118 CFRelease(expectedValueAsCFString);
119
120 if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0) {
121 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n");
122 failed = 1;
123 }
124
125 if (jsLength != (size_t)cfLength) {
126 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength);
127 failed = 1;
128 }
129
130 free(cfBuffer);
131 JSStringRelease(valueAsString);
132 }
133
134 static bool timeZoneIsPST()
135 {
136 char timeZoneName[70];
137 struct tm gtm;
138 memset(&gtm, 0, sizeof(gtm));
139 strftime(timeZoneName, sizeof(timeZoneName), "%Z", &gtm);
140
141 return 0 == strcmp("PST", timeZoneName);
142 }
143
144 static JSValueRef jsGlobalValue; // non-stack value for testing JSValueProtect()
145
146 /* MyObject pseudo-class */
147
148 static bool MyObject_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName)
149 {
150 UNUSED_PARAM(context);
151 UNUSED_PARAM(object);
152
153 if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")
154 || JSStringIsEqualToUTF8CString(propertyName, "cantFind")
155 || JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")
156 || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")
157 || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")
158 || JSStringIsEqualToUTF8CString(propertyName, "0")) {
159 return true;
160 }
161
162 return false;
163 }
164
165 static JSValueRef MyObject_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
166 {
167 UNUSED_PARAM(context);
168 UNUSED_PARAM(object);
169
170 if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")) {
171 return JSValueMakeNumber(context, 1);
172 }
173
174 if (JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")) {
175 return JSValueMakeNumber(context, 1);
176 }
177
178 if (JSStringIsEqualToUTF8CString(propertyName, "cantFind")) {
179 return JSValueMakeUndefined(context);
180 }
181
182 if (JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")) {
183 return 0;
184 }
185
186 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")) {
187 return JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
188 }
189
190 if (JSStringIsEqualToUTF8CString(propertyName, "0")) {
191 *exception = JSValueMakeNumber(context, 1);
192 return JSValueMakeNumber(context, 1);
193 }
194
195 return JSValueMakeNull(context);
196 }
197
198 static bool MyObject_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
199 {
200 UNUSED_PARAM(context);
201 UNUSED_PARAM(object);
202 UNUSED_PARAM(value);
203 UNUSED_PARAM(exception);
204
205 if (JSStringIsEqualToUTF8CString(propertyName, "cantSet"))
206 return true; // pretend we set the property in order to swallow it
207
208 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnSet")) {
209 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
210 }
211
212 return false;
213 }
214
215 static bool MyObject_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
216 {
217 UNUSED_PARAM(context);
218 UNUSED_PARAM(object);
219
220 if (JSStringIsEqualToUTF8CString(propertyName, "cantDelete"))
221 return true;
222
223 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnDelete")) {
224 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
225 return false;
226 }
227
228 return false;
229 }
230
231 static void MyObject_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
232 {
233 UNUSED_PARAM(context);
234 UNUSED_PARAM(object);
235
236 JSStringRef propertyName;
237
238 propertyName = JSStringCreateWithUTF8CString("alwaysOne");
239 JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
240 JSStringRelease(propertyName);
241
242 propertyName = JSStringCreateWithUTF8CString("myPropertyName");
243 JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
244 JSStringRelease(propertyName);
245 }
246
247 static JSValueRef MyObject_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
248 {
249 UNUSED_PARAM(context);
250 UNUSED_PARAM(object);
251 UNUSED_PARAM(thisObject);
252 UNUSED_PARAM(exception);
253
254 if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnCall")) {
255 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
256 return JSValueMakeUndefined(context);
257 }
258
259 if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
260 return JSValueMakeNumber(context, 1);
261
262 return JSValueMakeUndefined(context);
263 }
264
265 static JSObjectRef MyObject_callAsConstructor(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
266 {
267 UNUSED_PARAM(context);
268 UNUSED_PARAM(object);
269
270 if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnConstruct")) {
271 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
272 return object;
273 }
274
275 if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
276 return JSValueToObject(context, JSValueMakeNumber(context, 1), exception);
277
278 return JSValueToObject(context, JSValueMakeNumber(context, 0), exception);
279 }
280
281 static bool MyObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
282 {
283 UNUSED_PARAM(context);
284 UNUSED_PARAM(constructor);
285
286 if (JSValueIsString(context, possibleValue) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, possibleValue, 0), "throwOnHasInstance")) {
287 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), constructor, JSStringCreateWithUTF8CString("test script"), 1, exception);
288 return false;
289 }
290
291 JSStringRef numberString = JSStringCreateWithUTF8CString("Number");
292 JSObjectRef numberConstructor = JSValueToObject(context, JSObjectGetProperty(context, JSContextGetGlobalObject(context), numberString, exception), exception);
293 JSStringRelease(numberString);
294
295 return JSValueIsInstanceOfConstructor(context, possibleValue, numberConstructor, exception);
296 }
297
298 static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
299 {
300 UNUSED_PARAM(object);
301 UNUSED_PARAM(exception);
302
303 switch (type) {
304 case kJSTypeNumber:
305 return JSValueMakeNumber(context, 1);
306 case kJSTypeString:
307 {
308 JSStringRef string = JSStringCreateWithUTF8CString("MyObjectAsString");
309 JSValueRef result = JSValueMakeString(context, string);
310 JSStringRelease(string);
311 return result;
312 }
313 default:
314 break;
315 }
316
317 // string conversion -- forward to default object class
318 return JSValueMakeNull(context);
319 }
320
321 static JSValueRef MyObject_convertToTypeWrapper(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
322 {
323 UNUSED_PARAM(context);
324 UNUSED_PARAM(object);
325 UNUSED_PARAM(type);
326 UNUSED_PARAM(exception);
327 // Forward to default object class
328 return 0;
329 }
330
331 static bool MyObject_set_nullGetForwardSet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
332 {
333 UNUSED_PARAM(ctx);
334 UNUSED_PARAM(object);
335 UNUSED_PARAM(propertyName);
336 UNUSED_PARAM(value);
337 UNUSED_PARAM(exception);
338 return false; // Forward to parent class.
339 }
340
341 static JSStaticValue evilStaticValues[] = {
342 { "nullGetSet", 0, 0, kJSPropertyAttributeNone },
343 { "nullGetForwardSet", 0, MyObject_set_nullGetForwardSet, kJSPropertyAttributeNone },
344 { 0, 0, 0, 0 }
345 };
346
347 static JSStaticFunction evilStaticFunctions[] = {
348 { "nullCall", 0, kJSPropertyAttributeNone },
349 { 0, 0, 0 }
350 };
351
352 JSClassDefinition MyObject_definition = {
353 0,
354 kJSClassAttributeNone,
355
356 "MyObject",
357 NULL,
358
359 evilStaticValues,
360 evilStaticFunctions,
361
362 NULL,
363 NULL,
364 MyObject_hasProperty,
365 MyObject_getProperty,
366 MyObject_setProperty,
367 MyObject_deleteProperty,
368 MyObject_getPropertyNames,
369 MyObject_callAsFunction,
370 MyObject_callAsConstructor,
371 MyObject_hasInstance,
372 MyObject_convertToType,
373 };
374
375 JSClassDefinition MyObject_convertToTypeWrapperDefinition = {
376 0,
377 kJSClassAttributeNone,
378
379 "MyObject",
380 NULL,
381
382 NULL,
383 NULL,
384
385 NULL,
386 NULL,
387 NULL,
388 NULL,
389 NULL,
390 NULL,
391 NULL,
392 NULL,
393 NULL,
394 NULL,
395 MyObject_convertToTypeWrapper,
396 };
397
398 JSClassDefinition MyObject_nullWrapperDefinition = {
399 0,
400 kJSClassAttributeNone,
401
402 "MyObject",
403 NULL,
404
405 NULL,
406 NULL,
407
408 NULL,
409 NULL,
410 NULL,
411 NULL,
412 NULL,
413 NULL,
414 NULL,
415 NULL,
416 NULL,
417 NULL,
418 NULL,
419 };
420
421 static JSClassRef MyObject_class(JSContextRef context)
422 {
423 UNUSED_PARAM(context);
424
425 static JSClassRef jsClass;
426 if (!jsClass) {
427 JSClassRef baseClass = JSClassCreate(&MyObject_definition);
428 MyObject_convertToTypeWrapperDefinition.parentClass = baseClass;
429 JSClassRef wrapperClass = JSClassCreate(&MyObject_convertToTypeWrapperDefinition);
430 MyObject_nullWrapperDefinition.parentClass = wrapperClass;
431 jsClass = JSClassCreate(&MyObject_nullWrapperDefinition);
432 }
433
434 return jsClass;
435 }
436
437 static JSValueRef PropertyCatchalls_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
438 {
439 UNUSED_PARAM(context);
440 UNUSED_PARAM(object);
441 UNUSED_PARAM(propertyName);
442 UNUSED_PARAM(exception);
443
444 if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
445 static size_t count;
446 if (count++ < 5)
447 return NULL;
448
449 // Swallow all .x gets after 5, returning null.
450 return JSValueMakeNull(context);
451 }
452
453 if (JSStringIsEqualToUTF8CString(propertyName, "y")) {
454 static size_t count;
455 if (count++ < 5)
456 return NULL;
457
458 // Swallow all .y gets after 5, returning null.
459 return JSValueMakeNull(context);
460 }
461
462 if (JSStringIsEqualToUTF8CString(propertyName, "z")) {
463 static size_t count;
464 if (count++ < 5)
465 return NULL;
466
467 // Swallow all .y gets after 5, returning null.
468 return JSValueMakeNull(context);
469 }
470
471 return NULL;
472 }
473
474 static bool PropertyCatchalls_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
475 {
476 UNUSED_PARAM(context);
477 UNUSED_PARAM(object);
478 UNUSED_PARAM(propertyName);
479 UNUSED_PARAM(value);
480 UNUSED_PARAM(exception);
481
482 if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
483 static size_t count;
484 if (count++ < 5)
485 return false;
486
487 // Swallow all .x sets after 4.
488 return true;
489 }
490
491 if (JSStringIsEqualToUTF8CString(propertyName, "make_throw") || JSStringIsEqualToUTF8CString(propertyName, "0")) {
492 *exception = JSValueMakeNumber(context, 5);
493 return true;
494 }
495
496 return false;
497 }
498
499 static void PropertyCatchalls_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
500 {
501 UNUSED_PARAM(context);
502 UNUSED_PARAM(object);
503
504 static size_t count;
505 static const char* numbers[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
506
507 // Provide a property of a different name every time.
508 JSStringRef propertyName = JSStringCreateWithUTF8CString(numbers[count++ % 10]);
509 JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
510 JSStringRelease(propertyName);
511 }
512
513 JSClassDefinition PropertyCatchalls_definition = {
514 0,
515 kJSClassAttributeNone,
516
517 "PropertyCatchalls",
518 NULL,
519
520 NULL,
521 NULL,
522
523 NULL,
524 NULL,
525 NULL,
526 PropertyCatchalls_getProperty,
527 PropertyCatchalls_setProperty,
528 NULL,
529 PropertyCatchalls_getPropertyNames,
530 NULL,
531 NULL,
532 NULL,
533 NULL,
534 };
535
536 static JSClassRef PropertyCatchalls_class(JSContextRef context)
537 {
538 UNUSED_PARAM(context);
539
540 static JSClassRef jsClass;
541 if (!jsClass)
542 jsClass = JSClassCreate(&PropertyCatchalls_definition);
543
544 return jsClass;
545 }
546
547 static bool EvilExceptionObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
548 {
549 UNUSED_PARAM(context);
550 UNUSED_PARAM(constructor);
551
552 JSStringRef hasInstanceName = JSStringCreateWithUTF8CString("hasInstance");
553 JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception);
554 JSStringRelease(hasInstanceName);
555 if (!hasInstance)
556 return false;
557 JSObjectRef function = JSValueToObject(context, hasInstance, exception);
558 JSValueRef result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception);
559 return result && JSValueToBoolean(context, result);
560 }
561
562 static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
563 {
564 UNUSED_PARAM(object);
565 UNUSED_PARAM(exception);
566 JSStringRef funcName;
567 switch (type) {
568 case kJSTypeNumber:
569 funcName = JSStringCreateWithUTF8CString("toNumber");
570 break;
571 case kJSTypeString:
572 funcName = JSStringCreateWithUTF8CString("toStringExplicit");
573 break;
574 default:
575 return JSValueMakeNull(context);
576 }
577
578 JSValueRef func = JSObjectGetProperty(context, object, funcName, exception);
579 JSStringRelease(funcName);
580 JSObjectRef function = JSValueToObject(context, func, exception);
581 if (!function)
582 return JSValueMakeNull(context);
583 JSValueRef value = JSObjectCallAsFunction(context, function, object, 0, NULL, exception);
584 if (!value) {
585 JSStringRef errorString = JSStringCreateWithUTF8CString("convertToType failed");
586 JSValueRef errorStringRef = JSValueMakeString(context, errorString);
587 JSStringRelease(errorString);
588 return errorStringRef;
589 }
590 return value;
591 }
592
593 JSClassDefinition EvilExceptionObject_definition = {
594 0,
595 kJSClassAttributeNone,
596
597 "EvilExceptionObject",
598 NULL,
599
600 NULL,
601 NULL,
602
603 NULL,
604 NULL,
605 NULL,
606 NULL,
607 NULL,
608 NULL,
609 NULL,
610 NULL,
611 NULL,
612 EvilExceptionObject_hasInstance,
613 EvilExceptionObject_convertToType,
614 };
615
616 static JSClassRef EvilExceptionObject_class(JSContextRef context)
617 {
618 UNUSED_PARAM(context);
619
620 static JSClassRef jsClass;
621 if (!jsClass)
622 jsClass = JSClassCreate(&EvilExceptionObject_definition);
623
624 return jsClass;
625 }
626
627 JSClassDefinition EmptyObject_definition = {
628 0,
629 kJSClassAttributeNone,
630
631 NULL,
632 NULL,
633
634 NULL,
635 NULL,
636
637 NULL,
638 NULL,
639 NULL,
640 NULL,
641 NULL,
642 NULL,
643 NULL,
644 NULL,
645 NULL,
646 NULL,
647 NULL,
648 };
649
650 static JSClassRef EmptyObject_class(JSContextRef context)
651 {
652 UNUSED_PARAM(context);
653
654 static JSClassRef jsClass;
655 if (!jsClass)
656 jsClass = JSClassCreate(&EmptyObject_definition);
657
658 return jsClass;
659 }
660
661
662 static JSValueRef Base_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
663 {
664 UNUSED_PARAM(object);
665 UNUSED_PARAM(propertyName);
666 UNUSED_PARAM(exception);
667
668 return JSValueMakeNumber(ctx, 1); // distinguish base get form derived get
669 }
670
671 static bool Base_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
672 {
673 UNUSED_PARAM(object);
674 UNUSED_PARAM(propertyName);
675 UNUSED_PARAM(value);
676
677 *exception = JSValueMakeNumber(ctx, 1); // distinguish base set from derived set
678 return true;
679 }
680
681 static JSValueRef Base_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
682 {
683 UNUSED_PARAM(function);
684 UNUSED_PARAM(thisObject);
685 UNUSED_PARAM(argumentCount);
686 UNUSED_PARAM(arguments);
687 UNUSED_PARAM(exception);
688
689 return JSValueMakeNumber(ctx, 1); // distinguish base call from derived call
690 }
691
692 static JSValueRef Base_returnHardNull(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
693 {
694 UNUSED_PARAM(ctx);
695 UNUSED_PARAM(function);
696 UNUSED_PARAM(thisObject);
697 UNUSED_PARAM(argumentCount);
698 UNUSED_PARAM(arguments);
699 UNUSED_PARAM(exception);
700
701 return 0; // should convert to undefined!
702 }
703
704 static JSStaticFunction Base_staticFunctions[] = {
705 { "baseProtoDup", NULL, kJSPropertyAttributeNone },
706 { "baseProto", Base_callAsFunction, kJSPropertyAttributeNone },
707 { "baseHardNull", Base_returnHardNull, kJSPropertyAttributeNone },
708 { 0, 0, 0 }
709 };
710
711 static JSStaticValue Base_staticValues[] = {
712 { "baseDup", Base_get, Base_set, kJSPropertyAttributeNone },
713 { "baseOnly", Base_get, Base_set, kJSPropertyAttributeNone },
714 { 0, 0, 0, 0 }
715 };
716
717 static bool TestInitializeFinalize;
718 static void Base_initialize(JSContextRef context, JSObjectRef object)
719 {
720 UNUSED_PARAM(context);
721
722 if (TestInitializeFinalize) {
723 ASSERT((void*)1 == JSObjectGetPrivate(object));
724 JSObjectSetPrivate(object, (void*)2);
725 }
726 }
727
728 static unsigned Base_didFinalize;
729 static void Base_finalize(JSObjectRef object)
730 {
731 UNUSED_PARAM(object);
732 if (TestInitializeFinalize) {
733 ASSERT((void*)4 == JSObjectGetPrivate(object));
734 Base_didFinalize = true;
735 }
736 }
737
738 static JSClassRef Base_class(JSContextRef context)
739 {
740 UNUSED_PARAM(context);
741
742 static JSClassRef jsClass;
743 if (!jsClass) {
744 JSClassDefinition definition = kJSClassDefinitionEmpty;
745 definition.staticValues = Base_staticValues;
746 definition.staticFunctions = Base_staticFunctions;
747 definition.initialize = Base_initialize;
748 definition.finalize = Base_finalize;
749 jsClass = JSClassCreate(&definition);
750 }
751 return jsClass;
752 }
753
754 static JSValueRef Derived_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
755 {
756 UNUSED_PARAM(object);
757 UNUSED_PARAM(propertyName);
758 UNUSED_PARAM(exception);
759
760 return JSValueMakeNumber(ctx, 2); // distinguish base get form derived get
761 }
762
763 static bool Derived_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
764 {
765 UNUSED_PARAM(ctx);
766 UNUSED_PARAM(object);
767 UNUSED_PARAM(propertyName);
768 UNUSED_PARAM(value);
769
770 *exception = JSValueMakeNumber(ctx, 2); // distinguish base set from derived set
771 return true;
772 }
773
774 static JSValueRef Derived_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
775 {
776 UNUSED_PARAM(function);
777 UNUSED_PARAM(thisObject);
778 UNUSED_PARAM(argumentCount);
779 UNUSED_PARAM(arguments);
780 UNUSED_PARAM(exception);
781
782 return JSValueMakeNumber(ctx, 2); // distinguish base call from derived call
783 }
784
785 static JSStaticFunction Derived_staticFunctions[] = {
786 { "protoOnly", Derived_callAsFunction, kJSPropertyAttributeNone },
787 { "protoDup", NULL, kJSPropertyAttributeNone },
788 { "baseProtoDup", Derived_callAsFunction, kJSPropertyAttributeNone },
789 { 0, 0, 0 }
790 };
791
792 static JSStaticValue Derived_staticValues[] = {
793 { "derivedOnly", Derived_get, Derived_set, kJSPropertyAttributeNone },
794 { "protoDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
795 { "baseDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
796 { 0, 0, 0, 0 }
797 };
798
799 static void Derived_initialize(JSContextRef context, JSObjectRef object)
800 {
801 UNUSED_PARAM(context);
802
803 if (TestInitializeFinalize) {
804 ASSERT((void*)2 == JSObjectGetPrivate(object));
805 JSObjectSetPrivate(object, (void*)3);
806 }
807 }
808
809 static void Derived_finalize(JSObjectRef object)
810 {
811 if (TestInitializeFinalize) {
812 ASSERT((void*)3 == JSObjectGetPrivate(object));
813 JSObjectSetPrivate(object, (void*)4);
814 }
815 }
816
817 static JSClassRef Derived_class(JSContextRef context)
818 {
819 static JSClassRef jsClass;
820 if (!jsClass) {
821 JSClassDefinition definition = kJSClassDefinitionEmpty;
822 definition.parentClass = Base_class(context);
823 definition.staticValues = Derived_staticValues;
824 definition.staticFunctions = Derived_staticFunctions;
825 definition.initialize = Derived_initialize;
826 definition.finalize = Derived_finalize;
827 jsClass = JSClassCreate(&definition);
828 }
829 return jsClass;
830 }
831
832 static JSClassRef Derived2_class(JSContextRef context)
833 {
834 static JSClassRef jsClass;
835 if (!jsClass) {
836 JSClassDefinition definition = kJSClassDefinitionEmpty;
837 definition.parentClass = Derived_class(context);
838 jsClass = JSClassCreate(&definition);
839 }
840 return jsClass;
841 }
842
843 static JSValueRef print_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
844 {
845 UNUSED_PARAM(functionObject);
846 UNUSED_PARAM(thisObject);
847 UNUSED_PARAM(exception);
848
849 ASSERT(JSContextGetGlobalContext(ctx) == context);
850
851 if (argumentCount > 0) {
852 JSStringRef string = JSValueToStringCopy(ctx, arguments[0], NULL);
853 size_t sizeUTF8 = JSStringGetMaximumUTF8CStringSize(string);
854 char* stringUTF8 = (char*)malloc(sizeUTF8);
855 JSStringGetUTF8CString(string, stringUTF8, sizeUTF8);
856 printf("%s\n", stringUTF8);
857 free(stringUTF8);
858 JSStringRelease(string);
859 }
860
861 return JSValueMakeUndefined(ctx);
862 }
863
864 static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
865 {
866 UNUSED_PARAM(constructorObject);
867 UNUSED_PARAM(exception);
868
869 JSObjectRef result = JSObjectMake(context, NULL, NULL);
870 if (argumentCount > 0) {
871 JSStringRef value = JSStringCreateWithUTF8CString("value");
872 JSObjectSetProperty(context, result, value, arguments[0], kJSPropertyAttributeNone, NULL);
873 JSStringRelease(value);
874 }
875
876 return result;
877 }
878
879 static JSObjectRef myBadConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
880 {
881 UNUSED_PARAM(context);
882 UNUSED_PARAM(constructorObject);
883 UNUSED_PARAM(argumentCount);
884 UNUSED_PARAM(arguments);
885 UNUSED_PARAM(exception);
886
887 return 0;
888 }
889
890
891 static void globalObject_initialize(JSContextRef context, JSObjectRef object)
892 {
893 UNUSED_PARAM(object);
894 // Ensure that an execution context is passed in
895 ASSERT(context);
896
897 JSObjectRef globalObject = JSContextGetGlobalObject(context);
898 ASSERT(globalObject);
899
900 // Ensure that the standard global properties have been set on the global object
901 JSStringRef array = JSStringCreateWithUTF8CString("Array");
902 JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
903 JSStringRelease(array);
904
905 UNUSED_PARAM(arrayConstructor);
906 ASSERT(arrayConstructor);
907 }
908
909 static JSValueRef globalObject_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
910 {
911 UNUSED_PARAM(object);
912 UNUSED_PARAM(propertyName);
913 UNUSED_PARAM(exception);
914
915 return JSValueMakeNumber(ctx, 3);
916 }
917
918 static bool globalObject_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
919 {
920 UNUSED_PARAM(object);
921 UNUSED_PARAM(propertyName);
922 UNUSED_PARAM(value);
923
924 *exception = JSValueMakeNumber(ctx, 3);
925 return true;
926 }
927
928 static JSValueRef globalObject_call(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
929 {
930 UNUSED_PARAM(function);
931 UNUSED_PARAM(thisObject);
932 UNUSED_PARAM(argumentCount);
933 UNUSED_PARAM(arguments);
934 UNUSED_PARAM(exception);
935
936 return JSValueMakeNumber(ctx, 3);
937 }
938
939 static JSValueRef functionGC(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
940 {
941 UNUSED_PARAM(function);
942 UNUSED_PARAM(thisObject);
943 UNUSED_PARAM(argumentCount);
944 UNUSED_PARAM(arguments);
945 UNUSED_PARAM(exception);
946 JSGarbageCollect(context);
947 return JSValueMakeUndefined(context);
948 }
949
950 static JSStaticValue globalObject_staticValues[] = {
951 { "globalStaticValue", globalObject_get, globalObject_set, kJSPropertyAttributeNone },
952 { 0, 0, 0, 0 }
953 };
954
955 static JSStaticFunction globalObject_staticFunctions[] = {
956 { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone },
957 { "gc", functionGC, kJSPropertyAttributeNone },
958 { 0, 0, 0 }
959 };
960
961 static char* createStringWithContentsOfFile(const char* fileName);
962
963 static void testInitializeFinalize()
964 {
965 JSObjectRef o = JSObjectMake(context, Derived_class(context), (void*)1);
966 UNUSED_PARAM(o);
967 ASSERT(JSObjectGetPrivate(o) == (void*)3);
968 }
969
970 static JSValueRef jsNumberValue = NULL;
971
972 static JSObjectRef aHeapRef = NULL;
973
974 static void makeGlobalNumberValue(JSContextRef context) {
975 JSValueRef v = JSValueMakeNumber(context, 420);
976 JSValueProtect(context, v);
977 jsNumberValue = v;
978 v = NULL;
979 }
980
981 bool assertTrue(bool value, const char* message)
982 {
983 if (!value) {
984 if (message)
985 fprintf(stderr, "assertTrue failed: '%s'\n", message);
986 else
987 fprintf(stderr, "assertTrue failed.\n");
988 failed = 1;
989 }
990 return value;
991 }
992
993 static bool checkForCycleInPrototypeChain()
994 {
995 bool result = true;
996 JSGlobalContextRef context = JSGlobalContextCreate(0);
997 JSObjectRef object1 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
998 JSObjectRef object2 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
999 JSObjectRef object3 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0);
1000
1001 JSObjectSetPrototype(context, object1, JSValueMakeNull(context));
1002 ASSERT(JSValueIsNull(context, JSObjectGetPrototype(context, object1)));
1003
1004 // object1 -> object1
1005 JSObjectSetPrototype(context, object1, object1);
1006 result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to assign self as a prototype");
1007
1008 // object1 -> object2 -> object1
1009 JSObjectSetPrototype(context, object2, object1);
1010 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object1));
1011 JSObjectSetPrototype(context, object1, object2);
1012 result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to close a prototype chain cycle");
1013
1014 // object1 -> object2 -> object3 -> object1
1015 JSObjectSetPrototype(context, object2, object3);
1016 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object3));
1017 JSObjectSetPrototype(context, object1, object2);
1018 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object1), object2));
1019 JSObjectSetPrototype(context, object3, object1);
1020 result &= assertTrue(!JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object3), object1), "It is possible to close a prototype chain cycle");
1021
1022 JSValueRef exception;
1023 JSStringRef code = JSStringCreateWithUTF8CString("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o");
1024 JSStringRef file = JSStringCreateWithUTF8CString("");
1025 result &= assertTrue(!JSEvaluateScript(context, code, /* thisObject*/ 0, file, 1, &exception)
1026 , "An exception should be thrown");
1027
1028 JSStringRelease(code);
1029 JSStringRelease(file);
1030 JSGlobalContextRelease(context);
1031 return result;
1032 }
1033
1034 static JSValueRef valueToObjectExceptionCallAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
1035 {
1036 UNUSED_PARAM(function);
1037 UNUSED_PARAM(thisObject);
1038 UNUSED_PARAM(argumentCount);
1039 UNUSED_PARAM(arguments);
1040 JSValueRef jsUndefined = JSValueMakeUndefined(JSContextGetGlobalContext(ctx));
1041 JSValueToObject(JSContextGetGlobalContext(ctx), jsUndefined, exception);
1042
1043 return JSValueMakeUndefined(ctx);
1044 }
1045 static bool valueToObjectExceptionTest()
1046 {
1047 JSGlobalContextRef testContext;
1048 JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty;
1049 globalObjectClassDefinition.initialize = globalObject_initialize;
1050 globalObjectClassDefinition.staticValues = globalObject_staticValues;
1051 globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions;
1052 globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
1053 JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition);
1054 testContext = JSGlobalContextCreateInGroup(NULL, globalObjectClass);
1055 JSObjectRef globalObject = JSContextGetGlobalObject(testContext);
1056
1057 JSStringRef valueToObject = JSStringCreateWithUTF8CString("valueToObject");
1058 JSObjectRef valueToObjectFunction = JSObjectMakeFunctionWithCallback(testContext, valueToObject, valueToObjectExceptionCallAsFunction);
1059 JSObjectSetProperty(testContext, globalObject, valueToObject, valueToObjectFunction, kJSPropertyAttributeNone, NULL);
1060 JSStringRelease(valueToObject);
1061
1062 JSStringRef test = JSStringCreateWithUTF8CString("valueToObject();");
1063 JSEvaluateScript(testContext, test, NULL, NULL, 1, NULL);
1064
1065 JSStringRelease(test);
1066 JSClassRelease(globalObjectClass);
1067 JSGlobalContextRelease(testContext);
1068
1069 return true;
1070 }
1071
1072 static bool globalContextNameTest()
1073 {
1074 bool result = true;
1075 JSGlobalContextRef context = JSGlobalContextCreate(0);
1076
1077 JSStringRef str = JSGlobalContextCopyName(context);
1078 result &= assertTrue(!str, "Default context name is NULL");
1079
1080 JSStringRef name1 = JSStringCreateWithUTF8CString("name1");
1081 JSStringRef name2 = JSStringCreateWithUTF8CString("name2");
1082
1083 JSGlobalContextSetName(context, name1);
1084 JSStringRef fetchName1 = JSGlobalContextCopyName(context);
1085 JSGlobalContextSetName(context, name2);
1086 JSStringRef fetchName2 = JSGlobalContextCopyName(context);
1087 JSGlobalContextSetName(context, NULL);
1088 JSStringRef fetchName3 = JSGlobalContextCopyName(context);
1089
1090 result &= assertTrue(JSStringIsEqual(name1, fetchName1), "Unexpected Context name");
1091 result &= assertTrue(JSStringIsEqual(name2, fetchName2), "Unexpected Context name");
1092 result &= assertTrue(!JSStringIsEqual(fetchName1, fetchName2), "Unexpected Context name");
1093 result &= assertTrue(!fetchName3, "Unexpected Context name");
1094
1095 JSStringRelease(name1);
1096 JSStringRelease(name2);
1097 JSStringRelease(fetchName1);
1098 JSStringRelease(fetchName2);
1099
1100 return result;
1101 }
1102
1103 static void checkConstnessInJSObjectNames()
1104 {
1105 JSStaticFunction fun;
1106 fun.name = "something";
1107 JSStaticValue val;
1108 val.name = "something";
1109 }
1110
1111 #if OS(DARWIN)
1112 static double currentCPUTime()
1113 {
1114 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1115 thread_basic_info_data_t info;
1116
1117 /* Get thread information */
1118 mach_port_t threadPort = mach_thread_self();
1119 thread_info(threadPort, THREAD_BASIC_INFO, (thread_info_t)(&info), &infoCount);
1120 mach_port_deallocate(mach_task_self(), threadPort);
1121
1122 double time = info.user_time.seconds + info.user_time.microseconds / 1000000.;
1123 time += info.system_time.seconds + info.system_time.microseconds / 1000000.;
1124
1125 return time;
1126 }
1127
1128 static JSValueRef currentCPUTime_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
1129 {
1130 UNUSED_PARAM(functionObject);
1131 UNUSED_PARAM(thisObject);
1132 UNUSED_PARAM(argumentCount);
1133 UNUSED_PARAM(arguments);
1134 UNUSED_PARAM(exception);
1135
1136 ASSERT(JSContextGetGlobalContext(ctx) == context);
1137 return JSValueMakeNumber(ctx, currentCPUTime());
1138 }
1139
1140 bool shouldTerminateCallbackWasCalled = false;
1141 static bool shouldTerminateCallback(JSContextRef ctx, void* context)
1142 {
1143 UNUSED_PARAM(ctx);
1144 UNUSED_PARAM(context);
1145 shouldTerminateCallbackWasCalled = true;
1146 return true;
1147 }
1148
1149 bool cancelTerminateCallbackWasCalled = false;
1150 static bool cancelTerminateCallback(JSContextRef ctx, void* context)
1151 {
1152 UNUSED_PARAM(ctx);
1153 UNUSED_PARAM(context);
1154 cancelTerminateCallbackWasCalled = true;
1155 return false;
1156 }
1157
1158 int extendTerminateCallbackCalled = 0;
1159 static bool extendTerminateCallback(JSContextRef ctx, void* context)
1160 {
1161 UNUSED_PARAM(context);
1162 extendTerminateCallbackCalled++;
1163 if (extendTerminateCallbackCalled == 1) {
1164 JSContextGroupRef contextGroup = JSContextGetGroup(ctx);
1165 JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0);
1166 return false;
1167 }
1168 return true;
1169 }
1170 #endif /* OS(DARWIN) */
1171
1172
1173 int main(int argc, char* argv[])
1174 {
1175 #if OS(WINDOWS)
1176 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
1177 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
1178 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
1179 ::SetErrorMode(0);
1180 #endif
1181
1182 #if JSC_OBJC_API_ENABLED
1183 testObjectiveCAPI();
1184 #endif
1185
1186 const char *scriptPath = "testapi.js";
1187 if (argc > 1) {
1188 scriptPath = argv[1];
1189 }
1190
1191 // Test garbage collection with a fresh context
1192 context = JSGlobalContextCreateInGroup(NULL, NULL);
1193 TestInitializeFinalize = true;
1194 testInitializeFinalize();
1195 JSGlobalContextRelease(context);
1196 TestInitializeFinalize = false;
1197
1198 ASSERT(Base_didFinalize);
1199
1200 JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty;
1201 globalObjectClassDefinition.initialize = globalObject_initialize;
1202 globalObjectClassDefinition.staticValues = globalObject_staticValues;
1203 globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions;
1204 globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
1205 JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition);
1206 context = JSGlobalContextCreateInGroup(NULL, globalObjectClass);
1207
1208 JSContextGroupRef contextGroup = JSContextGetGroup(context);
1209
1210 JSGlobalContextRetain(context);
1211 JSGlobalContextRelease(context);
1212 ASSERT(JSContextGetGlobalContext(context) == context);
1213
1214 JSReportExtraMemoryCost(context, 0);
1215 JSReportExtraMemoryCost(context, 1);
1216 JSReportExtraMemoryCost(context, 1024);
1217
1218 JSObjectRef globalObject = JSContextGetGlobalObject(context);
1219 ASSERT(JSValueIsObject(context, globalObject));
1220
1221 JSValueRef jsUndefined = JSValueMakeUndefined(context);
1222 JSValueRef jsNull = JSValueMakeNull(context);
1223 JSValueRef jsTrue = JSValueMakeBoolean(context, true);
1224 JSValueRef jsFalse = JSValueMakeBoolean(context, false);
1225 JSValueRef jsZero = JSValueMakeNumber(context, 0);
1226 JSValueRef jsOne = JSValueMakeNumber(context, 1);
1227 JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0);
1228 JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, NULL);
1229 JSObjectSetPrototype(context, jsObjectNoProto, JSValueMakeNull(context));
1230
1231 JSObjectSetPrivate(globalObject, (void*)123);
1232 if (JSObjectGetPrivate(globalObject) != (void*)123) {
1233 printf("FAIL: Didn't return private data when set by JSObjectSetPrivate().\n");
1234 failed = 1;
1235 } else
1236 printf("PASS: returned private data when set by JSObjectSetPrivate().\n");
1237
1238 // FIXME: test funny utf8 characters
1239 JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString("");
1240 JSValueRef jsEmptyString = JSValueMakeString(context, jsEmptyIString);
1241
1242 JSStringRef jsOneIString = JSStringCreateWithUTF8CString("1");
1243 JSValueRef jsOneString = JSValueMakeString(context, jsOneIString);
1244
1245 UniChar singleUniChar = 65; // Capital A
1246 CFMutableStringRef cfString =
1247 CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault,
1248 &singleUniChar,
1249 1,
1250 1,
1251 kCFAllocatorNull);
1252
1253 JSStringRef jsCFIString = JSStringCreateWithCFString(cfString);
1254 JSValueRef jsCFString = JSValueMakeString(context, jsCFIString);
1255
1256 CFStringRef cfEmptyString = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8);
1257
1258 JSStringRef jsCFEmptyIString = JSStringCreateWithCFString(cfEmptyString);
1259 JSValueRef jsCFEmptyString = JSValueMakeString(context, jsCFEmptyIString);
1260
1261 CFIndex cfStringLength = CFStringGetLength(cfString);
1262 UniChar* buffer = (UniChar*)malloc(cfStringLength * sizeof(UniChar));
1263 CFStringGetCharacters(cfString,
1264 CFRangeMake(0, cfStringLength),
1265 buffer);
1266 JSStringRef jsCFIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, cfStringLength);
1267 JSValueRef jsCFStringWithCharacters = JSValueMakeString(context, jsCFIStringWithCharacters);
1268
1269 JSStringRef jsCFEmptyIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, CFStringGetLength(cfEmptyString));
1270 free(buffer);
1271 JSValueRef jsCFEmptyStringWithCharacters = JSValueMakeString(context, jsCFEmptyIStringWithCharacters);
1272
1273 JSChar constantString[] = { 'H', 'e', 'l', 'l', 'o', };
1274 JSStringRef constantStringRef = JSStringCreateWithCharactersNoCopy(constantString, sizeof(constantString) / sizeof(constantString[0]));
1275 ASSERT(JSStringGetCharactersPtr(constantStringRef) == constantString);
1276 JSStringRelease(constantStringRef);
1277
1278 ASSERT(JSValueGetType(context, NULL) == kJSTypeNull);
1279 ASSERT(JSValueGetType(context, jsUndefined) == kJSTypeUndefined);
1280 ASSERT(JSValueGetType(context, jsNull) == kJSTypeNull);
1281 ASSERT(JSValueGetType(context, jsTrue) == kJSTypeBoolean);
1282 ASSERT(JSValueGetType(context, jsFalse) == kJSTypeBoolean);
1283 ASSERT(JSValueGetType(context, jsZero) == kJSTypeNumber);
1284 ASSERT(JSValueGetType(context, jsOne) == kJSTypeNumber);
1285 ASSERT(JSValueGetType(context, jsOneThird) == kJSTypeNumber);
1286 ASSERT(JSValueGetType(context, jsEmptyString) == kJSTypeString);
1287 ASSERT(JSValueGetType(context, jsOneString) == kJSTypeString);
1288 ASSERT(JSValueGetType(context, jsCFString) == kJSTypeString);
1289 ASSERT(JSValueGetType(context, jsCFStringWithCharacters) == kJSTypeString);
1290 ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString);
1291 ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);
1292
1293 ASSERT(!JSValueIsBoolean(context, NULL));
1294 ASSERT(!JSValueIsObject(context, NULL));
1295 ASSERT(!JSValueIsString(context, NULL));
1296 ASSERT(!JSValueIsNumber(context, NULL));
1297 ASSERT(!JSValueIsUndefined(context, NULL));
1298 ASSERT(JSValueIsNull(context, NULL));
1299 ASSERT(!JSObjectCallAsFunction(context, NULL, NULL, 0, NULL, NULL));
1300 ASSERT(!JSObjectCallAsConstructor(context, NULL, 0, NULL, NULL));
1301 ASSERT(!JSObjectIsConstructor(context, NULL));
1302 ASSERT(!JSObjectIsFunction(context, NULL));
1303
1304 JSStringRef nullString = JSStringCreateWithUTF8CString(0);
1305 const JSChar* characters = JSStringGetCharactersPtr(nullString);
1306 if (characters) {
1307 printf("FAIL: Didn't return null when accessing character pointer of a null String.\n");
1308 failed = 1;
1309 } else
1310 printf("PASS: returned null when accessing character pointer of a null String.\n");
1311
1312 JSStringRef emptyString = JSStringCreateWithCFString(CFSTR(""));
1313 characters = JSStringGetCharactersPtr(emptyString);
1314 if (!characters) {
1315 printf("FAIL: Returned null when accessing character pointer of an empty String.\n");
1316 failed = 1;
1317 } else
1318 printf("PASS: returned empty when accessing character pointer of an empty String.\n");
1319
1320 size_t length = JSStringGetLength(nullString);
1321 if (length) {
1322 printf("FAIL: Didn't return 0 length for null String.\n");
1323 failed = 1;
1324 } else
1325 printf("PASS: returned 0 length for null String.\n");
1326 JSStringRelease(nullString);
1327
1328 length = JSStringGetLength(emptyString);
1329 if (length) {
1330 printf("FAIL: Didn't return 0 length for empty String.\n");
1331 failed = 1;
1332 } else
1333 printf("PASS: returned 0 length for empty String.\n");
1334 JSStringRelease(emptyString);
1335
1336 JSObjectRef propertyCatchalls = JSObjectMake(context, PropertyCatchalls_class(context), NULL);
1337 JSStringRef propertyCatchallsString = JSStringCreateWithUTF8CString("PropertyCatchalls");
1338 JSObjectSetProperty(context, globalObject, propertyCatchallsString, propertyCatchalls, kJSPropertyAttributeNone, NULL);
1339 JSStringRelease(propertyCatchallsString);
1340
1341 JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
1342 JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
1343 JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
1344 JSStringRelease(myObjectIString);
1345
1346 JSObjectRef EvilExceptionObject = JSObjectMake(context, EvilExceptionObject_class(context), NULL);
1347 JSStringRef EvilExceptionObjectIString = JSStringCreateWithUTF8CString("EvilExceptionObject");
1348 JSObjectSetProperty(context, globalObject, EvilExceptionObjectIString, EvilExceptionObject, kJSPropertyAttributeNone, NULL);
1349 JSStringRelease(EvilExceptionObjectIString);
1350
1351 JSObjectRef EmptyObject = JSObjectMake(context, EmptyObject_class(context), NULL);
1352 JSStringRef EmptyObjectIString = JSStringCreateWithUTF8CString("EmptyObject");
1353 JSObjectSetProperty(context, globalObject, EmptyObjectIString, EmptyObject, kJSPropertyAttributeNone, NULL);
1354 JSStringRelease(EmptyObjectIString);
1355
1356 JSStringRef lengthStr = JSStringCreateWithUTF8CString("length");
1357 JSObjectRef aStackRef = JSObjectMakeArray(context, 0, 0, 0);
1358 aHeapRef = aStackRef;
1359 JSObjectSetProperty(context, aHeapRef, lengthStr, JSValueMakeNumber(context, 10), 0, 0);
1360 JSStringRef privatePropertyName = JSStringCreateWithUTF8CString("privateProperty");
1361 if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, aHeapRef)) {
1362 printf("FAIL: Could not set private property.\n");
1363 failed = 1;
1364 } else
1365 printf("PASS: Set private property.\n");
1366 aStackRef = 0;
1367 if (JSObjectSetPrivateProperty(context, aHeapRef, privatePropertyName, aHeapRef)) {
1368 printf("FAIL: JSObjectSetPrivateProperty should fail on non-API objects.\n");
1369 failed = 1;
1370 } else
1371 printf("PASS: Did not allow JSObjectSetPrivateProperty on a non-API object.\n");
1372 if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName) != aHeapRef) {
1373 printf("FAIL: Could not retrieve private property.\n");
1374 failed = 1;
1375 } else
1376 printf("PASS: Retrieved private property.\n");
1377 if (JSObjectGetPrivateProperty(context, aHeapRef, privatePropertyName)) {
1378 printf("FAIL: JSObjectGetPrivateProperty should return NULL when called on a non-API object.\n");
1379 failed = 1;
1380 } else
1381 printf("PASS: JSObjectGetPrivateProperty return NULL.\n");
1382
1383 if (JSObjectGetProperty(context, myObject, privatePropertyName, 0) == aHeapRef) {
1384 printf("FAIL: Accessed private property through ordinary property lookup.\n");
1385 failed = 1;
1386 } else
1387 printf("PASS: Cannot access private property through ordinary property lookup.\n");
1388
1389 JSGarbageCollect(context);
1390
1391 for (int i = 0; i < 10000; i++)
1392 JSObjectMake(context, 0, 0);
1393
1394 aHeapRef = JSValueToObject(context, JSObjectGetPrivateProperty(context, myObject, privatePropertyName), 0);
1395 if (JSValueToNumber(context, JSObjectGetProperty(context, aHeapRef, lengthStr, 0), 0) != 10) {
1396 printf("FAIL: Private property has been collected.\n");
1397 failed = 1;
1398 } else
1399 printf("PASS: Private property does not appear to have been collected.\n");
1400 JSStringRelease(lengthStr);
1401
1402 if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, 0)) {
1403 printf("FAIL: Could not set private property to NULL.\n");
1404 failed = 1;
1405 } else
1406 printf("PASS: Set private property to NULL.\n");
1407 if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName)) {
1408 printf("FAIL: Could not retrieve private property.\n");
1409 failed = 1;
1410 } else
1411 printf("PASS: Retrieved private property.\n");
1412
1413 JSStringRef nullJSON = JSStringCreateWithUTF8CString(0);
1414 JSValueRef nullJSONObject = JSValueMakeFromJSONString(context, nullJSON);
1415 if (nullJSONObject) {
1416 printf("FAIL: Did not parse null String as JSON correctly\n");
1417 failed = 1;
1418 } else
1419 printf("PASS: Parsed null String as JSON correctly.\n");
1420 JSStringRelease(nullJSON);
1421
1422 JSStringRef validJSON = JSStringCreateWithUTF8CString("{\"aProperty\":true}");
1423 JSValueRef jsonObject = JSValueMakeFromJSONString(context, validJSON);
1424 JSStringRelease(validJSON);
1425 if (!JSValueIsObject(context, jsonObject)) {
1426 printf("FAIL: Did not parse valid JSON correctly\n");
1427 failed = 1;
1428 } else
1429 printf("PASS: Parsed valid JSON string.\n");
1430 JSStringRef propertyName = JSStringCreateWithUTF8CString("aProperty");
1431 assertEqualsAsBoolean(JSObjectGetProperty(context, JSValueToObject(context, jsonObject, 0), propertyName, 0), true);
1432 JSStringRelease(propertyName);
1433 JSStringRef invalidJSON = JSStringCreateWithUTF8CString("fail!");
1434 if (JSValueMakeFromJSONString(context, invalidJSON)) {
1435 printf("FAIL: Should return null for invalid JSON data\n");
1436 failed = 1;
1437 } else
1438 printf("PASS: Correctly returned null for invalid JSON data.\n");
1439 JSValueRef exception;
1440 JSStringRef str = JSValueCreateJSONString(context, jsonObject, 0, 0);
1441 if (!JSStringIsEqualToUTF8CString(str, "{\"aProperty\":true}")) {
1442 printf("FAIL: Did not correctly serialise with indent of 0.\n");
1443 failed = 1;
1444 } else
1445 printf("PASS: Correctly serialised with indent of 0.\n");
1446 JSStringRelease(str);
1447
1448 str = JSValueCreateJSONString(context, jsonObject, 4, 0);
1449 if (!JSStringIsEqualToUTF8CString(str, "{\n \"aProperty\": true\n}")) {
1450 printf("FAIL: Did not correctly serialise with indent of 4.\n");
1451 failed = 1;
1452 } else
1453 printf("PASS: Correctly serialised with indent of 4.\n");
1454 JSStringRelease(str);
1455 JSStringRef src = JSStringCreateWithUTF8CString("({get a(){ throw '';}})");
1456 JSValueRef unstringifiableObj = JSEvaluateScript(context, src, NULL, NULL, 1, NULL);
1457
1458 str = JSValueCreateJSONString(context, unstringifiableObj, 4, 0);
1459 if (str) {
1460 printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
1461 JSStringRelease(str);
1462 failed = 1;
1463 } else
1464 printf("PASS: returned null when attempting to serialize unserializable value.\n");
1465
1466 str = JSValueCreateJSONString(context, unstringifiableObj, 4, &exception);
1467 if (str) {
1468 printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n");
1469 JSStringRelease(str);
1470 failed = 1;
1471 } else
1472 printf("PASS: returned null when attempting to serialize unserializable value.\n");
1473 if (!exception) {
1474 printf("FAIL: Did not set exception on serialisation error\n");
1475 failed = 1;
1476 } else
1477 printf("PASS: set exception on serialisation error\n");
1478 // Conversions that throw exceptions
1479 exception = NULL;
1480 ASSERT(NULL == JSValueToObject(context, jsNull, &exception));
1481 ASSERT(exception);
1482
1483 exception = NULL;
1484 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
1485 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
1486 // After that's resolved, we can remove these casts
1487 ASSERT(isnan((float)JSValueToNumber(context, jsObjectNoProto, &exception)));
1488 ASSERT(exception);
1489
1490 exception = NULL;
1491 ASSERT(!JSValueToStringCopy(context, jsObjectNoProto, &exception));
1492 ASSERT(exception);
1493
1494 ASSERT(JSValueToBoolean(context, myObject));
1495
1496 exception = NULL;
1497 ASSERT(!JSValueIsEqual(context, jsObjectNoProto, JSValueMakeNumber(context, 1), &exception));
1498 ASSERT(exception);
1499
1500 exception = NULL;
1501 JSObjectGetPropertyAtIndex(context, myObject, 0, &exception);
1502 ASSERT(1 == JSValueToNumber(context, exception, NULL));
1503
1504 assertEqualsAsBoolean(jsUndefined, false);
1505 assertEqualsAsBoolean(jsNull, false);
1506 assertEqualsAsBoolean(jsTrue, true);
1507 assertEqualsAsBoolean(jsFalse, false);
1508 assertEqualsAsBoolean(jsZero, false);
1509 assertEqualsAsBoolean(jsOne, true);
1510 assertEqualsAsBoolean(jsOneThird, true);
1511 assertEqualsAsBoolean(jsEmptyString, false);
1512 assertEqualsAsBoolean(jsOneString, true);
1513 assertEqualsAsBoolean(jsCFString, true);
1514 assertEqualsAsBoolean(jsCFStringWithCharacters, true);
1515 assertEqualsAsBoolean(jsCFEmptyString, false);
1516 assertEqualsAsBoolean(jsCFEmptyStringWithCharacters, false);
1517
1518 assertEqualsAsNumber(jsUndefined, nan(""));
1519 assertEqualsAsNumber(jsNull, 0);
1520 assertEqualsAsNumber(jsTrue, 1);
1521 assertEqualsAsNumber(jsFalse, 0);
1522 assertEqualsAsNumber(jsZero, 0);
1523 assertEqualsAsNumber(jsOne, 1);
1524 assertEqualsAsNumber(jsOneThird, 1.0 / 3.0);
1525 assertEqualsAsNumber(jsEmptyString, 0);
1526 assertEqualsAsNumber(jsOneString, 1);
1527 assertEqualsAsNumber(jsCFString, nan(""));
1528 assertEqualsAsNumber(jsCFStringWithCharacters, nan(""));
1529 assertEqualsAsNumber(jsCFEmptyString, 0);
1530 assertEqualsAsNumber(jsCFEmptyStringWithCharacters, 0);
1531 ASSERT(sizeof(JSChar) == sizeof(UniChar));
1532
1533 assertEqualsAsCharactersPtr(jsUndefined, "undefined");
1534 assertEqualsAsCharactersPtr(jsNull, "null");
1535 assertEqualsAsCharactersPtr(jsTrue, "true");
1536 assertEqualsAsCharactersPtr(jsFalse, "false");
1537 assertEqualsAsCharactersPtr(jsZero, "0");
1538 assertEqualsAsCharactersPtr(jsOne, "1");
1539 assertEqualsAsCharactersPtr(jsOneThird, "0.3333333333333333");
1540 assertEqualsAsCharactersPtr(jsEmptyString, "");
1541 assertEqualsAsCharactersPtr(jsOneString, "1");
1542 assertEqualsAsCharactersPtr(jsCFString, "A");
1543 assertEqualsAsCharactersPtr(jsCFStringWithCharacters, "A");
1544 assertEqualsAsCharactersPtr(jsCFEmptyString, "");
1545 assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters, "");
1546
1547 assertEqualsAsUTF8String(jsUndefined, "undefined");
1548 assertEqualsAsUTF8String(jsNull, "null");
1549 assertEqualsAsUTF8String(jsTrue, "true");
1550 assertEqualsAsUTF8String(jsFalse, "false");
1551 assertEqualsAsUTF8String(jsZero, "0");
1552 assertEqualsAsUTF8String(jsOne, "1");
1553 assertEqualsAsUTF8String(jsOneThird, "0.3333333333333333");
1554 assertEqualsAsUTF8String(jsEmptyString, "");
1555 assertEqualsAsUTF8String(jsOneString, "1");
1556 assertEqualsAsUTF8String(jsCFString, "A");
1557 assertEqualsAsUTF8String(jsCFStringWithCharacters, "A");
1558 assertEqualsAsUTF8String(jsCFEmptyString, "");
1559 assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters, "");
1560
1561 checkConstnessInJSObjectNames();
1562
1563 ASSERT(JSValueIsStrictEqual(context, jsTrue, jsTrue));
1564 ASSERT(!JSValueIsStrictEqual(context, jsOne, jsOneString));
1565
1566 ASSERT(JSValueIsEqual(context, jsOne, jsOneString, NULL));
1567 ASSERT(!JSValueIsEqual(context, jsTrue, jsFalse, NULL));
1568
1569 CFStringRef cfJSString = JSStringCopyCFString(kCFAllocatorDefault, jsCFIString);
1570 CFStringRef cfJSEmptyString = JSStringCopyCFString(kCFAllocatorDefault, jsCFEmptyIString);
1571 ASSERT(CFEqual(cfJSString, cfString));
1572 ASSERT(CFEqual(cfJSEmptyString, cfEmptyString));
1573 CFRelease(cfJSString);
1574 CFRelease(cfJSEmptyString);
1575
1576 CFRelease(cfString);
1577 CFRelease(cfEmptyString);
1578
1579 jsGlobalValue = JSObjectMake(context, NULL, NULL);
1580 makeGlobalNumberValue(context);
1581 JSValueProtect(context, jsGlobalValue);
1582 JSGarbageCollect(context);
1583 ASSERT(JSValueIsObject(context, jsGlobalValue));
1584 JSValueUnprotect(context, jsGlobalValue);
1585 JSValueUnprotect(context, jsNumberValue);
1586
1587 JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;");
1588 const char* badSyntaxConstant = "x := 1;";
1589 JSStringRef badSyntax = JSStringCreateWithUTF8CString(badSyntaxConstant);
1590 ASSERT(JSCheckScriptSyntax(context, goodSyntax, NULL, 0, NULL));
1591 ASSERT(!JSCheckScriptSyntax(context, badSyntax, NULL, 0, NULL));
1592 ASSERT(!JSScriptCreateFromString(contextGroup, 0, 0, badSyntax, 0, 0));
1593 ASSERT(!JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, badSyntaxConstant, strlen(badSyntaxConstant), 0, 0));
1594
1595 JSValueRef result;
1596 JSValueRef v;
1597 JSObjectRef o;
1598 JSStringRef string;
1599
1600 result = JSEvaluateScript(context, goodSyntax, NULL, NULL, 1, NULL);
1601 ASSERT(result);
1602 ASSERT(JSValueIsEqual(context, result, jsOne, NULL));
1603
1604 exception = NULL;
1605 result = JSEvaluateScript(context, badSyntax, NULL, NULL, 1, &exception);
1606 ASSERT(!result);
1607 ASSERT(JSValueIsObject(context, exception));
1608
1609 JSStringRef array = JSStringCreateWithUTF8CString("Array");
1610 JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
1611 JSStringRelease(array);
1612 result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL);
1613 ASSERT(result);
1614 ASSERT(JSValueIsObject(context, result));
1615 ASSERT(JSValueIsInstanceOfConstructor(context, result, arrayConstructor, NULL));
1616 ASSERT(!JSValueIsInstanceOfConstructor(context, JSValueMakeNull(context), arrayConstructor, NULL));
1617
1618 o = JSValueToObject(context, result, NULL);
1619 exception = NULL;
1620 ASSERT(JSValueIsUndefined(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception)));
1621 ASSERT(!exception);
1622
1623 JSObjectSetPropertyAtIndex(context, o, 0, JSValueMakeNumber(context, 1), &exception);
1624 ASSERT(!exception);
1625
1626 exception = NULL;
1627 ASSERT(1 == JSValueToNumber(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception), &exception));
1628 ASSERT(!exception);
1629
1630 JSStringRef functionBody;
1631 JSObjectRef function;
1632
1633 exception = NULL;
1634 functionBody = JSStringCreateWithUTF8CString("rreturn Array;");
1635 JSStringRef line = JSStringCreateWithUTF8CString("line");
1636 ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception));
1637 ASSERT(JSValueIsObject(context, exception));
1638 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL);
1639 assertEqualsAsNumber(v, 1);
1640 JSStringRelease(functionBody);
1641 JSStringRelease(line);
1642
1643 exception = NULL;
1644 functionBody = JSStringCreateWithUTF8CString("rreturn Array;");
1645 line = JSStringCreateWithUTF8CString("line");
1646 ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, -42, &exception));
1647 ASSERT(JSValueIsObject(context, exception));
1648 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL);
1649 assertEqualsAsNumber(v, 1);
1650 JSStringRelease(functionBody);
1651 JSStringRelease(line);
1652
1653 exception = NULL;
1654 functionBody = JSStringCreateWithUTF8CString("// Line one.\nrreturn Array;");
1655 line = JSStringCreateWithUTF8CString("line");
1656 ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception));
1657 ASSERT(JSValueIsObject(context, exception));
1658 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL);
1659 assertEqualsAsNumber(v, 2);
1660 JSStringRelease(functionBody);
1661 JSStringRelease(line);
1662
1663 exception = NULL;
1664 functionBody = JSStringCreateWithUTF8CString("return Array;");
1665 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception);
1666 JSStringRelease(functionBody);
1667 ASSERT(!exception);
1668 ASSERT(JSObjectIsFunction(context, function));
1669 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1670 ASSERT(v);
1671 ASSERT(JSValueIsEqual(context, v, arrayConstructor, NULL));
1672
1673 exception = NULL;
1674 function = JSObjectMakeFunction(context, NULL, 0, NULL, jsEmptyIString, NULL, 0, &exception);
1675 ASSERT(!exception);
1676 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, &exception);
1677 ASSERT(v && !exception);
1678 ASSERT(JSValueIsUndefined(context, v));
1679
1680 exception = NULL;
1681 v = NULL;
1682 JSStringRef foo = JSStringCreateWithUTF8CString("foo");
1683 JSStringRef argumentNames[] = { foo };
1684 functionBody = JSStringCreateWithUTF8CString("return foo;");
1685 function = JSObjectMakeFunction(context, foo, 1, argumentNames, functionBody, NULL, 1, &exception);
1686 ASSERT(function && !exception);
1687 JSValueRef arguments[] = { JSValueMakeNumber(context, 2) };
1688 JSObjectCallAsFunction(context, function, NULL, 1, arguments, &exception);
1689 JSStringRelease(foo);
1690 JSStringRelease(functionBody);
1691
1692 string = JSValueToStringCopy(context, function, NULL);
1693 assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) { return foo;\n}");
1694 JSStringRelease(string);
1695
1696 JSStringRef print = JSStringCreateWithUTF8CString("print");
1697 JSObjectRef printFunction = JSObjectMakeFunctionWithCallback(context, print, print_callAsFunction);
1698 JSObjectSetProperty(context, globalObject, print, printFunction, kJSPropertyAttributeNone, NULL);
1699 JSStringRelease(print);
1700
1701 ASSERT(!JSObjectSetPrivate(printFunction, (void*)1));
1702 ASSERT(!JSObjectGetPrivate(printFunction));
1703
1704 JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor");
1705 JSObjectRef myConstructor = JSObjectMakeConstructor(context, NULL, myConstructor_callAsConstructor);
1706 JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL);
1707 JSStringRelease(myConstructorIString);
1708
1709 JSStringRef myBadConstructorIString = JSStringCreateWithUTF8CString("MyBadConstructor");
1710 JSObjectRef myBadConstructor = JSObjectMakeConstructor(context, NULL, myBadConstructor_callAsConstructor);
1711 JSObjectSetProperty(context, globalObject, myBadConstructorIString, myBadConstructor, kJSPropertyAttributeNone, NULL);
1712 JSStringRelease(myBadConstructorIString);
1713
1714 ASSERT(!JSObjectSetPrivate(myConstructor, (void*)1));
1715 ASSERT(!JSObjectGetPrivate(myConstructor));
1716
1717 string = JSStringCreateWithUTF8CString("Base");
1718 JSObjectRef baseConstructor = JSObjectMakeConstructor(context, Base_class(context), NULL);
1719 JSObjectSetProperty(context, globalObject, string, baseConstructor, kJSPropertyAttributeNone, NULL);
1720 JSStringRelease(string);
1721
1722 string = JSStringCreateWithUTF8CString("Derived");
1723 JSObjectRef derivedConstructor = JSObjectMakeConstructor(context, Derived_class(context), NULL);
1724 JSObjectSetProperty(context, globalObject, string, derivedConstructor, kJSPropertyAttributeNone, NULL);
1725 JSStringRelease(string);
1726
1727 string = JSStringCreateWithUTF8CString("Derived2");
1728 JSObjectRef derived2Constructor = JSObjectMakeConstructor(context, Derived2_class(context), NULL);
1729 JSObjectSetProperty(context, globalObject, string, derived2Constructor, kJSPropertyAttributeNone, NULL);
1730 JSStringRelease(string);
1731
1732 o = JSObjectMake(context, NULL, NULL);
1733 JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL);
1734 JSObjectSetProperty(context, o, jsCFIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL);
1735 JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o);
1736 size_t expectedCount = JSPropertyNameArrayGetCount(nameArray);
1737 size_t count;
1738 for (count = 0; count < expectedCount; ++count)
1739 JSPropertyNameArrayGetNameAtIndex(nameArray, count);
1740 JSPropertyNameArrayRelease(nameArray);
1741 ASSERT(count == 1); // jsCFString should not be enumerated
1742
1743 JSValueRef argumentsArrayValues[] = { JSValueMakeNumber(context, 10), JSValueMakeNumber(context, 20) };
1744 o = JSObjectMakeArray(context, sizeof(argumentsArrayValues) / sizeof(JSValueRef), argumentsArrayValues, NULL);
1745 string = JSStringCreateWithUTF8CString("length");
1746 v = JSObjectGetProperty(context, o, string, NULL);
1747 assertEqualsAsNumber(v, 2);
1748 v = JSObjectGetPropertyAtIndex(context, o, 0, NULL);
1749 assertEqualsAsNumber(v, 10);
1750 v = JSObjectGetPropertyAtIndex(context, o, 1, NULL);
1751 assertEqualsAsNumber(v, 20);
1752
1753 o = JSObjectMakeArray(context, 0, NULL, NULL);
1754 v = JSObjectGetProperty(context, o, string, NULL);
1755 assertEqualsAsNumber(v, 0);
1756 JSStringRelease(string);
1757
1758 JSValueRef argumentsDateValues[] = { JSValueMakeNumber(context, 0) };
1759 o = JSObjectMakeDate(context, 1, argumentsDateValues, NULL);
1760 if (timeZoneIsPST())
1761 assertEqualsAsUTF8String(o, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)");
1762
1763 string = JSStringCreateWithUTF8CString("an error message");
1764 JSValueRef argumentsErrorValues[] = { JSValueMakeString(context, string) };
1765 o = JSObjectMakeError(context, 1, argumentsErrorValues, NULL);
1766 assertEqualsAsUTF8String(o, "Error: an error message");
1767 JSStringRelease(string);
1768
1769 string = JSStringCreateWithUTF8CString("foo");
1770 JSStringRef string2 = JSStringCreateWithUTF8CString("gi");
1771 JSValueRef argumentsRegExpValues[] = { JSValueMakeString(context, string), JSValueMakeString(context, string2) };
1772 o = JSObjectMakeRegExp(context, 2, argumentsRegExpValues, NULL);
1773 assertEqualsAsUTF8String(o, "/foo/gi");
1774 JSStringRelease(string);
1775 JSStringRelease(string2);
1776
1777 JSClassDefinition nullDefinition = kJSClassDefinitionEmpty;
1778 nullDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
1779 JSClassRef nullClass = JSClassCreate(&nullDefinition);
1780 JSClassRelease(nullClass);
1781
1782 nullDefinition = kJSClassDefinitionEmpty;
1783 nullClass = JSClassCreate(&nullDefinition);
1784 JSClassRelease(nullClass);
1785
1786 functionBody = JSStringCreateWithUTF8CString("return this;");
1787 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
1788 JSStringRelease(functionBody);
1789 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1790 ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1791 v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
1792 ASSERT(JSValueIsEqual(context, v, o, NULL));
1793
1794 functionBody = JSStringCreateWithUTF8CString("return eval(\"this\");");
1795 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
1796 JSStringRelease(functionBody);
1797 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
1798 ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1799 v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
1800 ASSERT(JSValueIsEqual(context, v, o, NULL));
1801
1802 const char* thisScript = "this;";
1803 JSStringRef script = JSStringCreateWithUTF8CString(thisScript);
1804 v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
1805 ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1806 v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
1807 ASSERT(JSValueIsEqual(context, v, o, NULL));
1808 JSStringRelease(script);
1809
1810 JSScriptRef scriptObject = JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, thisScript, strlen(thisScript), 0, 0);
1811 v = JSScriptEvaluate(context, scriptObject, NULL, NULL);
1812 ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1813 v = JSScriptEvaluate(context, scriptObject, o, NULL);
1814 ASSERT(JSValueIsEqual(context, v, o, NULL));
1815 JSScriptRelease(scriptObject);
1816
1817 script = JSStringCreateWithUTF8CString("eval(this);");
1818 v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL);
1819 ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
1820 v = JSEvaluateScript(context, script, o, NULL, 1, NULL);
1821 ASSERT(JSValueIsEqual(context, v, o, NULL));
1822 JSStringRelease(script);
1823
1824 exception = NULL;
1825 script = JSStringCreateWithUTF8CString("rreturn Array;");
1826 JSStringRef sourceURL = JSStringCreateWithUTF8CString("file:///foo/bar.js");
1827 JSStringRef sourceURLKey = JSStringCreateWithUTF8CString("sourceURL");
1828 JSEvaluateScript(context, script, NULL, sourceURL, 1, &exception);
1829 ASSERT(exception);
1830 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), sourceURLKey, NULL);
1831 assertEqualsAsUTF8String(v, "file:///foo/bar.js");
1832 JSStringRelease(script);
1833 JSStringRelease(sourceURL);
1834 JSStringRelease(sourceURLKey);
1835
1836 // Verify that creating a constructor for a class with no static functions does not trigger
1837 // an assert inside putDirect or lead to a crash during GC. <https://bugs.webkit.org/show_bug.cgi?id=25785>
1838 nullDefinition = kJSClassDefinitionEmpty;
1839 nullClass = JSClassCreate(&nullDefinition);
1840 JSObjectMakeConstructor(context, nullClass, 0);
1841 JSClassRelease(nullClass);
1842
1843 char* scriptUTF8 = createStringWithContentsOfFile(scriptPath);
1844 if (!scriptUTF8) {
1845 printf("FAIL: Test script could not be loaded.\n");
1846 failed = 1;
1847 } else {
1848 JSStringRef url = JSStringCreateWithUTF8CString(scriptPath);
1849 JSStringRef script = JSStringCreateWithUTF8CString(scriptUTF8);
1850 JSStringRef errorMessage = 0;
1851 int errorLine = 0;
1852 JSScriptRef scriptObject = JSScriptCreateFromString(contextGroup, url, 1, script, &errorMessage, &errorLine);
1853 ASSERT((!scriptObject) != (!errorMessage));
1854 if (!scriptObject) {
1855 printf("FAIL: Test script did not parse\n\t%s:%d\n\t", scriptPath, errorLine);
1856 CFStringRef errorCF = JSStringCopyCFString(kCFAllocatorDefault, errorMessage);
1857 CFShow(errorCF);
1858 CFRelease(errorCF);
1859 JSStringRelease(errorMessage);
1860 failed = 1;
1861 }
1862
1863 JSStringRelease(script);
1864 exception = NULL;
1865 result = scriptObject ? JSScriptEvaluate(context, scriptObject, 0, &exception) : 0;
1866 if (result && JSValueIsUndefined(context, result))
1867 printf("PASS: Test script executed successfully.\n");
1868 else {
1869 printf("FAIL: Test script returned unexpected value:\n");
1870 JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL);
1871 CFStringRef exceptionCF = JSStringCopyCFString(kCFAllocatorDefault, exceptionIString);
1872 CFShow(exceptionCF);
1873 CFRelease(exceptionCF);
1874 JSStringRelease(exceptionIString);
1875 failed = 1;
1876 }
1877 JSScriptRelease(scriptObject);
1878 free(scriptUTF8);
1879 }
1880
1881 #if OS(DARWIN)
1882 JSStringRef currentCPUTimeStr = JSStringCreateWithUTF8CString("currentCPUTime");
1883 JSObjectRef currentCPUTimeFunction = JSObjectMakeFunctionWithCallback(context, currentCPUTimeStr, currentCPUTime_callAsFunction);
1884 JSObjectSetProperty(context, globalObject, currentCPUTimeStr, currentCPUTimeFunction, kJSPropertyAttributeNone, NULL);
1885 JSStringRelease(currentCPUTimeStr);
1886
1887 /* Test script timeout: */
1888 JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, shouldTerminateCallback, 0);
1889 {
1890 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
1891 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
1892 double startTime;
1893 double endTime;
1894 exception = NULL;
1895 shouldTerminateCallbackWasCalled = false;
1896 startTime = currentCPUTime();
1897 v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
1898 endTime = currentCPUTime();
1899
1900 if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled)
1901 printf("PASS: script timed out as expected.\n");
1902 else {
1903 if (!((endTime - startTime) < .150f))
1904 printf("FAIL: script did not timed out as expected.\n");
1905 if (!shouldTerminateCallbackWasCalled)
1906 printf("FAIL: script timeout callback was not called.\n");
1907 failed = true;
1908 }
1909
1910 if (!exception) {
1911 printf("FAIL: TerminatedExecutionException was not thrown.\n");
1912 failed = true;
1913 }
1914 }
1915
1916 /* Test the script timeout's TerminatedExecutionException should NOT be catchable: */
1917 JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, shouldTerminateCallback, 0);
1918 {
1919 const char* loopForeverScript = "var startTime = currentCPUTime(); try { while (true) { if (currentCPUTime() - startTime > .150) break; } } catch(e) { }";
1920 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
1921 double startTime;
1922 double endTime;
1923 exception = NULL;
1924 shouldTerminateCallbackWasCalled = false;
1925 startTime = currentCPUTime();
1926 v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
1927 endTime = currentCPUTime();
1928
1929 if (((endTime - startTime) >= .150f) || !shouldTerminateCallbackWasCalled) {
1930 if (!((endTime - startTime) < .150f))
1931 printf("FAIL: script did not timed out as expected.\n");
1932 if (!shouldTerminateCallbackWasCalled)
1933 printf("FAIL: script timeout callback was not called.\n");
1934 failed = true;
1935 }
1936
1937 if (exception)
1938 printf("PASS: TerminatedExecutionException was not catchable as expected.\n");
1939 else {
1940 printf("FAIL: TerminatedExecutionException was caught.\n");
1941 failed = true;
1942 }
1943 }
1944
1945 /* Test script timeout with no callback: */
1946 JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, 0, 0);
1947 {
1948 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
1949 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
1950 double startTime;
1951 double endTime;
1952 exception = NULL;
1953 startTime = currentCPUTime();
1954 v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
1955 endTime = currentCPUTime();
1956
1957 if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled)
1958 printf("PASS: script timed out as expected when no callback is specified.\n");
1959 else {
1960 if (!((endTime - startTime) < .150f))
1961 printf("FAIL: script did not timed out as expected when no callback is specified.\n");
1962 failed = true;
1963 }
1964
1965 if (!exception) {
1966 printf("FAIL: TerminatedExecutionException was not thrown.\n");
1967 failed = true;
1968 }
1969 }
1970
1971 /* Test script timeout cancellation: */
1972 JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, cancelTerminateCallback, 0);
1973 {
1974 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
1975 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
1976 double startTime;
1977 double endTime;
1978 exception = NULL;
1979 startTime = currentCPUTime();
1980 v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
1981 endTime = currentCPUTime();
1982
1983 if (((endTime - startTime) >= .150f) && cancelTerminateCallbackWasCalled && !exception)
1984 printf("PASS: script timeout was cancelled as expected.\n");
1985 else {
1986 if (((endTime - startTime) < .150) || exception)
1987 printf("FAIL: script timeout was not cancelled.\n");
1988 if (!cancelTerminateCallbackWasCalled)
1989 printf("FAIL: script timeout callback was not called.\n");
1990 failed = true;
1991 }
1992
1993 if (exception) {
1994 printf("FAIL: Unexpected TerminatedExecutionException thrown.\n");
1995 failed = true;
1996 }
1997 }
1998
1999 /* Test script timeout extension: */
2000 JSContextGroupSetExecutionTimeLimit(contextGroup, 0.100f, extendTerminateCallback, 0);
2001 {
2002 const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .500) break; } ";
2003 JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
2004 double startTime;
2005 double endTime;
2006 double deltaTime;
2007 exception = NULL;
2008 startTime = currentCPUTime();
2009 v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
2010 endTime = currentCPUTime();
2011 deltaTime = endTime - startTime;
2012
2013 if ((deltaTime >= .300f) && (deltaTime < .500f) && (extendTerminateCallbackCalled == 2) && exception)
2014 printf("PASS: script timeout was extended as expected.\n");
2015 else {
2016 if (deltaTime < .200f)
2017 printf("FAIL: script timeout was not extended as expected.\n");
2018 else if (deltaTime >= .500f)
2019 printf("FAIL: script did not timeout.\n");
2020
2021 if (extendTerminateCallbackCalled < 1)
2022 printf("FAIL: script timeout callback was not called.\n");
2023 if (extendTerminateCallbackCalled < 2)
2024 printf("FAIL: script timeout callback was not called after timeout extension.\n");
2025
2026 if (!exception)
2027 printf("FAIL: TerminatedExecutionException was not thrown during timeout extension test.\n");
2028
2029 failed = true;
2030 }
2031 }
2032 #endif /* OS(DARWIN) */
2033
2034 // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
2035 function = NULL;
2036 v = NULL;
2037 o = NULL;
2038 globalObject = NULL;
2039 myConstructor = NULL;
2040
2041 JSStringRelease(jsEmptyIString);
2042 JSStringRelease(jsOneIString);
2043 JSStringRelease(jsCFIString);
2044 JSStringRelease(jsCFEmptyIString);
2045 JSStringRelease(jsCFIStringWithCharacters);
2046 JSStringRelease(jsCFEmptyIStringWithCharacters);
2047 JSStringRelease(goodSyntax);
2048 JSStringRelease(badSyntax);
2049
2050 JSGlobalContextRelease(context);
2051 JSClassRelease(globalObjectClass);
2052
2053 // Test for an infinite prototype chain that used to be created. This test
2054 // passes if the call to JSObjectHasProperty() does not hang.
2055
2056 JSClassDefinition prototypeLoopClassDefinition = kJSClassDefinitionEmpty;
2057 prototypeLoopClassDefinition.staticFunctions = globalObject_staticFunctions;
2058 JSClassRef prototypeLoopClass = JSClassCreate(&prototypeLoopClassDefinition);
2059 JSGlobalContextRef prototypeLoopContext = JSGlobalContextCreateInGroup(NULL, prototypeLoopClass);
2060
2061 JSStringRef nameProperty = JSStringCreateWithUTF8CString("name");
2062 JSObjectHasProperty(prototypeLoopContext, JSContextGetGlobalObject(prototypeLoopContext), nameProperty);
2063
2064 JSGlobalContextRelease(prototypeLoopContext);
2065 JSClassRelease(prototypeLoopClass);
2066
2067 printf("PASS: Infinite prototype chain does not occur.\n");
2068
2069 if (checkForCycleInPrototypeChain())
2070 printf("PASS: A cycle in a prototype chain can't be created.\n");
2071 else {
2072 printf("FAIL: A cycle in a prototype chain can be created.\n");
2073 failed = true;
2074 }
2075 if (valueToObjectExceptionTest())
2076 printf("PASS: throwException did not crash when handling an error with appendMessageToError set and no codeBlock available.\n");
2077
2078 if (globalContextNameTest())
2079 printf("PASS: global context name behaves as expected.\n");
2080
2081 customGlobalObjectClassTest();
2082 globalObjectSetPrototypeTest();
2083 globalObjectPrivatePropertyTest();
2084
2085 if (failed) {
2086 printf("FAIL: Some tests failed.\n");
2087 return 1;
2088 }
2089
2090 printf("PASS: Program exited normally.\n");
2091 return 0;
2092 }
2093
2094 static char* createStringWithContentsOfFile(const char* fileName)
2095 {
2096 char* buffer;
2097
2098 size_t buffer_size = 0;
2099 size_t buffer_capacity = 1024;
2100 buffer = (char*)malloc(buffer_capacity);
2101
2102 FILE* f = fopen(fileName, "r");
2103 if (!f) {
2104 fprintf(stderr, "Could not open file: %s\n", fileName);
2105 free(buffer);
2106 return 0;
2107 }
2108
2109 while (!feof(f) && !ferror(f)) {
2110 buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f);
2111 if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0'
2112 buffer_capacity *= 2;
2113 buffer = (char*)realloc(buffer, buffer_capacity);
2114 ASSERT(buffer);
2115 }
2116
2117 ASSERT(buffer_size < buffer_capacity);
2118 }
2119 fclose(f);
2120 buffer[buffer_size] = '\0';
2121
2122 return buffer;
2123 }