1 /* 2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "JavaScriptCore.h" 27 #include "JSBasePrivate.h" 28 #include "JSContextRefPrivate.h" 29 #include <math.h> 30 #define ASSERT_DISABLED 0 31 #include <wtf/Assertions.h> 32 #include <wtf/UnusedParam.h> 33 34 #if COMPILER(MSVC) 35 36 #include <wtf/MathExtras.h> 37 38 static double nan(const char*) 39 { 40 return std::numeric_limits<double>::quiet_NaN(); 41 } 42 43 #endif 44 45 static JSGlobalContextRef context; 46 static int failed; 47 static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue) 48 { 49 if (JSValueToBoolean(context, value) != expectedValue) { 50 fprintf(stderr, "assertEqualsAsBoolean failed: %p, %d\n", value, expectedValue); 51 failed = 1; 52 } 53 } 54 55 static 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 62 if (number != expectedValue && !(isnan((float)number) && isnan((float)expectedValue))) { 63 fprintf(stderr, "assertEqualsAsNumber failed: %p, %lf\n", value, expectedValue); 64 failed = 1; 65 } 66 } 67 68 static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue) 69 { 70 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL); 71 72 size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString); 73 char* jsBuffer = (char*)malloc(jsSize); 74 JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize); 75 76 unsigned i; 77 for (i = 0; jsBuffer[i]; i++) { 78 if (jsBuffer[i] != expectedValue[i]) { 79 fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]); 80 failed = 1; 81 } 82 } 83 84 if (jsSize < strlen(jsBuffer) + 1) { 85 fprintf(stderr, "assertEqualsAsUTF8String failed: jsSize was too small\n"); 86 failed = 1; 87 } 88 89 free(jsBuffer); 90 JSStringRelease(valueAsString); 91 } 92 93 static 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); 104 UniChar* cfBuffer = (UniChar*)malloc(cfLength * sizeof(UniChar)); 105 CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer); 106 CFRelease(expectedValueAsCFString); 107 108 if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0) { 109 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n"); 110 failed = 1; 111 } 112 113 if (jsLength != (size_t)cfLength) { 114 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength); 115 failed = 1; 116 } 117 118 free(cfBuffer); 119 JSStringRelease(valueAsString); 120 } 121 122 static bool timeZoneIsPST() 123 { 124 char timeZoneName[70]; 125 struct tm gtm; 126 memset(>m, 0, sizeof(gtm)); 127 strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m); 128 129 return 0 == strcmp("PST", timeZoneName); 130 } 131 132 static JSValueRef jsGlobalValue; // non-stack value for testing JSValueProtect() 133 134 /* MyObject pseudo-class */ 135 136 static 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") 143 || JSStringIsEqualToUTF8CString(propertyName, "throwOnGet") 144 || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName") 145 || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie") 146 || JSStringIsEqualToUTF8CString(propertyName, "0")) { 147 return true; 148 } 149 150 return false; 151 } 152 153 static 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 } 169 170 if (JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")) { 171 return 0; 172 } 173 174 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")) { 175 return JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); 176 } 177 178 if (JSStringIsEqualToUTF8CString(propertyName, "0")) { 179 *exception = JSValueMakeNumber(context, 1); 180 return JSValueMakeNumber(context, 1); 181 } 182 183 return JSValueMakeNull(context); 184 } 185 186 static 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 196 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnSet")) { 197 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); 198 } 199 200 return false; 201 } 202 203 static 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")) { 212 JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); 213 return false; 214 } 215 216 return false; 217 } 218 219 static 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 235 static 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 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 247 if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0))) 248 return JSValueMakeNumber(context, 1); 249 250 return JSValueMakeUndefined(context); 251 } 252 253 static 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 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 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 269 static bool MyObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception) 270 { 271 UNUSED_PARAM(context); 272 UNUSED_PARAM(constructor); 273 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 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 286 static 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); 294 case kJSTypeString: 295 { 296 JSStringRef string = JSStringCreateWithUTF8CString("MyObjectAsString"); 297 JSValueRef result = JSValueMakeString(context, string); 298 JSStringRelease(string); 299 return result; 300 } 301 default: 302 break; 303 } 304 305 // string conversion -- forward to default object class 306 return JSValueMakeNull(context); 307 } 308 309 static JSStaticValue evilStaticValues[] = { 310 { "nullGetSet", 0, 0, kJSPropertyAttributeNone }, 311 { 0, 0, 0, 0 } 312 }; 313 314 static JSStaticFunction evilStaticFunctions[] = { 315 { "nullCall", 0, kJSPropertyAttributeNone }, 316 { 0, 0, 0 } 317 }; 318 319 JSClassDefinition 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 342 static 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 353 static 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 368 static 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: 381 return JSValueMakeNull(context); 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) 389 return JSValueMakeNull(context); 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 400 JSClassDefinition 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 423 static 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 434 JSClassDefinition 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 457 static 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 469 static 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 478 static 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 488 static 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 499 static JSStaticFunction Base_staticFunctions[] = { 500 { "baseProtoDup", NULL, kJSPropertyAttributeNone }, 501 { "baseProto", Base_callAsFunction, kJSPropertyAttributeNone }, 502 { 0, 0, 0 } 503 }; 504 505 static JSStaticValue Base_staticValues[] = { 506 { "baseDup", Base_get, Base_set, kJSPropertyAttributeNone }, 507 { "baseOnly", Base_get, Base_set, kJSPropertyAttributeNone }, 508 { 0, 0, 0, 0 } 509 }; 510 511 static bool TestInitializeFinalize; 512 static 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 522 static unsigned Base_didFinalize; 523 static 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 532 static 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 548 static 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 557 static 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 568 static 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 579 static JSStaticFunction Derived_staticFunctions[] = { 580 { "protoOnly", Derived_callAsFunction, kJSPropertyAttributeNone }, 581 { "protoDup", NULL, kJSPropertyAttributeNone }, 582 { "baseProtoDup", Derived_callAsFunction, kJSPropertyAttributeNone }, 583 { 0, 0, 0 } 584 }; 585 586 static 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 593 static 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 603 static void Derived_finalize(JSObjectRef object) 604 { 605 if (TestInitializeFinalize) { 606 ASSERT((void*)3 == JSObjectGetPrivate(object)); 607 JSObjectSetPrivate(object, (void*)4); 608 } 609 } 610 611 static 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 626 static 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 637 static JSValueRef print_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 638 { 639 UNUSED_PARAM(functionObject); 640 UNUSED_PARAM(thisObject); 641 UNUSED_PARAM(exception); 642 643 ASSERT(JSContextGetGlobalContext(ctx) == context); 644 645 if (argumentCount > 0) { 646 JSStringRef string = JSValueToStringCopy(ctx, arguments[0], NULL); 647 size_t sizeUTF8 = JSStringGetMaximumUTF8CStringSize(string); 648 char* stringUTF8 = (char*)malloc(sizeUTF8); 649 JSStringGetUTF8CString(string, stringUTF8, sizeUTF8); 650 printf("%s\n", stringUTF8); 651 free(stringUTF8); 652 JSStringRelease(string); 653 } 654 655 return JSValueMakeUndefined(ctx); 656 } 657 658 static 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 674 static 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 694 static 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 703 static 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 713 static 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 724 static 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 735 static JSStaticValue globalObject_staticValues[] = { 736 { "globalStaticValue", globalObject_get, globalObject_set, kJSPropertyAttributeNone }, 737 { 0, 0, 0, 0 } 738 }; 739 740 static JSStaticFunction globalObject_staticFunctions[] = { 741 { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone }, 742 { "gc", functionGC, kJSPropertyAttributeNone }, 743 { 0, 0, 0 } 744 }; 745 746 static char* createStringWithContentsOfFile(const char* fileName); 747 748 static 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 755 static JSValueRef jsNumberValue = NULL; 756 757 static void makeGlobalNumberValue(JSContextRef context) { 758 JSValueRef v = JSValueMakeNumber(context, 420); 759 JSValueProtect(context, v); 760 jsNumberValue = v; 761 v = NULL; 762 } 763 764 int 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 772 context = JSGlobalContextCreateInGroup(NULL, NULL); 773 TestInitializeFinalize = true; 774 testInitializeFinalize(); 775 JSGlobalContextRelease(context); 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); 786 context = JSGlobalContextCreateInGroup(NULL, globalObjectClass); 787 788 JSGlobalContextRetain(context); 789 JSGlobalContextRelease(context); 790 ASSERT(JSContextGetGlobalContext(context) == context); 791 792 JSReportExtraMemoryCost(context, 0); 793 JSReportExtraMemoryCost(context, 1); 794 JSReportExtraMemoryCost(context, 1024); 795 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); 833 UniChar* buffer = (UniChar*)malloc(cfStringLength * sizeof(UniChar)); 834 CFStringGetCharacters(cfString, 835 CFRangeMake(0, cfStringLength), 836 buffer); 837 JSStringRef jsCFIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, cfStringLength); 838 JSValueRef jsCFStringWithCharacters = JSValueMakeString(context, jsCFIStringWithCharacters); 839 840 JSStringRef jsCFEmptyIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, CFStringGetLength(cfEmptyString)); 841 free(buffer); 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 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 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); 975 makeGlobalNumberValue(context); 976 JSValueProtect(context, jsGlobalValue); 977 JSGarbageCollect(context); 978 ASSERT(JSValueIsObject(context, jsGlobalValue)); 979 JSValueUnprotect(context, jsGlobalValue); 980 JSValueUnprotect(context, jsNumberValue); 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); 1031 assertEqualsAsNumber(v, 1); 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); 1065 assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) { return foo;\n}"); 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 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 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 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 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 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); 1127 if (timeZoneIsPST()) 1128 assertEqualsAsUTF8String(o, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)"); 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 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)); 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 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 1190 char* scriptUTF8 = createStringWithContentsOfFile(scriptPath); 1191 if (!scriptUTF8) { 1192 printf("FAIL: Test script could not be loaded.\n"); 1193 failed = 1; 1194 } else { 1195 script = JSStringCreateWithUTF8CString(scriptUTF8); 1196 result = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); 1197 if (result && JSValueIsUndefined(context, result)) 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); 1206 failed = 1; 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; 1217 myConstructor = NULL; 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); 1229 JSClassRelease(globalObjectClass); 1230 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 1252 printf("PASS: Program exited normally.\n"); 1253 return 0; 1254 } 1255 1256 static 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 } 1285