]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - API/tests/testapi.mm
JavaScriptCore-7600.1.4.17.5.tar.gz
[apple/javascriptcore.git] / API / tests / testapi.mm
... / ...
CommitLineData
1/*
2 * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import <JavaScriptCore/JavaScriptCore.h>
27
28#import "CurrentThisInsideBlockGetterTest.h"
29#import "DateTests.h"
30#import "JSExportTests.h"
31#import "Regress141809.h"
32
33#import <pthread.h>
34
35extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef);
36extern "C" void JSSynchronousEdenCollectForDebugging(JSContextRef);
37
38extern "C" bool _Block_has_signature(id);
39extern "C" const char * _Block_signature(id);
40
41extern int failed;
42extern "C" void testObjectiveCAPI(void);
43extern "C" void checkResult(NSString *, bool);
44
45#if JSC_OBJC_API_ENABLED
46
47@interface UnexportedObject : NSObject
48@end
49
50@implementation UnexportedObject
51@end
52
53@protocol ParentObject <JSExport>
54@end
55
56@interface ParentObject : NSObject<ParentObject>
57+ (NSString *)parentTest;
58@end
59
60@implementation ParentObject
61+ (NSString *)parentTest
62{
63 return [self description];
64}
65@end
66
67@protocol TestObject <JSExport>
68- (id)init;
69@property int variable;
70@property (readonly) int six;
71@property CGPoint point;
72+ (NSString *)classTest;
73+ (NSString *)parentTest;
74- (NSString *)getString;
75JSExportAs(testArgumentTypes,
76- (NSString *)testArgumentTypesWithInt:(int)i double:(double)d boolean:(BOOL)b string:(NSString *)s number:(NSNumber *)n array:(NSArray *)a dictionary:(NSDictionary *)o
77);
78- (void)callback:(JSValue *)function;
79- (void)bogusCallback:(void(^)(int))function;
80@end
81
82@interface TestObject : ParentObject <TestObject>
83@property int six;
84+ (id)testObject;
85@end
86
87@implementation TestObject
88@synthesize variable;
89@synthesize six;
90@synthesize point;
91+ (id)testObject
92{
93 return [[TestObject alloc] init];
94}
95+ (NSString *)classTest
96{
97 return @"classTest - okay";
98}
99- (NSString *)getString
100{
101 return @"42";
102}
103- (NSString *)testArgumentTypesWithInt:(int)i double:(double)d boolean:(BOOL)b string:(NSString *)s number:(NSNumber *)n array:(NSArray *)a dictionary:(NSDictionary *)o
104{
105 return [NSString stringWithFormat:@"%d,%g,%d,%@,%d,%@,%@", i, d, b==YES?true:false,s,[n intValue],a[1],o[@"x"]];
106}
107- (void)callback:(JSValue *)function
108{
109 [function callWithArguments:[NSArray arrayWithObject:[NSNumber numberWithInt:42]]];
110}
111- (void)bogusCallback:(void(^)(int))function
112{
113 function(42);
114}
115@end
116
117bool testXYZTested = false;
118
119@protocol TextXYZ <JSExport>
120- (id)initWithString:(NSString*)string;
121@property int x;
122@property (readonly) int y;
123@property (assign) JSValue *onclick;
124@property (assign) JSValue *weakOnclick;
125- (void)test:(NSString *)message;
126@end
127
128@interface TextXYZ : NSObject <TextXYZ>
129@property int x;
130@property int y;
131@property int z;
132- (void)click;
133@end
134
135@implementation TextXYZ {
136 JSManagedValue *m_weakOnclickHandler;
137 JSManagedValue *m_onclickHandler;
138}
139@synthesize x;
140@synthesize y;
141@synthesize z;
142- (id)initWithString:(NSString*)string
143{
144 self = [super init];
145 if (!self)
146 return nil;
147
148 NSLog(@"%@", string);
149
150 return self;
151}
152- (void)test:(NSString *)message
153{
154 testXYZTested = [message isEqual:@"test"] && x == 13 & y == 4 && z == 5;
155}
156- (void)setWeakOnclick:(JSValue *)value
157{
158 m_weakOnclickHandler = [JSManagedValue managedValueWithValue:value];
159}
160
161- (void)setOnclick:(JSValue *)value
162{
163 m_onclickHandler = [JSManagedValue managedValueWithValue:value];
164 [value.context.virtualMachine addManagedReference:m_onclickHandler withOwner:self];
165}
166- (JSValue *)weakOnclick
167{
168 return [m_weakOnclickHandler value];
169}
170- (JSValue *)onclick
171{
172 return [m_onclickHandler value];
173}
174- (void)click
175{
176 if (!m_onclickHandler)
177 return;
178
179 JSValue *function = [m_onclickHandler value];
180 [function callWithArguments:[NSArray array]];
181}
182@end
183
184@class TinyDOMNode;
185
186@protocol TinyDOMNode <JSExport>
187- (void)appendChild:(TinyDOMNode *)child;
188- (NSUInteger)numberOfChildren;
189- (TinyDOMNode *)childAtIndex:(NSUInteger)index;
190- (void)removeChildAtIndex:(NSUInteger)index;
191@end
192
193@interface TinyDOMNode : NSObject<TinyDOMNode>
194@end
195
196@implementation TinyDOMNode {
197 NSMutableArray *m_children;
198 JSVirtualMachine *m_sharedVirtualMachine;
199}
200
201- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine
202{
203 self = [super init];
204 if (!self)
205 return nil;
206
207 m_children = [[NSMutableArray alloc] initWithCapacity:0];
208 m_sharedVirtualMachine = virtualMachine;
209#if !__has_feature(objc_arc)
210 [m_sharedVirtualMachine retain];
211#endif
212
213 return self;
214}
215
216- (void)appendChild:(TinyDOMNode *)child
217{
218 [m_sharedVirtualMachine addManagedReference:child withOwner:self];
219 [m_children addObject:child];
220}
221
222- (NSUInteger)numberOfChildren
223{
224 return [m_children count];
225}
226
227- (TinyDOMNode *)childAtIndex:(NSUInteger)index
228{
229 if (index >= [m_children count])
230 return nil;
231 return [m_children objectAtIndex:index];
232}
233
234- (void)removeChildAtIndex:(NSUInteger)index
235{
236 if (index >= [m_children count])
237 return;
238 [m_sharedVirtualMachine removeManagedReference:[m_children objectAtIndex:index] withOwner:self];
239 [m_children removeObjectAtIndex:index];
240}
241
242@end
243
244@interface JSCollection : NSObject
245- (void)setValue:(JSValue *)value forKey:(NSString *)key;
246- (JSValue *)valueForKey:(NSString *)key;
247@end
248
249@implementation JSCollection {
250 NSMutableDictionary *_dict;
251}
252- (id)init
253{
254 self = [super init];
255 if (!self)
256 return nil;
257
258 _dict = [[NSMutableDictionary alloc] init];
259
260 return self;
261}
262
263- (void)setValue:(JSValue *)value forKey:(NSString *)key
264{
265 JSManagedValue *oldManagedValue = [_dict objectForKey:key];
266 if (oldManagedValue) {
267 JSValue* oldValue = [oldManagedValue value];
268 if (oldValue)
269 [oldValue.context.virtualMachine removeManagedReference:oldManagedValue withOwner:self];
270 }
271 JSManagedValue *managedValue = [JSManagedValue managedValueWithValue:value];
272 [value.context.virtualMachine addManagedReference:managedValue withOwner:self];
273 [_dict setObject:managedValue forKey:key];
274}
275
276- (JSValue *)valueForKey:(NSString *)key
277{
278 JSManagedValue *managedValue = [_dict objectForKey:key];
279 if (!managedValue)
280 return nil;
281 return [managedValue value];
282}
283@end
284
285@protocol InitA <JSExport>
286- (id)initWithA:(int)a;
287- (int)initialize;
288@end
289
290@protocol InitB <JSExport>
291- (id)initWithA:(int)a b:(int)b;
292@end
293
294@protocol InitC <JSExport>
295- (id)_init;
296@end
297
298@interface ClassA : NSObject<InitA>
299@end
300
301@interface ClassB : ClassA<InitB>
302@end
303
304@interface ClassC : ClassB<InitA, InitB>
305@end
306
307@interface ClassCPrime : ClassB<InitA, InitC>
308@end
309
310@interface ClassD : NSObject<InitA>
311- (id)initWithA:(int)a;
312@end
313
314@interface ClassE : ClassD
315- (id)initWithA:(int)a;
316@end
317
318@implementation ClassA {
319 int _a;
320}
321- (id)initWithA:(int)a
322{
323 self = [super init];
324 if (!self)
325 return nil;
326
327 _a = a;
328
329 return self;
330}
331- (int)initialize
332{
333 return 42;
334}
335@end
336
337@implementation ClassB {
338 int _b;
339}
340- (id)initWithA:(int)a b:(int)b
341{
342 self = [super initWithA:a];
343 if (!self)
344 return nil;
345
346 _b = b;
347
348 return self;
349}
350@end
351
352@implementation ClassC {
353 int _c;
354}
355- (id)initWithA:(int)a
356{
357 return [self initWithA:a b:0];
358}
359- (id)initWithA:(int)a b:(int)b
360{
361 self = [super initWithA:a b:b];
362 if (!self)
363 return nil;
364
365 _c = a + b;
366
367 return self;
368}
369@end
370
371@implementation ClassCPrime
372- (id)initWithA:(int)a
373{
374 self = [super initWithA:a b:0];
375 if (!self)
376 return nil;
377 return self;
378}
379- (id)_init
380{
381 return [self initWithA:42];
382}
383@end
384
385@implementation ClassD
386
387- (id)initWithA:(int)a
388{
389 self = nil;
390 return [[ClassE alloc] initWithA:a];
391}
392- (int)initialize
393{
394 return 0;
395}
396@end
397
398@implementation ClassE {
399 int _a;
400}
401
402- (id)initWithA:(int)a
403{
404 self = [super init];
405 if (!self)
406 return nil;
407
408 _a = a;
409
410 return self;
411}
412@end
413
414static bool evilAllocationObjectWasDealloced = false;
415
416@interface EvilAllocationObject : NSObject
417- (JSValue *)doEvilThingsWithContext:(JSContext *)context;
418@end
419
420@implementation EvilAllocationObject {
421 JSContext *m_context;
422}
423- (id)initWithContext:(JSContext *)context
424{
425 self = [super init];
426 if (!self)
427 return nil;
428
429 m_context = context;
430
431 return self;
432}
433- (void)dealloc
434{
435 [self doEvilThingsWithContext:m_context];
436 evilAllocationObjectWasDealloced = true;
437#if !__has_feature(objc_arc)
438 [super dealloc];
439#endif
440}
441
442- (JSValue *)doEvilThingsWithContext:(JSContext *)context
443{
444 JSValue *result = [context evaluateScript:@" \
445 (function() { \
446 var a = []; \
447 var sum = 0; \
448 for (var i = 0; i < 10000; ++i) { \
449 sum += i; \
450 a[i] = sum; \
451 } \
452 return sum; \
453 })()"];
454
455 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
456 return result;
457}
458@end
459
460extern "C" void checkResult(NSString *description, bool passed)
461{
462 NSLog(@"TEST: \"%@\": %@", description, passed ? @"PASSED" : @"FAILED");
463 if (!passed)
464 failed = 1;
465}
466
467static bool blockSignatureContainsClass()
468{
469 static bool containsClass = ^{
470 id block = ^(NSString *string){ return string; };
471 return _Block_has_signature(block) && strstr(_Block_signature(block), "NSString");
472 }();
473 return containsClass;
474}
475
476static void* threadMain(void* contextPtr)
477{
478 JSContext *context = (__bridge JSContext*)contextPtr;
479
480 // Do something to enter the VM.
481 TestObject *testObject = [TestObject testObject];
482 context[@"testObject"] = testObject;
483 pthread_exit(nullptr);
484}
485
486void testObjectiveCAPI()
487{
488 NSLog(@"Testing Objective-C API");
489
490 @autoreleasepool {
491 JSVirtualMachine* vm = [[JSVirtualMachine alloc] init];
492 JSContext* context = [[JSContext alloc] initWithVirtualMachine:vm];
493 [context evaluateScript:@"bad"];
494 }
495
496 @autoreleasepool {
497 JSContext *context = [[JSContext alloc] init];
498 JSValue *result = [context evaluateScript:@"2 + 2"];
499 checkResult(@"2 + 2", [result isNumber] && [result toInt32] == 4);
500 }
501
502 @autoreleasepool {
503 JSContext *context = [[JSContext alloc] init];
504 NSString *result = [NSString stringWithFormat:@"Two plus two is %@", [context evaluateScript:@"2 + 2"]];
505 checkResult(@"stringWithFormat", [result isEqual:@"Two plus two is 4"]);
506 }
507
508 @autoreleasepool {
509 JSContext *context = [[JSContext alloc] init];
510 context[@"message"] = @"Hello";
511 JSValue *result = [context evaluateScript:@"message + ', World!'"];
512 checkResult(@"Hello, World!", [result isString] && [result isEqualToObject:@"Hello, World!"]);
513 }
514
515 @autoreleasepool {
516 JSContext *context = [[JSContext alloc] init];
517 JSValue *result = [context evaluateScript:@"({ x:42 })"];
518 checkResult(@"({ x:42 })", [result isObject] && [result[@"x"] isEqualToObject:@42]);
519 id obj = [result toObject];
520 checkResult(@"Check dictionary literal", [obj isKindOfClass:[NSDictionary class]]);
521 id num = (NSDictionary *)obj[@"x"];
522 checkResult(@"Check numeric literal", [num isKindOfClass:[NSNumber class]]);
523 }
524
525 @autoreleasepool {
526 JSCollection* myPrivateProperties = [[JSCollection alloc] init];
527
528 @autoreleasepool {
529 JSContext* context = [[JSContext alloc] init];
530 TestObject* rootObject = [TestObject testObject];
531 context[@"root"] = rootObject;
532 [context.virtualMachine addManagedReference:myPrivateProperties withOwner:rootObject];
533 [myPrivateProperties setValue:[JSValue valueWithBool:true inContext:context] forKey:@"is_ham"];
534 [myPrivateProperties setValue:[JSValue valueWithObject:@"hello!" inContext:context] forKey:@"message"];
535 [myPrivateProperties setValue:[JSValue valueWithInt32:42 inContext:context] forKey:@"my_number"];
536 [myPrivateProperties setValue:[JSValue valueWithNullInContext:context] forKey:@"definitely_null"];
537 [myPrivateProperties setValue:[JSValue valueWithUndefinedInContext:context] forKey:@"not_sure_if_undefined"];
538
539 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
540
541 JSValue *isHam = [myPrivateProperties valueForKey:@"is_ham"];
542 JSValue *message = [myPrivateProperties valueForKey:@"message"];
543 JSValue *myNumber = [myPrivateProperties valueForKey:@"my_number"];
544 JSValue *definitelyNull = [myPrivateProperties valueForKey:@"definitely_null"];
545 JSValue *notSureIfUndefined = [myPrivateProperties valueForKey:@"not_sure_if_undefined"];
546 checkResult(@"is_ham is true", [isHam isBoolean] && [isHam toBool]);
547 checkResult(@"message is hello!", [message isString] && [@"hello!" isEqualToString:[message toString]]);
548 checkResult(@"my_number is 42", [myNumber isNumber] && [myNumber toInt32] == 42);
549 checkResult(@"definitely_null is null", [definitelyNull isNull]);
550 checkResult(@"not_sure_if_undefined is undefined", [notSureIfUndefined isUndefined]);
551 }
552
553 checkResult(@"is_ham is nil", ![myPrivateProperties valueForKey:@"is_ham"]);
554 checkResult(@"message is nil", ![myPrivateProperties valueForKey:@"message"]);
555 checkResult(@"my_number is 42", ![myPrivateProperties valueForKey:@"my_number"]);
556 checkResult(@"definitely_null is null", ![myPrivateProperties valueForKey:@"definitely_null"]);
557 checkResult(@"not_sure_if_undefined is undefined", ![myPrivateProperties valueForKey:@"not_sure_if_undefined"]);
558 }
559
560 @autoreleasepool {
561 JSContext *context = [[JSContext alloc] init];
562 JSValue *message = [JSValue valueWithObject:@"hello" inContext:context];
563 TestObject *rootObject = [TestObject testObject];
564 JSCollection *collection = [[JSCollection alloc] init];
565 context[@"root"] = rootObject;
566 @autoreleasepool {
567 JSValue *jsCollection = [JSValue valueWithObject:collection inContext:context];
568 JSManagedValue *weakCollection = [JSManagedValue managedValueWithValue:jsCollection andOwner:rootObject];
569 [context.virtualMachine addManagedReference:weakCollection withOwner:message];
570 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
571 }
572 }
573
574 @autoreleasepool {
575 JSContext *context = [[JSContext alloc] init];
576 __block int result;
577 context[@"blockCallback"] = ^(int value){
578 result = value;
579 };
580 [context evaluateScript:@"blockCallback(42)"];
581 checkResult(@"blockCallback", result == 42);
582 }
583
584 if (blockSignatureContainsClass()) {
585 @autoreleasepool {
586 JSContext *context = [[JSContext alloc] init];
587 __block bool result = false;
588 context[@"blockCallback"] = ^(NSString *value){
589 result = [@"42" isEqualToString:value] == YES;
590 };
591 [context evaluateScript:@"blockCallback(42)"];
592 checkResult(@"blockCallback(NSString *)", result);
593 }
594 } else
595 NSLog(@"Skipping 'blockCallback(NSString *)' test case");
596
597 @autoreleasepool {
598 JSContext *context = [[JSContext alloc] init];
599 checkResult(@"!context.exception", !context.exception);
600 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
601 checkResult(@"context.exception", context.exception);
602 }
603
604 @autoreleasepool {
605 JSContext *context = [[JSContext alloc] init];
606 __block bool caught = false;
607 context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
608 (void)context;
609 (void)exception;
610 caught = true;
611 };
612 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
613 checkResult(@"JSContext.exceptionHandler", caught);
614 }
615
616 @autoreleasepool {
617 JSContext *context = [[JSContext alloc] init];
618 __block int expectedExceptionLineNumber = 1;
619 __block bool sawExpectedExceptionLineNumber = false;
620 context.exceptionHandler = ^(JSContext *, JSValue *exception) {
621 sawExpectedExceptionLineNumber = [exception[@"line"] toInt32] == expectedExceptionLineNumber;
622 };
623 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
624 checkResult(@"evaluteScript exception on line 1", sawExpectedExceptionLineNumber);
625
626 expectedExceptionLineNumber = 2;
627 sawExpectedExceptionLineNumber = false;
628 [context evaluateScript:@"// Line 1\n!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
629 checkResult(@"evaluteScript exception on line 2", sawExpectedExceptionLineNumber);
630 }
631
632 @autoreleasepool {
633 JSContext *context = [[JSContext alloc] init];
634 __block bool emptyExceptionSourceURL = false;
635 context.exceptionHandler = ^(JSContext *, JSValue *exception) {
636 emptyExceptionSourceURL = [exception[@"sourceURL"] isUndefined];
637 };
638 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
639 checkResult(@"evaluteScript: exception has no sourceURL", emptyExceptionSourceURL);
640
641 __block NSString *exceptionSourceURL = nil;
642 context.exceptionHandler = ^(JSContext *, JSValue *exception) {
643 exceptionSourceURL = [exception[@"sourceURL"] toString];
644 };
645 NSURL *url = [NSURL fileURLWithPath:@"/foo/bar.js"];
646 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()" withSourceURL:url];
647 checkResult(@"evaluateScript:withSourceURL: exception has expected sourceURL", [exceptionSourceURL isEqualToString:[url absoluteString]]);
648 }
649
650 @autoreleasepool {
651 JSContext *context = [[JSContext alloc] init];
652 context[@"callback"] = ^{
653 JSContext *context = [JSContext currentContext];
654 context.exception = [JSValue valueWithNewErrorFromMessage:@"Something went wrong." inContext:context];
655 };
656 JSValue *result = [context evaluateScript:@"var result; try { callback(); } catch (e) { result = 'Caught exception'; }"];
657 checkResult(@"Explicit throw in callback - was caught by JavaScript", [result isEqualToObject:@"Caught exception"]);
658 checkResult(@"Explicit throw in callback - not thrown to Objective-C", !context.exception);
659 }
660
661 @autoreleasepool {
662 JSContext *context = [[JSContext alloc] init];
663 context[@"callback"] = ^{
664 JSContext *context = [JSContext currentContext];
665 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
666 };
667 JSValue *result = [context evaluateScript:@"var result; try { callback(); } catch (e) { result = 'Caught exception'; }"];
668 checkResult(@"Implicit throw in callback - was caught by JavaScript", [result isEqualToObject:@"Caught exception"]);
669 checkResult(@"Implicit throw in callback - not thrown to Objective-C", !context.exception);
670 }
671
672 @autoreleasepool {
673 JSContext *context = [[JSContext alloc] init];
674 [context evaluateScript:
675 @"function sum(array) { \
676 var result = 0; \
677 for (var i in array) \
678 result += array[i]; \
679 return result; \
680 }"];
681 JSValue *array = [JSValue valueWithObject:@[@13, @2, @7] inContext:context];
682 JSValue *sumFunction = context[@"sum"];
683 JSValue *result = [sumFunction callWithArguments:@[ array ]];
684 checkResult(@"sum([13, 2, 7])", [result toInt32] == 22);
685 }
686
687 @autoreleasepool {
688 JSContext *context = [[JSContext alloc] init];
689 JSValue *mulAddFunction = [context evaluateScript:
690 @"(function(array, object) { \
691 var result = []; \
692 for (var i in array) \
693 result.push(array[i] * object.x + object.y); \
694 return result; \
695 })"];
696 JSValue *result = [mulAddFunction callWithArguments:@[ @[ @2, @4, @8 ], @{ @"x":@0.5, @"y":@42 } ]];
697 checkResult(@"mulAddFunction", [result isObject] && [[result toString] isEqual:@"43,44,46"]);
698 }
699
700 @autoreleasepool {
701 JSContext *context = [[JSContext alloc] init];
702 JSValue *array = [JSValue valueWithNewArrayInContext:context];
703 checkResult(@"arrayLengthEmpty", [[array[@"length"] toNumber] unsignedIntegerValue] == 0);
704 JSValue *value1 = [JSValue valueWithInt32:42 inContext:context];
705 JSValue *value2 = [JSValue valueWithInt32:24 inContext:context];
706 NSUInteger lowIndex = 5;
707 NSUInteger maxLength = UINT_MAX;
708
709 [array setValue:value1 atIndex:lowIndex];
710 checkResult(@"array.length after put to low index", [[array[@"length"] toNumber] unsignedIntegerValue] == (lowIndex + 1));
711
712 [array setValue:value1 atIndex:(maxLength - 1)];
713 checkResult(@"array.length after put to maxLength - 1", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength);
714
715 [array setValue:value2 atIndex:maxLength];
716 checkResult(@"array.length after put to maxLength", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength);
717
718 [array setValue:value2 atIndex:(maxLength + 1)];
719 checkResult(@"array.length after put to maxLength + 1", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength);
720
721 if (sizeof(NSUInteger) == 8)
722 checkResult(@"valueAtIndex:0 is undefined", [[array valueAtIndex:0] isUndefined]);
723 else
724 checkResult(@"valueAtIndex:0", [[array valueAtIndex:0] toInt32] == 24);
725 checkResult(@"valueAtIndex:lowIndex", [[array valueAtIndex:lowIndex] toInt32] == 42);
726 checkResult(@"valueAtIndex:maxLength - 1", [[array valueAtIndex:(maxLength - 1)] toInt32] == 42);
727 checkResult(@"valueAtIndex:maxLength", [[array valueAtIndex:maxLength] toInt32] == 24);
728 checkResult(@"valueAtIndex:maxLength + 1", [[array valueAtIndex:(maxLength + 1)] toInt32] == 24);
729 }
730
731 @autoreleasepool {
732 JSContext *context = [[JSContext alloc] init];
733 JSValue *object = [JSValue valueWithNewObjectInContext:context];
734
735 object[@"point"] = @{ @"x":@1, @"y":@2 };
736 object[@"point"][@"x"] = @3;
737 CGPoint point = [object[@"point"] toPoint];
738 checkResult(@"toPoint", point.x == 3 && point.y == 2);
739
740 object[@{ @"toString":^{ return @"foo"; } }] = @"bar";
741 checkResult(@"toString in object literal used as subscript", [[object[@"foo"] toString] isEqual:@"bar"]);
742
743 object[[@"foobar" substringToIndex:3]] = @"bar";
744 checkResult(@"substring used as subscript", [[object[@"foo"] toString] isEqual:@"bar"]);
745 }
746
747 @autoreleasepool {
748 JSContext *context = [[JSContext alloc] init];
749 TextXYZ *testXYZ = [[TextXYZ alloc] init];
750 context[@"testXYZ"] = testXYZ;
751 testXYZ.x = 3;
752 testXYZ.y = 4;
753 testXYZ.z = 5;
754 [context evaluateScript:@"testXYZ.x = 13; testXYZ.y = 14;"];
755 [context evaluateScript:@"testXYZ.test('test')"];
756 checkResult(@"TextXYZ - testXYZTested", testXYZTested);
757 JSValue *result = [context evaluateScript:@"testXYZ.x + ',' + testXYZ.y + ',' + testXYZ.z"];
758 checkResult(@"TextXYZ - result", [result isEqualToObject:@"13,4,undefined"]);
759 }
760
761 @autoreleasepool {
762 JSContext *context = [[JSContext alloc] init];
763 [context[@"Object"][@"prototype"] defineProperty:@"getterProperty" descriptor:@{
764 JSPropertyDescriptorGetKey:^{
765 return [JSContext currentThis][@"x"];
766 }
767 }];
768 JSValue *object = [JSValue valueWithObject:@{ @"x":@101 } inContext:context];
769 int result = [object [@"getterProperty"] toInt32];
770 checkResult(@"getterProperty", result == 101);
771 }
772
773 @autoreleasepool {
774 JSContext *context = [[JSContext alloc] init];
775 context[@"concatenate"] = ^{
776 NSArray *arguments = [JSContext currentArguments];
777 if (![arguments count])
778 return @"";
779 NSString *message = [arguments[0] description];
780 for (NSUInteger index = 1; index < [arguments count]; ++index)
781 message = [NSString stringWithFormat:@"%@ %@", message, arguments[index]];
782 return message;
783 };
784 JSValue *result = [context evaluateScript:@"concatenate('Hello,', 'World!')"];
785 checkResult(@"concatenate", [result isEqualToObject:@"Hello, World!"]);
786 }
787
788 @autoreleasepool {
789 JSContext *context = [[JSContext alloc] init];
790 context[@"foo"] = @YES;
791 checkResult(@"@YES is boolean", [context[@"foo"] isBoolean]);
792 JSValue *result = [context evaluateScript:@"typeof foo"];
793 checkResult(@"@YES is boolean", [result isEqualToObject:@"boolean"]);
794 }
795
796 @autoreleasepool {
797 JSContext *context = [[JSContext alloc] init];
798 JSValue *result = [context evaluateScript:@"String(console)"];
799 checkResult(@"String(console)", [result isEqualToObject:@"[object Console]"]);
800 result = [context evaluateScript:@"typeof console.log"];
801 checkResult(@"typeof console.log", [result isEqualToObject:@"function"]);
802 }
803
804 @autoreleasepool {
805 JSContext *context = [[JSContext alloc] init];
806 TestObject* testObject = [TestObject testObject];
807 context[@"testObject"] = testObject;
808 JSValue *result = [context evaluateScript:@"String(testObject)"];
809 checkResult(@"String(testObject)", [result isEqualToObject:@"[object TestObject]"]);
810 }
811
812 @autoreleasepool {
813 JSContext *context = [[JSContext alloc] init];
814 TestObject* testObject = [TestObject testObject];
815 context[@"testObject"] = testObject;
816 JSValue *result = [context evaluateScript:@"String(testObject.__proto__)"];
817 checkResult(@"String(testObject.__proto__)", [result isEqualToObject:@"[object TestObjectPrototype]"]);
818 }
819
820 @autoreleasepool {
821 JSContext *context = [[JSContext alloc] init];
822 context[@"TestObject"] = [TestObject class];
823 JSValue *result = [context evaluateScript:@"String(TestObject)"];
824 checkResult(@"String(TestObject)", [result isEqualToObject:@"function TestObject() {\n [native code]\n}"]);
825 }
826
827 @autoreleasepool {
828 JSContext *context = [[JSContext alloc] init];
829 JSValue* value = [JSValue valueWithObject:[TestObject class] inContext:context];
830 checkResult(@"[value toObject] == [TestObject class]", [value toObject] == [TestObject class]);
831 }
832
833 @autoreleasepool {
834 JSContext *context = [[JSContext alloc] init];
835 context[@"TestObject"] = [TestObject class];
836 JSValue *result = [context evaluateScript:@"TestObject.parentTest()"];
837 checkResult(@"TestObject.parentTest()", [result isEqualToObject:@"TestObject"]);
838 }
839
840 @autoreleasepool {
841 JSContext *context = [[JSContext alloc] init];
842 TestObject* testObject = [TestObject testObject];
843 context[@"testObjectA"] = testObject;
844 context[@"testObjectB"] = testObject;
845 JSValue *result = [context evaluateScript:@"testObjectA == testObjectB"];
846 checkResult(@"testObjectA == testObjectB", [result isBoolean] && [result toBool]);
847 }
848
849 @autoreleasepool {
850 JSContext *context = [[JSContext alloc] init];
851 TestObject* testObject = [TestObject testObject];
852 context[@"testObject"] = testObject;
853 testObject.point = (CGPoint){3,4};
854 JSValue *result = [context evaluateScript:@"var result = JSON.stringify(testObject.point); testObject.point = {x:12,y:14}; result"];
855 checkResult(@"testObject.point - result", [result isEqualToObject:@"{\"x\":3,\"y\":4}"]);
856 checkResult(@"testObject.point - {x:12,y:14}", testObject.point.x == 12 && testObject.point.y == 14);
857 }
858
859 @autoreleasepool {
860 JSContext *context = [[JSContext alloc] init];
861 TestObject* testObject = [TestObject testObject];
862 testObject.six = 6;
863 context[@"testObject"] = testObject;
864 context[@"mul"] = ^(int x, int y){ return x * y; };
865 JSValue *result = [context evaluateScript:@"mul(testObject.six, 7)"];
866 checkResult(@"mul(testObject.six, 7)", [result isNumber] && [result toInt32] == 42);
867 }
868
869 @autoreleasepool {
870 JSContext *context = [[JSContext alloc] init];
871 TestObject* testObject = [TestObject testObject];
872 context[@"testObject"] = testObject;
873 context[@"testObject"][@"variable"] = @4;
874 [context evaluateScript:@"++testObject.variable"];
875 checkResult(@"++testObject.variable", testObject.variable == 5);
876 }
877
878 @autoreleasepool {
879 JSContext *context = [[JSContext alloc] init];
880 context[@"point"] = @{ @"x":@6, @"y":@7 };
881 JSValue *result = [context evaluateScript:@"point.x + ',' + point.y"];
882 checkResult(@"point.x + ',' + point.y", [result isEqualToObject:@"6,7"]);
883 }
884
885 @autoreleasepool {
886 JSContext *context = [[JSContext alloc] init];
887 context[@"point"] = @{ @"x":@6, @"y":@7 };
888 JSValue *result = [context evaluateScript:@"point.x + ',' + point.y"];
889 checkResult(@"point.x + ',' + point.y", [result isEqualToObject:@"6,7"]);
890 }
891
892 @autoreleasepool {
893 JSContext *context = [[JSContext alloc] init];
894 TestObject* testObject = [TestObject testObject];
895 context[@"testObject"] = testObject;
896 JSValue *result = [context evaluateScript:@"testObject.getString()"];
897 checkResult(@"testObject.getString()", [result isString] && [result toInt32] == 42);
898 }
899
900 @autoreleasepool {
901 JSContext *context = [[JSContext alloc] init];
902 TestObject* testObject = [TestObject testObject];
903 context[@"testObject"] = testObject;
904 JSValue *result = [context evaluateScript:@"testObject.testArgumentTypes(101,0.5,true,'foo',666,[false,'bar',false],{x:'baz'})"];
905 checkResult(@"testObject.testArgumentTypes", [result isEqualToObject:@"101,0.5,1,foo,666,bar,baz"]);
906 }
907
908 @autoreleasepool {
909 JSContext *context = [[JSContext alloc] init];
910 TestObject* testObject = [TestObject testObject];
911 context[@"testObject"] = testObject;
912 JSValue *result = [context evaluateScript:@"testObject.getString.call(testObject)"];
913 checkResult(@"testObject.getString.call(testObject)", [result isString] && [result toInt32] == 42);
914 }
915
916 @autoreleasepool {
917 JSContext *context = [[JSContext alloc] init];
918 TestObject* testObject = [TestObject testObject];
919 context[@"testObject"] = testObject;
920 checkResult(@"testObject.getString.call({}) pre", !context.exception);
921 [context evaluateScript:@"testObject.getString.call({})"];
922 checkResult(@"testObject.getString.call({}) post", context.exception);
923 }
924
925 @autoreleasepool {
926 JSContext *context = [[JSContext alloc] init];
927 TestObject* testObject = [TestObject testObject];
928 context[@"testObject"] = testObject;
929 JSValue *result = [context evaluateScript:@"var result = 0; testObject.callback(function(x){ result = x; }); result"];
930 checkResult(@"testObject.callback", [result isNumber] && [result toInt32] == 42);
931 result = [context evaluateScript:@"testObject.bogusCallback"];
932 checkResult(@"testObject.bogusCallback == undefined", [result isUndefined]);
933 }
934
935 @autoreleasepool {
936 JSContext *context = [[JSContext alloc] init];
937 TestObject *testObject = [TestObject testObject];
938 context[@"testObject"] = testObject;
939 JSValue *result = [context evaluateScript:@"Function.prototype.toString.call(testObject.callback)"];
940 checkResult(@"Function.prototype.toString", !context.exception && ![result isUndefined]);
941 }
942
943 @autoreleasepool {
944 JSContext *context1 = [[JSContext alloc] init];
945 JSContext *context2 = [[JSContext alloc] initWithVirtualMachine:context1.virtualMachine];
946 JSValue *value = [JSValue valueWithDouble:42 inContext:context2];
947 context1[@"passValueBetweenContexts"] = value;
948 JSValue *result = [context1 evaluateScript:@"passValueBetweenContexts"];
949 checkResult(@"[value isEqualToObject:result]", [value isEqualToObject:result]);
950 }
951
952 @autoreleasepool {
953 JSContext *context = [[JSContext alloc] init];
954 context[@"handleTheDictionary"] = ^(NSDictionary *dict) {
955 NSDictionary *expectedDict = @{
956 @"foo" : [NSNumber numberWithInt:1],
957 @"bar" : @{
958 @"baz": [NSNumber numberWithInt:2]
959 }
960 };
961 checkResult(@"recursively convert nested dictionaries", [dict isEqualToDictionary:expectedDict]);
962 };
963 [context evaluateScript:@"var myDict = { \
964 'foo': 1, \
965 'bar': {'baz': 2} \
966 }; \
967 handleTheDictionary(myDict);"];
968
969 context[@"handleTheArray"] = ^(NSArray *array) {
970 NSArray *expectedArray = @[@"foo", @"bar", @[@"baz"]];
971 checkResult(@"recursively convert nested arrays", [array isEqualToArray:expectedArray]);
972 };
973 [context evaluateScript:@"var myArray = ['foo', 'bar', ['baz']]; handleTheArray(myArray);"];
974 }
975
976 @autoreleasepool {
977 JSContext *context = [[JSContext alloc] init];
978 TestObject *testObject = [TestObject testObject];
979 @autoreleasepool {
980 context[@"testObject"] = testObject;
981 [context evaluateScript:@"var constructor = Object.getPrototypeOf(testObject).constructor; constructor.prototype = undefined;"];
982 [context evaluateScript:@"testObject = undefined"];
983 }
984
985 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
986
987 @autoreleasepool {
988 context[@"testObject"] = testObject;
989 }
990 }
991
992 @autoreleasepool {
993 JSContext *context = [[JSContext alloc] init];
994 TextXYZ *testXYZ = [[TextXYZ alloc] init];
995
996 @autoreleasepool {
997 context[@"testXYZ"] = testXYZ;
998
999 [context evaluateScript:@" \
1000 didClick = false; \
1001 testXYZ.onclick = function() { \
1002 didClick = true; \
1003 }; \
1004 \
1005 testXYZ.weakOnclick = function() { \
1006 return 'foo'; \
1007 }; \
1008 "];
1009 }
1010
1011 @autoreleasepool {
1012 [testXYZ click];
1013 JSValue *result = [context evaluateScript:@"didClick"];
1014 checkResult(@"Event handler onclick", [result toBool]);
1015 }
1016
1017 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1018
1019 @autoreleasepool {
1020 JSValue *result = [context evaluateScript:@"testXYZ.onclick"];
1021 checkResult(@"onclick still around after GC", !([result isNull] || [result isUndefined]));
1022 }
1023
1024
1025 @autoreleasepool {
1026 JSValue *result = [context evaluateScript:@"testXYZ.weakOnclick"];
1027 checkResult(@"weakOnclick not around after GC", [result isNull] || [result isUndefined]);
1028 }
1029
1030 @autoreleasepool {
1031 [context evaluateScript:@" \
1032 didClick = false; \
1033 testXYZ = null; \
1034 "];
1035 }
1036
1037 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1038
1039 @autoreleasepool {
1040 [testXYZ click];
1041 JSValue *result = [context evaluateScript:@"didClick"];
1042 checkResult(@"Event handler onclick doesn't fire", ![result toBool]);
1043 }
1044 }
1045
1046 @autoreleasepool {
1047 JSVirtualMachine *vm = [[JSVirtualMachine alloc] init];
1048 TestObject *testObject = [TestObject testObject];
1049 JSManagedValue *weakValue;
1050 @autoreleasepool {
1051 JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm];
1052 context[@"testObject"] = testObject;
1053 weakValue = [[JSManagedValue alloc] initWithValue:context[@"testObject"]];
1054 }
1055
1056 @autoreleasepool {
1057 JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm];
1058 context[@"testObject"] = testObject;
1059 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1060 checkResult(@"weak value == nil", ![weakValue value]);
1061 checkResult(@"root is still alive", ![context[@"testObject"] isUndefined]);
1062 }
1063 }
1064
1065 @autoreleasepool {
1066 JSContext *context = [[JSContext alloc] init];
1067 TinyDOMNode *root = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
1068 TinyDOMNode *lastNode = root;
1069 for (NSUInteger i = 0; i < 3; i++) {
1070 TinyDOMNode *newNode = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
1071 [lastNode appendChild:newNode];
1072 lastNode = newNode;
1073 }
1074
1075 @autoreleasepool {
1076 context[@"root"] = root;
1077 context[@"getLastNodeInChain"] = ^(TinyDOMNode *head){
1078 TinyDOMNode *lastNode = nil;
1079 while (head) {
1080 lastNode = head;
1081 head = [lastNode childAtIndex:0];
1082 }
1083 return lastNode;
1084 };
1085 [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty = 42;"];
1086 }
1087
1088 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1089
1090 JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"];
1091 checkResult(@"My custom property == 42", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42);
1092 }
1093
1094 @autoreleasepool {
1095 JSContext *context = [[JSContext alloc] init];
1096 TinyDOMNode *root = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
1097 TinyDOMNode *lastNode = root;
1098 for (NSUInteger i = 0; i < 3; i++) {
1099 TinyDOMNode *newNode = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
1100 [lastNode appendChild:newNode];
1101 lastNode = newNode;
1102 }
1103
1104 @autoreleasepool {
1105 context[@"root"] = root;
1106 context[@"getLastNodeInChain"] = ^(TinyDOMNode *head){
1107 TinyDOMNode *lastNode = nil;
1108 while (head) {
1109 lastNode = head;
1110 head = [lastNode childAtIndex:0];
1111 }
1112 return lastNode;
1113 };
1114 [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty = 42;"];
1115
1116 [root appendChild:[root childAtIndex:0]];
1117 [root removeChildAtIndex:0];
1118 }
1119
1120 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1121
1122 JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"];
1123 checkResult(@"duplicate calls to addManagedReference don't cause things to die", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42);
1124 }
1125
1126 @autoreleasepool {
1127 JSContext *context = [[JSContext alloc] init];
1128 JSValue *o = [JSValue valueWithNewObjectInContext:context];
1129 o[@"foo"] = @"foo";
1130 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1131
1132 checkResult(@"JSValue correctly protected its internal value", [[o[@"foo"] toString] isEqualToString:@"foo"]);
1133 }
1134
1135 @autoreleasepool {
1136 JSContext *context = [[JSContext alloc] init];
1137 TestObject *testObject = [TestObject testObject];
1138 context[@"testObject"] = testObject;
1139 [context evaluateScript:@"testObject.__lookupGetter__('variable').call({})"];
1140 checkResult(@"Make sure we throw an exception when calling getter on incorrect |this|", context.exception);
1141 }
1142
1143 @autoreleasepool {
1144 TestObject *testObject = [TestObject testObject];
1145 JSManagedValue *managedTestObject;
1146 @autoreleasepool {
1147 JSContext *context = [[JSContext alloc] init];
1148 context[@"testObject"] = testObject;
1149 managedTestObject = [JSManagedValue managedValueWithValue:context[@"testObject"]];
1150 [context.virtualMachine addManagedReference:managedTestObject withOwner:testObject];
1151 }
1152 }
1153
1154 @autoreleasepool {
1155 JSContext *context = [[JSContext alloc] init];
1156 TestObject *testObject = [TestObject testObject];
1157 context[@"testObject"] = testObject;
1158 JSManagedValue *managedValue = nil;
1159 @autoreleasepool {
1160 JSValue *object = [JSValue valueWithNewObjectInContext:context];
1161 managedValue = [JSManagedValue managedValueWithValue:object andOwner:testObject];
1162 [context.virtualMachine addManagedReference:managedValue withOwner:testObject];
1163 }
1164 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1165 }
1166
1167 @autoreleasepool {
1168 JSContext *context = [[JSContext alloc] init];
1169 context[@"MyClass"] = ^{
1170 JSValue *newThis = [JSValue valueWithNewObjectInContext:[JSContext currentContext]];
1171 JSGlobalContextRef contextRef = [[JSContext currentContext] JSGlobalContextRef];
1172 JSObjectRef newThisRef = JSValueToObject(contextRef, [newThis JSValueRef], NULL);
1173 JSObjectSetPrototype(contextRef, newThisRef, [[JSContext currentContext][@"MyClass"][@"prototype"] JSValueRef]);
1174 return newThis;
1175 };
1176
1177 context[@"MyOtherClass"] = ^{
1178 JSValue *newThis = [JSValue valueWithNewObjectInContext:[JSContext currentContext]];
1179 JSGlobalContextRef contextRef = [[JSContext currentContext] JSGlobalContextRef];
1180 JSObjectRef newThisRef = JSValueToObject(contextRef, [newThis JSValueRef], NULL);
1181 JSObjectSetPrototype(contextRef, newThisRef, [[JSContext currentContext][@"MyOtherClass"][@"prototype"] JSValueRef]);
1182 return newThis;
1183 };
1184
1185 context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
1186 NSLog(@"EXCEPTION: %@", [exception toString]);
1187 context.exception = nil;
1188 };
1189
1190 JSValue *constructor1 = context[@"MyClass"];
1191 JSValue *constructor2 = context[@"MyOtherClass"];
1192
1193 JSValue *value1 = [context evaluateScript:@"new MyClass()"];
1194 checkResult(@"value1 instanceof MyClass", [value1 isInstanceOf:constructor1]);
1195 checkResult(@"!(value1 instanceof MyOtherClass)", ![value1 isInstanceOf:constructor2]);
1196 checkResult(@"MyClass.prototype.constructor === MyClass", [[context evaluateScript:@"MyClass.prototype.constructor === MyClass"] toBool]);
1197 checkResult(@"MyClass instanceof Function", [[context evaluateScript:@"MyClass instanceof Function"] toBool]);
1198
1199 JSValue *value2 = [context evaluateScript:@"new MyOtherClass()"];
1200 checkResult(@"value2 instanceof MyOtherClass", [value2 isInstanceOf:constructor2]);
1201 checkResult(@"!(value2 instanceof MyClass)", ![value2 isInstanceOf:constructor1]);
1202 checkResult(@"MyOtherClass.prototype.constructor === MyOtherClass", [[context evaluateScript:@"MyOtherClass.prototype.constructor === MyOtherClass"] toBool]);
1203 checkResult(@"MyOtherClass instanceof Function", [[context evaluateScript:@"MyOtherClass instanceof Function"] toBool]);
1204 }
1205
1206 @autoreleasepool {
1207 JSContext *context = [[JSContext alloc] init];
1208 context[@"MyClass"] = ^{
1209 NSLog(@"I'm intentionally not returning anything.");
1210 };
1211 JSValue *result = [context evaluateScript:@"new MyClass()"];
1212 checkResult(@"result === undefined", [result isUndefined]);
1213 checkResult(@"exception.message is correct'", context.exception
1214 && [@"Objective-C blocks called as constructors must return an object." isEqualToString:[context.exception[@"message"] toString]]);
1215 }
1216
1217 @autoreleasepool {
1218 checkResult(@"[JSContext currentThis] == nil outside of callback", ![JSContext currentThis]);
1219 checkResult(@"[JSContext currentArguments] == nil outside of callback", ![JSContext currentArguments]);
1220 if ([JSContext currentCallee])
1221 checkResult(@"[JSContext currentCallee] == nil outside of callback", ![JSContext currentCallee]);
1222 }
1223
1224 if ([JSContext currentCallee]) {
1225 @autoreleasepool {
1226 JSContext *context = [[JSContext alloc] init];
1227 context[@"testFunction"] = ^{
1228 checkResult(@"testFunction.foo === 42", [[JSContext currentCallee][@"foo"] toInt32] == 42);
1229 };
1230 context[@"testFunction"][@"foo"] = @42;
1231 [context[@"testFunction"] callWithArguments:nil];
1232
1233 context[@"TestConstructor"] = ^{
1234 JSValue *newThis = [JSValue valueWithNewObjectInContext:[JSContext currentContext]];
1235 JSGlobalContextRef contextRef = [[JSContext currentContext] JSGlobalContextRef];
1236 JSObjectRef newThisRef = JSValueToObject(contextRef, [newThis JSValueRef], NULL);
1237 JSObjectSetPrototype(contextRef, newThisRef, [[JSContext currentCallee][@"prototype"] JSValueRef]);
1238 return newThis;
1239 };
1240 checkResult(@"(new TestConstructor) instanceof TestConstructor", [context evaluateScript:@"(new TestConstructor) instanceof TestConstructor"]);
1241 }
1242 }
1243
1244 @autoreleasepool {
1245 JSContext *context = [[JSContext alloc] init];
1246 context[@"TestObject"] = [TestObject class];
1247 JSValue *testObject = [context evaluateScript:@"(new TestObject())"];
1248 checkResult(@"testObject instanceof TestObject", [testObject isInstanceOf:context[@"TestObject"]]);
1249
1250 context[@"TextXYZ"] = [TextXYZ class];
1251 JSValue *textObject = [context evaluateScript:@"(new TextXYZ(\"Called TextXYZ constructor!\"))"];
1252 checkResult(@"textObject instanceof TextXYZ", [textObject isInstanceOf:context[@"TextXYZ"]]);
1253 }
1254
1255 @autoreleasepool {
1256 JSContext *context = [[JSContext alloc] init];
1257 context[@"ClassA"] = [ClassA class];
1258 context[@"ClassB"] = [ClassB class];
1259 context[@"ClassC"] = [ClassC class]; // Should print error message about too many inits found.
1260 context[@"ClassCPrime"] = [ClassCPrime class]; // Ditto.
1261
1262 JSValue *a = [context evaluateScript:@"(new ClassA(42))"];
1263 checkResult(@"a instanceof ClassA", [a isInstanceOf:context[@"ClassA"]]);
1264 checkResult(@"a.initialize() is callable", [[a invokeMethod:@"initialize" withArguments:@[]] toInt32] == 42);
1265
1266 JSValue *b = [context evaluateScript:@"(new ClassB(42, 53))"];
1267 checkResult(@"b instanceof ClassB", [b isInstanceOf:context[@"ClassB"]]);
1268
1269 JSValue *canConstructClassC = [context evaluateScript:@"(function() { \
1270 try { \
1271 (new ClassC(1, 2)); \
1272 return true; \
1273 } catch(e) { \
1274 return false; \
1275 } \
1276 })()"];
1277 checkResult(@"shouldn't be able to construct ClassC", ![canConstructClassC toBool]);
1278 JSValue *canConstructClassCPrime = [context evaluateScript:@"(function() { \
1279 try { \
1280 (new ClassCPrime(1)); \
1281 return true; \
1282 } catch(e) { \
1283 return false; \
1284 } \
1285 })()"];
1286 checkResult(@"shouldn't be able to construct ClassCPrime", ![canConstructClassCPrime toBool]);
1287 }
1288
1289 @autoreleasepool {
1290 JSContext *context = [[JSContext alloc] init];
1291 context[@"ClassD"] = [ClassD class];
1292 context[@"ClassE"] = [ClassE class];
1293
1294 JSValue *d = [context evaluateScript:@"(new ClassD())"];
1295 checkResult(@"Returning instance of ClassE from ClassD's init has correct class", [d isInstanceOf:context[@"ClassE"]]);
1296 }
1297
1298 @autoreleasepool {
1299 JSContext *context = [[JSContext alloc] init];
1300 while (!evilAllocationObjectWasDealloced) {
1301 @autoreleasepool {
1302 EvilAllocationObject *evilObject = [[EvilAllocationObject alloc] initWithContext:context];
1303 context[@"evilObject"] = evilObject;
1304 context[@"evilObject"] = nil;
1305 }
1306 }
1307 checkResult(@"EvilAllocationObject was successfully dealloced without crashing", evilAllocationObjectWasDealloced);
1308 }
1309
1310 @autoreleasepool {
1311 JSContext *context = [[JSContext alloc] init];
1312 checkResult(@"default context.name is nil", context.name == nil);
1313 NSString *name1 = @"Name1";
1314 NSString *name2 = @"Name2";
1315 context.name = name1;
1316 NSString *fetchedName1 = context.name;
1317 context.name = name2;
1318 NSString *fetchedName2 = context.name;
1319 context.name = nil;
1320 NSString *fetchedName3 = context.name;
1321 checkResult(@"fetched context.name was expected", [fetchedName1 isEqualToString:name1]);
1322 checkResult(@"fetched context.name was expected", [fetchedName2 isEqualToString:name2]);
1323 checkResult(@"fetched context.name was expected", ![fetchedName1 isEqualToString:fetchedName2]);
1324 checkResult(@"fetched context.name was expected", fetchedName3 == nil);
1325 }
1326
1327 @autoreleasepool {
1328 JSContext *context = [[JSContext alloc] init];
1329 context[@"UnexportedObject"] = [UnexportedObject class];
1330 context[@"makeObject"] = ^{
1331 return [[UnexportedObject alloc] init];
1332 };
1333 JSValue *result = [context evaluateScript:@"(makeObject() instanceof UnexportedObject)"];
1334 checkResult(@"makeObject() instanceof UnexportedObject", [result isBoolean] && [result toBool]);
1335 }
1336
1337 @autoreleasepool {
1338 JSContext *context = [[JSContext alloc] init];
1339 [[JSValue valueWithInt32:42 inContext:context] toDictionary];
1340 [[JSValue valueWithInt32:42 inContext:context] toArray];
1341 }
1342
1343 @autoreleasepool {
1344 JSContext *context = [[JSContext alloc] init];
1345
1346 // Create the root, make it reachable from JS, and force an EdenCollection
1347 // so that we scan the external object graph.
1348 TestObject *root = [TestObject testObject];
1349 @autoreleasepool {
1350 context[@"root"] = root;
1351 }
1352 JSSynchronousEdenCollectForDebugging([context JSGlobalContextRef]);
1353
1354 // Create a new Obj-C object only reachable via the external object graph
1355 // through the object we already scanned during the EdenCollection.
1356 TestObject *child = [TestObject testObject];
1357 [context.virtualMachine addManagedReference:child withOwner:root];
1358
1359 // Create a new managed JSValue that will only be kept alive if we properly rescan
1360 // the external object graph.
1361 JSManagedValue *managedJSObject = nil;
1362 @autoreleasepool {
1363 JSValue *jsObject = [JSValue valueWithObject:@"hello" inContext:context];
1364 managedJSObject = [JSManagedValue managedValueWithValue:jsObject];
1365 [context.virtualMachine addManagedReference:managedJSObject withOwner:child];
1366 }
1367
1368 // Force another EdenCollection. It should rescan the new part of the external object graph.
1369 JSSynchronousEdenCollectForDebugging([context JSGlobalContextRef]);
1370
1371 // Check that the managed JSValue is still alive.
1372 checkResult(@"EdenCollection doesn't reclaim new managed values", [managedJSObject value] != nil);
1373 }
1374
1375 @autoreleasepool {
1376 JSContext *context = [[JSContext alloc] init];
1377
1378 pthread_t threadID;
1379 pthread_create(&threadID, NULL, &threadMain, (__bridge void*)context);
1380 pthread_join(threadID, nullptr);
1381 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1382
1383 checkResult(@"Did not crash after entering the VM from another thread", true);
1384 }
1385
1386 currentThisInsideBlockGetterTest();
1387 runDateTests();
1388 runJSExportTests();
1389 runRegress141809();
1390}
1391
1392#else
1393
1394void testObjectiveCAPI()
1395{
1396}
1397
1398#endif // JSC_OBJC_API_ENABLED