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