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