]> git.saurik.com Git - apple/javascriptcore.git/blob - API/testapi.c
JavaScriptCore-466.1.tar.gz
[apple/javascriptcore.git] / API / testapi.c
1 // -*- mode: c++; c-basic-offset: 4 -*-
2 /*
3 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "JavaScriptCore.h"
28 #include <math.h>
29 #include <wtf/Assertions.h>
30 #include <wtf/UnusedParam.h>
31
32 static JSGlobalContextRef context = 0;
33
34 static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue)
35 {
36 if (JSValueToBoolean(context, value) != expectedValue)
37 fprintf(stderr, "assertEqualsAsBoolean failed: %p, %d\n", value, expectedValue);
38 }
39
40 static void assertEqualsAsNumber(JSValueRef value, double expectedValue)
41 {
42 double number = JSValueToNumber(context, value, NULL);
43
44 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
45 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
46 // After that's resolved, we can remove these casts
47 if (number != expectedValue && !(isnan((float)number) && isnan((float)expectedValue)))
48 fprintf(stderr, "assertEqualsAsNumber failed: %p, %lf\n", value, expectedValue);
49 }
50
51 static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue)
52 {
53 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
54
55 size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString);
56 char jsBuffer[jsSize];
57 JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize);
58
59 unsigned i;
60 for (i = 0; jsBuffer[i]; i++)
61 if (jsBuffer[i] != expectedValue[i])
62 fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]);
63
64 if (jsSize < strlen(jsBuffer) + 1)
65 fprintf(stderr, "assertEqualsAsUTF8String failed: jsSize was too small\n");
66
67 JSStringRelease(valueAsString);
68 }
69
70 static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedValue)
71 {
72 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL);
73
74 size_t jsLength = JSStringGetLength(valueAsString);
75 const JSChar* jsBuffer = JSStringGetCharactersPtr(valueAsString);
76
77 CFStringRef expectedValueAsCFString = CFStringCreateWithCString(kCFAllocatorDefault,
78 expectedValue,
79 kCFStringEncodingUTF8);
80 CFIndex cfLength = CFStringGetLength(expectedValueAsCFString);
81 UniChar cfBuffer[cfLength];
82 CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer);
83 CFRelease(expectedValueAsCFString);
84
85 if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0)
86 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n");
87
88 if (jsLength != (size_t)cfLength)
89 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength);
90
91 JSStringRelease(valueAsString);
92 }
93
94 static JSValueRef jsGlobalValue; // non-stack value for testing JSValueProtect()
95
96 /* MyObject pseudo-class */
97
98 static bool MyObject_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName)
99 {
100 UNUSED_PARAM(context);
101 UNUSED_PARAM(object);
102
103 if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")
104 || JSStringIsEqualToUTF8CString(propertyName, "cantFind")
105 || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")
106 || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")
107 || JSStringIsEqualToUTF8CString(propertyName, "0")) {
108 return true;
109 }
110
111 return false;
112 }
113
114 static JSValueRef MyObject_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
115 {
116 UNUSED_PARAM(context);
117 UNUSED_PARAM(object);
118
119 if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")) {
120 return JSValueMakeNumber(context, 1);
121 }
122
123 if (JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")) {
124 return JSValueMakeNumber(context, 1);
125 }
126
127 if (JSStringIsEqualToUTF8CString(propertyName, "cantFind")) {
128 return JSValueMakeUndefined(context);
129 }
130
131 if (JSStringIsEqualToUTF8CString(propertyName, "0")) {
132 *exception = JSValueMakeNumber(context, 1);
133 return JSValueMakeNumber(context, 1);
134 }
135
136 return NULL;
137 }
138
139 static bool MyObject_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
140 {
141 UNUSED_PARAM(context);
142 UNUSED_PARAM(object);
143 UNUSED_PARAM(value);
144 UNUSED_PARAM(exception);
145
146 if (JSStringIsEqualToUTF8CString(propertyName, "cantSet"))
147 return true; // pretend we set the property in order to swallow it
148
149 return false;
150 }
151
152 static bool MyObject_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
153 {
154 UNUSED_PARAM(context);
155 UNUSED_PARAM(object);
156
157 if (JSStringIsEqualToUTF8CString(propertyName, "cantDelete"))
158 return true;
159
160 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnDelete")) {
161 *exception = JSValueMakeNumber(context, 2);
162 return false;
163 }
164
165 return false;
166 }
167
168 static void MyObject_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
169 {
170 UNUSED_PARAM(context);
171 UNUSED_PARAM(object);
172
173 JSStringRef propertyName;
174
175 propertyName = JSStringCreateWithUTF8CString("alwaysOne");
176 JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
177 JSStringRelease(propertyName);
178
179 propertyName = JSStringCreateWithUTF8CString("myPropertyName");
180 JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
181 JSStringRelease(propertyName);
182 }
183
184 static JSValueRef MyObject_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
185 {
186 UNUSED_PARAM(context);
187 UNUSED_PARAM(object);
188 UNUSED_PARAM(thisObject);
189 UNUSED_PARAM(exception);
190
191 if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
192 return JSValueMakeNumber(context, 1);
193
194 return JSValueMakeUndefined(context);
195 }
196
197 static JSObjectRef MyObject_callAsConstructor(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
198 {
199 UNUSED_PARAM(context);
200 UNUSED_PARAM(object);
201
202 if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
203 return JSValueToObject(context, JSValueMakeNumber(context, 1), exception);
204
205 return JSValueToObject(context, JSValueMakeNumber(context, 0), exception);
206 }
207
208 static bool MyObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
209 {
210 UNUSED_PARAM(context);
211 UNUSED_PARAM(constructor);
212
213 JSStringRef numberString = JSStringCreateWithUTF8CString("Number");
214 JSObjectRef numberConstructor = JSValueToObject(context, JSObjectGetProperty(context, JSContextGetGlobalObject(context), numberString, exception), exception);
215 JSStringRelease(numberString);
216
217 return JSValueIsInstanceOfConstructor(context, possibleValue, numberConstructor, exception);
218 }
219
220 static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
221 {
222 UNUSED_PARAM(object);
223 UNUSED_PARAM(exception);
224
225 switch (type) {
226 case kJSTypeNumber:
227 return JSValueMakeNumber(context, 1);
228 default:
229 break;
230 }
231
232 // string conversion -- forward to default object class
233 return NULL;
234 }
235
236 static JSStaticValue evilStaticValues[] = {
237 { "nullGetSet", 0, 0, kJSPropertyAttributeNone },
238 { 0, 0, 0, 0 }
239 };
240
241 static JSStaticFunction evilStaticFunctions[] = {
242 { "nullCall", 0, kJSPropertyAttributeNone },
243 { 0, 0, 0 }
244 };
245
246 JSClassDefinition MyObject_definition = {
247 0,
248 kJSClassAttributeNone,
249
250 "MyObject",
251 NULL,
252
253 evilStaticValues,
254 evilStaticFunctions,
255
256 NULL,
257 NULL,
258 MyObject_hasProperty,
259 MyObject_getProperty,
260 MyObject_setProperty,
261 MyObject_deleteProperty,
262 MyObject_getPropertyNames,
263 MyObject_callAsFunction,
264 MyObject_callAsConstructor,
265 MyObject_hasInstance,
266 MyObject_convertToType,
267 };
268
269 static JSClassRef MyObject_class(JSContextRef context)
270 {
271 UNUSED_PARAM(context);
272
273 static JSClassRef jsClass;
274 if (!jsClass)
275 jsClass = JSClassCreate(&MyObject_definition);
276
277 return jsClass;
278 }
279
280 static JSValueRef Base_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
281 {
282 UNUSED_PARAM(object);
283 UNUSED_PARAM(propertyName);
284 UNUSED_PARAM(exception);
285
286 return JSValueMakeNumber(ctx, 1); // distinguish base get form derived get
287 }
288
289 static bool Base_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
290 {
291 UNUSED_PARAM(object);
292 UNUSED_PARAM(propertyName);
293 UNUSED_PARAM(value);
294
295 *exception = JSValueMakeNumber(ctx, 1); // distinguish base set from derived set
296 return true;
297 }
298
299 static JSValueRef Base_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
300 {
301 UNUSED_PARAM(function);
302 UNUSED_PARAM(thisObject);
303 UNUSED_PARAM(argumentCount);
304 UNUSED_PARAM(arguments);
305 UNUSED_PARAM(exception);
306
307 return JSValueMakeNumber(ctx, 1); // distinguish base call from derived call
308 }
309
310 static JSStaticFunction Base_staticFunctions[] = {
311 { "baseProtoDup", NULL, kJSPropertyAttributeNone },
312 { "baseProto", Base_callAsFunction, kJSPropertyAttributeNone },
313 { 0, 0, 0 }
314 };
315
316 static JSStaticValue Base_staticValues[] = {
317 { "baseDup", Base_get, Base_set, kJSPropertyAttributeNone },
318 { "baseOnly", Base_get, Base_set, kJSPropertyAttributeNone },
319 { 0, 0, 0, 0 }
320 };
321
322 static bool TestInitializeFinalize;
323 static void Base_initialize(JSContextRef context, JSObjectRef object)
324 {
325 UNUSED_PARAM(context);
326
327 if (TestInitializeFinalize) {
328 ASSERT((void*)1 == JSObjectGetPrivate(object));
329 JSObjectSetPrivate(object, (void*)2);
330 }
331 }
332
333 static unsigned Base_didFinalize;
334 static void Base_finalize(JSObjectRef object)
335 {
336 UNUSED_PARAM(object);
337 if (TestInitializeFinalize) {
338 ASSERT((void*)4 == JSObjectGetPrivate(object));
339 Base_didFinalize = true;
340 }
341 }
342
343 static JSClassRef Base_class(JSContextRef context)
344 {
345 UNUSED_PARAM(context);
346
347 static JSClassRef jsClass;
348 if (!jsClass) {
349 JSClassDefinition definition = kJSClassDefinitionEmpty;
350 definition.staticValues = Base_staticValues;
351 definition.staticFunctions = Base_staticFunctions;
352 definition.initialize = Base_initialize;
353 definition.finalize = Base_finalize;
354 jsClass = JSClassCreate(&definition);
355 }
356 return jsClass;
357 }
358
359 static JSValueRef Derived_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
360 {
361 UNUSED_PARAM(object);
362 UNUSED_PARAM(propertyName);
363 UNUSED_PARAM(exception);
364
365 return JSValueMakeNumber(ctx, 2); // distinguish base get form derived get
366 }
367
368 static bool Derived_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
369 {
370 UNUSED_PARAM(ctx);
371 UNUSED_PARAM(object);
372 UNUSED_PARAM(propertyName);
373 UNUSED_PARAM(value);
374
375 *exception = JSValueMakeNumber(ctx, 2); // distinguish base set from derived set
376 return true;
377 }
378
379 static JSValueRef Derived_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
380 {
381 UNUSED_PARAM(function);
382 UNUSED_PARAM(thisObject);
383 UNUSED_PARAM(argumentCount);
384 UNUSED_PARAM(arguments);
385 UNUSED_PARAM(exception);
386
387 return JSValueMakeNumber(ctx, 2); // distinguish base call from derived call
388 }
389
390 static JSStaticFunction Derived_staticFunctions[] = {
391 { "protoOnly", Derived_callAsFunction, kJSPropertyAttributeNone },
392 { "protoDup", NULL, kJSPropertyAttributeNone },
393 { "baseProtoDup", Derived_callAsFunction, kJSPropertyAttributeNone },
394 { 0, 0, 0 }
395 };
396
397 static JSStaticValue Derived_staticValues[] = {
398 { "derivedOnly", Derived_get, Derived_set, kJSPropertyAttributeNone },
399 { "protoDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
400 { "baseDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
401 { 0, 0, 0, 0 }
402 };
403
404 static void Derived_initialize(JSContextRef context, JSObjectRef object)
405 {
406 UNUSED_PARAM(context);
407
408 if (TestInitializeFinalize) {
409 ASSERT((void*)2 == JSObjectGetPrivate(object));
410 JSObjectSetPrivate(object, (void*)3);
411 }
412 }
413
414 static void Derived_finalize(JSObjectRef object)
415 {
416 if (TestInitializeFinalize) {
417 ASSERT((void*)3 == JSObjectGetPrivate(object));
418 JSObjectSetPrivate(object, (void*)4);
419 }
420 }
421
422 static JSClassRef Derived_class(JSContextRef context)
423 {
424 static JSClassRef jsClass;
425 if (!jsClass) {
426 JSClassDefinition definition = kJSClassDefinitionEmpty;
427 definition.parentClass = Base_class(context);
428 definition.staticValues = Derived_staticValues;
429 definition.staticFunctions = Derived_staticFunctions;
430 definition.initialize = Derived_initialize;
431 definition.finalize = Derived_finalize;
432 jsClass = JSClassCreate(&definition);
433 }
434 return jsClass;
435 }
436
437 static JSValueRef print_callAsFunction(JSContextRef context, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
438 {
439 UNUSED_PARAM(functionObject);
440 UNUSED_PARAM(thisObject);
441 UNUSED_PARAM(exception);
442
443 if (argumentCount > 0) {
444 JSStringRef string = JSValueToStringCopy(context, arguments[0], NULL);
445 size_t sizeUTF8 = JSStringGetMaximumUTF8CStringSize(string);
446 char stringUTF8[sizeUTF8];
447 JSStringGetUTF8CString(string, stringUTF8, sizeUTF8);
448 printf("%s\n", stringUTF8);
449 JSStringRelease(string);
450 }
451
452 return JSValueMakeUndefined(context);
453 }
454
455 static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
456 {
457 UNUSED_PARAM(constructorObject);
458 UNUSED_PARAM(exception);
459
460 JSObjectRef result = JSObjectMake(context, NULL, NULL);
461 if (argumentCount > 0) {
462 JSStringRef value = JSStringCreateWithUTF8CString("value");
463 JSObjectSetProperty(context, result, value, arguments[0], kJSPropertyAttributeNone, NULL);
464 JSStringRelease(value);
465 }
466
467 return result;
468 }
469
470
471 static void globalObject_initialize(JSContextRef context, JSObjectRef object)
472 {
473 UNUSED_PARAM(object);
474 // Ensure that an execution context is passed in
475 ASSERT(context);
476
477 // Ensure that the global object is set to the object that we were passed
478 JSObjectRef globalObject = JSContextGetGlobalObject(context);
479 ASSERT(globalObject);
480 ASSERT(object == globalObject);
481
482 // Ensure that the standard global properties have been set on the global object
483 JSStringRef array = JSStringCreateWithUTF8CString("Array");
484 JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
485 JSStringRelease(array);
486
487 UNUSED_PARAM(arrayConstructor);
488 ASSERT(arrayConstructor);
489 }
490
491 static JSValueRef globalObject_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
492 {
493 UNUSED_PARAM(object);
494 UNUSED_PARAM(propertyName);
495 UNUSED_PARAM(exception);
496
497 return JSValueMakeNumber(ctx, 3);
498 }
499
500 static bool globalObject_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
501 {
502 UNUSED_PARAM(object);
503 UNUSED_PARAM(propertyName);
504 UNUSED_PARAM(value);
505
506 *exception = JSValueMakeNumber(ctx, 3);
507 return true;
508 }
509
510 static JSValueRef globalObject_call(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
511 {
512 UNUSED_PARAM(function);
513 UNUSED_PARAM(thisObject);
514 UNUSED_PARAM(argumentCount);
515 UNUSED_PARAM(arguments);
516 UNUSED_PARAM(exception);
517
518 return JSValueMakeNumber(ctx, 3);
519 }
520
521 static JSStaticValue globalObject_staticValues[] = {
522 { "globalStaticValue", globalObject_get, globalObject_set, kJSPropertyAttributeNone },
523 { 0, 0, 0, 0 }
524 };
525
526 static JSStaticFunction globalObject_staticFunctions[] = {
527 { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone },
528 { 0, 0, 0 }
529 };
530
531 static char* createStringWithContentsOfFile(const char* fileName);
532
533 static void testInitializeFinalize()
534 {
535 JSObjectRef o = JSObjectMake(context, Derived_class(context), (void*)1);
536 UNUSED_PARAM(o);
537 ASSERT(JSObjectGetPrivate(o) == (void*)3);
538 }
539
540 int main(int argc, char* argv[])
541 {
542 const char *scriptPath = "testapi.js";
543 if (argc > 1) {
544 scriptPath = argv[1];
545 }
546
547 // Test garbage collection with a fresh context
548 context = JSGlobalContextCreate(NULL);
549 TestInitializeFinalize = true;
550 testInitializeFinalize();
551 JSGlobalContextRelease(context);
552 JSGarbageCollect(context);
553 TestInitializeFinalize = false;
554
555 ASSERT(Base_didFinalize);
556
557 JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty;
558 globalObjectClassDefinition.initialize = globalObject_initialize;
559 globalObjectClassDefinition.staticValues = globalObject_staticValues;
560 globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions;
561 globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
562 JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition);
563 context = JSGlobalContextCreate(globalObjectClass);
564
565 JSObjectRef globalObject = JSContextGetGlobalObject(context);
566 ASSERT(JSValueIsObject(context, globalObject));
567
568 JSValueRef jsUndefined = JSValueMakeUndefined(context);
569 JSValueRef jsNull = JSValueMakeNull(context);
570 JSValueRef jsTrue = JSValueMakeBoolean(context, true);
571 JSValueRef jsFalse = JSValueMakeBoolean(context, false);
572 JSValueRef jsZero = JSValueMakeNumber(context, 0);
573 JSValueRef jsOne = JSValueMakeNumber(context, 1);
574 JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0);
575 JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, NULL);
576 JSObjectSetPrototype(context, jsObjectNoProto, JSValueMakeNull(context));
577
578 // FIXME: test funny utf8 characters
579 JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString("");
580 JSValueRef jsEmptyString = JSValueMakeString(context, jsEmptyIString);
581
582 JSStringRef jsOneIString = JSStringCreateWithUTF8CString("1");
583 JSValueRef jsOneString = JSValueMakeString(context, jsOneIString);
584
585 UniChar singleUniChar = 65; // Capital A
586 CFMutableStringRef cfString =
587 CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault,
588 &singleUniChar,
589 1,
590 1,
591 kCFAllocatorNull);
592
593 JSStringRef jsCFIString = JSStringCreateWithCFString(cfString);
594 JSValueRef jsCFString = JSValueMakeString(context, jsCFIString);
595
596 CFStringRef cfEmptyString = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8);
597
598 JSStringRef jsCFEmptyIString = JSStringCreateWithCFString(cfEmptyString);
599 JSValueRef jsCFEmptyString = JSValueMakeString(context, jsCFEmptyIString);
600
601 CFIndex cfStringLength = CFStringGetLength(cfString);
602 UniChar buffer[cfStringLength];
603 CFStringGetCharacters(cfString,
604 CFRangeMake(0, cfStringLength),
605 buffer);
606 JSStringRef jsCFIStringWithCharacters = JSStringCreateWithCharacters(buffer, cfStringLength);
607 JSValueRef jsCFStringWithCharacters = JSValueMakeString(context, jsCFIStringWithCharacters);
608
609 JSStringRef jsCFEmptyIStringWithCharacters = JSStringCreateWithCharacters(buffer, CFStringGetLength(cfEmptyString));
610 JSValueRef jsCFEmptyStringWithCharacters = JSValueMakeString(context, jsCFEmptyIStringWithCharacters);
611
612 ASSERT(JSValueGetType(context, jsUndefined) == kJSTypeUndefined);
613 ASSERT(JSValueGetType(context, jsNull) == kJSTypeNull);
614 ASSERT(JSValueGetType(context, jsTrue) == kJSTypeBoolean);
615 ASSERT(JSValueGetType(context, jsFalse) == kJSTypeBoolean);
616 ASSERT(JSValueGetType(context, jsZero) == kJSTypeNumber);
617 ASSERT(JSValueGetType(context, jsOne) == kJSTypeNumber);
618 ASSERT(JSValueGetType(context, jsOneThird) == kJSTypeNumber);
619 ASSERT(JSValueGetType(context, jsEmptyString) == kJSTypeString);
620 ASSERT(JSValueGetType(context, jsOneString) == kJSTypeString);
621 ASSERT(JSValueGetType(context, jsCFString) == kJSTypeString);
622 ASSERT(JSValueGetType(context, jsCFStringWithCharacters) == kJSTypeString);
623 ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString);
624 ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);
625
626 JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
627 JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
628 JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
629 JSStringRelease(myObjectIString);
630
631 JSValueRef exception;
632
633 // Conversions that throw exceptions
634 exception = NULL;
635 ASSERT(NULL == JSValueToObject(context, jsNull, &exception));
636 ASSERT(exception);
637
638 exception = NULL;
639 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function,
640 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team.
641 // After that's resolved, we can remove these casts
642 ASSERT(isnan((float)JSValueToNumber(context, jsObjectNoProto, &exception)));
643 ASSERT(exception);
644
645 exception = NULL;
646 ASSERT(!JSValueToStringCopy(context, jsObjectNoProto, &exception));
647 ASSERT(exception);
648
649 ASSERT(JSValueToBoolean(context, myObject));
650
651 exception = NULL;
652 ASSERT(!JSValueIsEqual(context, jsObjectNoProto, JSValueMakeNumber(context, 1), &exception));
653 ASSERT(exception);
654
655 exception = NULL;
656 JSObjectGetPropertyAtIndex(context, myObject, 0, &exception);
657 ASSERT(1 == JSValueToNumber(context, exception, NULL));
658
659 assertEqualsAsBoolean(jsUndefined, false);
660 assertEqualsAsBoolean(jsNull, false);
661 assertEqualsAsBoolean(jsTrue, true);
662 assertEqualsAsBoolean(jsFalse, false);
663 assertEqualsAsBoolean(jsZero, false);
664 assertEqualsAsBoolean(jsOne, true);
665 assertEqualsAsBoolean(jsOneThird, true);
666 assertEqualsAsBoolean(jsEmptyString, false);
667 assertEqualsAsBoolean(jsOneString, true);
668 assertEqualsAsBoolean(jsCFString, true);
669 assertEqualsAsBoolean(jsCFStringWithCharacters, true);
670 assertEqualsAsBoolean(jsCFEmptyString, false);
671 assertEqualsAsBoolean(jsCFEmptyStringWithCharacters, false);
672
673 assertEqualsAsNumber(jsUndefined, nan(""));
674 assertEqualsAsNumber(jsNull, 0);
675 assertEqualsAsNumber(jsTrue, 1);
676 assertEqualsAsNumber(jsFalse, 0);
677 assertEqualsAsNumber(jsZero, 0);
678 assertEqualsAsNumber(jsOne, 1);
679 assertEqualsAsNumber(jsOneThird, 1.0 / 3.0);
680 assertEqualsAsNumber(jsEmptyString, 0);
681 assertEqualsAsNumber(jsOneString, 1);
682 assertEqualsAsNumber(jsCFString, nan(""));
683 assertEqualsAsNumber(jsCFStringWithCharacters, nan(""));
684 assertEqualsAsNumber(jsCFEmptyString, 0);
685 assertEqualsAsNumber(jsCFEmptyStringWithCharacters, 0);
686 ASSERT(sizeof(JSChar) == sizeof(UniChar));
687
688 assertEqualsAsCharactersPtr(jsUndefined, "undefined");
689 assertEqualsAsCharactersPtr(jsNull, "null");
690 assertEqualsAsCharactersPtr(jsTrue, "true");
691 assertEqualsAsCharactersPtr(jsFalse, "false");
692 assertEqualsAsCharactersPtr(jsZero, "0");
693 assertEqualsAsCharactersPtr(jsOne, "1");
694 assertEqualsAsCharactersPtr(jsOneThird, "0.3333333333333333");
695 assertEqualsAsCharactersPtr(jsEmptyString, "");
696 assertEqualsAsCharactersPtr(jsOneString, "1");
697 assertEqualsAsCharactersPtr(jsCFString, "A");
698 assertEqualsAsCharactersPtr(jsCFStringWithCharacters, "A");
699 assertEqualsAsCharactersPtr(jsCFEmptyString, "");
700 assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters, "");
701
702 assertEqualsAsUTF8String(jsUndefined, "undefined");
703 assertEqualsAsUTF8String(jsNull, "null");
704 assertEqualsAsUTF8String(jsTrue, "true");
705 assertEqualsAsUTF8String(jsFalse, "false");
706 assertEqualsAsUTF8String(jsZero, "0");
707 assertEqualsAsUTF8String(jsOne, "1");
708 assertEqualsAsUTF8String(jsOneThird, "0.3333333333333333");
709 assertEqualsAsUTF8String(jsEmptyString, "");
710 assertEqualsAsUTF8String(jsOneString, "1");
711 assertEqualsAsUTF8String(jsCFString, "A");
712 assertEqualsAsUTF8String(jsCFStringWithCharacters, "A");
713 assertEqualsAsUTF8String(jsCFEmptyString, "");
714 assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters, "");
715
716 ASSERT(JSValueIsStrictEqual(context, jsTrue, jsTrue));
717 ASSERT(!JSValueIsStrictEqual(context, jsOne, jsOneString));
718
719 ASSERT(JSValueIsEqual(context, jsOne, jsOneString, NULL));
720 ASSERT(!JSValueIsEqual(context, jsTrue, jsFalse, NULL));
721
722 CFStringRef cfJSString = JSStringCopyCFString(kCFAllocatorDefault, jsCFIString);
723 CFStringRef cfJSEmptyString = JSStringCopyCFString(kCFAllocatorDefault, jsCFEmptyIString);
724 ASSERT(CFEqual(cfJSString, cfString));
725 ASSERT(CFEqual(cfJSEmptyString, cfEmptyString));
726 CFRelease(cfJSString);
727 CFRelease(cfJSEmptyString);
728
729 CFRelease(cfString);
730 CFRelease(cfEmptyString);
731
732 jsGlobalValue = JSObjectMake(context, NULL, NULL);
733 JSValueProtect(context, jsGlobalValue);
734 JSGarbageCollect(context);
735 ASSERT(JSValueIsObject(context, jsGlobalValue));
736 JSValueUnprotect(context, jsGlobalValue);
737
738 JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;");
739 JSStringRef badSyntax = JSStringCreateWithUTF8CString("x := 1;");
740 ASSERT(JSCheckScriptSyntax(context, goodSyntax, NULL, 0, NULL));
741 ASSERT(!JSCheckScriptSyntax(context, badSyntax, NULL, 0, NULL));
742
743 JSValueRef result;
744 JSValueRef v;
745 JSObjectRef o;
746 JSStringRef string;
747
748 result = JSEvaluateScript(context, goodSyntax, NULL, NULL, 1, NULL);
749 ASSERT(result);
750 ASSERT(JSValueIsEqual(context, result, jsOne, NULL));
751
752 exception = NULL;
753 result = JSEvaluateScript(context, badSyntax, NULL, NULL, 1, &exception);
754 ASSERT(!result);
755 ASSERT(JSValueIsObject(context, exception));
756
757 JSStringRef array = JSStringCreateWithUTF8CString("Array");
758 JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL);
759 JSStringRelease(array);
760 result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL);
761 ASSERT(result);
762 ASSERT(JSValueIsObject(context, result));
763 ASSERT(JSValueIsInstanceOfConstructor(context, result, arrayConstructor, NULL));
764 ASSERT(!JSValueIsInstanceOfConstructor(context, JSValueMakeNull(context), arrayConstructor, NULL));
765
766 o = JSValueToObject(context, result, NULL);
767 exception = NULL;
768 ASSERT(JSValueIsUndefined(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception)));
769 ASSERT(!exception);
770
771 JSObjectSetPropertyAtIndex(context, o, 0, JSValueMakeNumber(context, 1), &exception);
772 ASSERT(!exception);
773
774 exception = NULL;
775 ASSERT(1 == JSValueToNumber(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception), &exception));
776 ASSERT(!exception);
777
778 JSStringRef functionBody;
779 JSObjectRef function;
780
781 exception = NULL;
782 functionBody = JSStringCreateWithUTF8CString("rreturn Array;");
783 JSStringRef line = JSStringCreateWithUTF8CString("line");
784 ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception));
785 ASSERT(JSValueIsObject(context, exception));
786 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL);
787 assertEqualsAsNumber(v, 2); // FIXME: Lexer::setCode bumps startingLineNumber by 1 -- we need to change internal callers so that it doesn't have to (saying '0' to mean '1' in the API would be really confusing -- it's really confusing internally, in fact)
788 JSStringRelease(functionBody);
789 JSStringRelease(line);
790
791 exception = NULL;
792 functionBody = JSStringCreateWithUTF8CString("return Array;");
793 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception);
794 JSStringRelease(functionBody);
795 ASSERT(!exception);
796 ASSERT(JSObjectIsFunction(context, function));
797 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
798 ASSERT(v);
799 ASSERT(JSValueIsEqual(context, v, arrayConstructor, NULL));
800
801 exception = NULL;
802 function = JSObjectMakeFunction(context, NULL, 0, NULL, jsEmptyIString, NULL, 0, &exception);
803 ASSERT(!exception);
804 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, &exception);
805 ASSERT(v && !exception);
806 ASSERT(JSValueIsUndefined(context, v));
807
808 exception = NULL;
809 v = NULL;
810 JSStringRef foo = JSStringCreateWithUTF8CString("foo");
811 JSStringRef argumentNames[] = { foo };
812 functionBody = JSStringCreateWithUTF8CString("return foo;");
813 function = JSObjectMakeFunction(context, foo, 1, argumentNames, functionBody, NULL, 1, &exception);
814 ASSERT(function && !exception);
815 JSValueRef arguments[] = { JSValueMakeNumber(context, 2) };
816 v = JSObjectCallAsFunction(context, function, NULL, 1, arguments, &exception);
817 JSStringRelease(foo);
818 JSStringRelease(functionBody);
819
820 string = JSValueToStringCopy(context, function, NULL);
821 assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) \n{\n return foo;\n}");
822 JSStringRelease(string);
823
824 JSStringRef print = JSStringCreateWithUTF8CString("print");
825 JSObjectRef printFunction = JSObjectMakeFunctionWithCallback(context, print, print_callAsFunction);
826 JSObjectSetProperty(context, globalObject, print, printFunction, kJSPropertyAttributeNone, NULL);
827 JSStringRelease(print);
828
829 ASSERT(!JSObjectSetPrivate(printFunction, (void*)1));
830 ASSERT(!JSObjectGetPrivate(printFunction));
831
832 JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor");
833 JSObjectRef myConstructor = JSObjectMakeConstructor(context, NULL, myConstructor_callAsConstructor);
834 JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL);
835 JSStringRelease(myConstructorIString);
836
837 ASSERT(!JSObjectSetPrivate(myConstructor, (void*)1));
838 ASSERT(!JSObjectGetPrivate(myConstructor));
839
840 string = JSStringCreateWithUTF8CString("Derived");
841 JSObjectRef derivedConstructor = JSObjectMakeConstructor(context, Derived_class(context), NULL);
842 JSObjectSetProperty(context, globalObject, string, derivedConstructor, kJSPropertyAttributeNone, NULL);
843 JSStringRelease(string);
844
845 o = JSObjectMake(context, NULL, NULL);
846 JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL);
847 JSObjectSetProperty(context, o, jsCFIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL);
848 JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o);
849 size_t expectedCount = JSPropertyNameArrayGetCount(nameArray);
850 size_t count;
851 for (count = 0; count < expectedCount; ++count)
852 JSPropertyNameArrayGetNameAtIndex(nameArray, count);
853 JSPropertyNameArrayRelease(nameArray);
854 ASSERT(count == 1); // jsCFString should not be enumerated
855
856 JSClassDefinition nullDefinition = kJSClassDefinitionEmpty;
857 nullDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
858 JSClassRef nullClass = JSClassCreate(&nullDefinition);
859 JSClassRelease(nullClass);
860
861 nullDefinition = kJSClassDefinitionEmpty;
862 nullClass = JSClassCreate(&nullDefinition);
863 JSClassRelease(nullClass);
864
865 functionBody = JSStringCreateWithUTF8CString("return this;");
866 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
867 JSStringRelease(functionBody);
868 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
869 ASSERT(JSValueIsEqual(context, v, globalObject, NULL));
870 v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
871 ASSERT(JSValueIsEqual(context, v, o, NULL));
872
873 char* scriptUTF8 = createStringWithContentsOfFile(scriptPath);
874 if (!scriptUTF8)
875 printf("FAIL: Test script could not be loaded.\n");
876 else {
877 JSStringRef script = JSStringCreateWithUTF8CString(scriptUTF8);
878 result = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
879 if (JSValueIsUndefined(context, result))
880 printf("PASS: Test script executed successfully.\n");
881 else {
882 printf("FAIL: Test script returned unexpected value:\n");
883 JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL);
884 CFStringRef exceptionCF = JSStringCopyCFString(kCFAllocatorDefault, exceptionIString);
885 CFShow(exceptionCF);
886 CFRelease(exceptionCF);
887 JSStringRelease(exceptionIString);
888 }
889 JSStringRelease(script);
890 free(scriptUTF8);
891 }
892
893 // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
894 function = NULL;
895 v = NULL;
896 o = NULL;
897 globalObject = NULL;
898
899 JSStringRelease(jsEmptyIString);
900 JSStringRelease(jsOneIString);
901 JSStringRelease(jsCFIString);
902 JSStringRelease(jsCFEmptyIString);
903 JSStringRelease(jsCFIStringWithCharacters);
904 JSStringRelease(jsCFEmptyIStringWithCharacters);
905 JSStringRelease(goodSyntax);
906 JSStringRelease(badSyntax);
907
908 JSGlobalContextRelease(context);
909 JSGarbageCollect(context);
910 JSClassRelease(globalObjectClass);
911
912 printf("PASS: Program exited normally.\n");
913 return 0;
914 }
915
916 static char* createStringWithContentsOfFile(const char* fileName)
917 {
918 char* buffer;
919
920 size_t buffer_size = 0;
921 size_t buffer_capacity = 1024;
922 buffer = (char*)malloc(buffer_capacity);
923
924 FILE* f = fopen(fileName, "r");
925 if (!f) {
926 fprintf(stderr, "Could not open file: %s\n", fileName);
927 return 0;
928 }
929
930 while (!feof(f) && !ferror(f)) {
931 buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f);
932 if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0'
933 buffer_capacity *= 2;
934 buffer = (char*)realloc(buffer, buffer_capacity);
935 ASSERT(buffer);
936 }
937
938 ASSERT(buffer_size < buffer_capacity);
939 }
940 fclose(f);
941 buffer[buffer_size] = '\0';
942
943 return buffer;
944 }