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