1/* 2 * Copyright (C) 2014 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. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "JSExportTests.h" 27 28#import <objc/runtime.h> 29#import <objc/objc.h> 30 31#if JSC_OBJC_API_ENABLED 32 33extern "C" void checkResult(NSString *description, bool passed); 34 35@interface JSExportTests : NSObject 36+ (void) exportInstanceMethodWithIdProtocolTest; 37+ (void) exportInstanceMethodWithClassProtocolTest; 38+ (void) exportDynamicallyGeneratedProtocolTest; 39@end 40 41@protocol TruthTeller 42- (BOOL) returnTrue; 43@end 44 45@interface TruthTeller : NSObject<TruthTeller> 46@end 47 48@implementation TruthTeller 49- (BOOL) returnTrue 50{ 51 return true; 52} 53@end 54 55@protocol ExportMethodWithIdProtocol <JSExport> 56- (void) methodWithIdProtocol:(id<TruthTeller>)object; 57@end 58 59@interface ExportMethodWithIdProtocol : NSObject<ExportMethodWithIdProtocol> 60@end 61 62@implementation ExportMethodWithIdProtocol 63- (void) methodWithIdProtocol:(id<TruthTeller>)object 64{ 65 checkResult(@"Exporting a method with id<protocol> in the type signature", [object returnTrue]); 66} 67@end 68 69@protocol ExportMethodWithClassProtocol <JSExport> 70- (void) methodWithClassProtocol:(NSObject<TruthTeller> *)object; 71@end 72 73@interface ExportMethodWithClassProtocol : NSObject<ExportMethodWithClassProtocol> 74@end 75 76@implementation ExportMethodWithClassProtocol 77- (void) methodWithClassProtocol:(NSObject<TruthTeller> *)object 78{ 79 checkResult(@"Exporting a method with class<protocol> in the type signature", [object returnTrue]); 80} 81@end 82 83@implementation JSExportTests 84+ (void) exportInstanceMethodWithIdProtocolTest 85{ 86 JSContext *context = [[JSContext alloc] init]; 87 context[@"ExportMethodWithIdProtocol"] = [ExportMethodWithIdProtocol class]; 88 context[@"makeTestObject"] = ^{ 89 return [[ExportMethodWithIdProtocol alloc] init]; 90 }; 91 context[@"opaqueObject"] = [[TruthTeller alloc] init]; 92 [context evaluateScript:@"makeTestObject().methodWithIdProtocol(opaqueObject);"]; 93 checkResult(@"Successfully exported instance method", !context.exception); 94} 95 96+ (void) exportInstanceMethodWithClassProtocolTest 97{ 98 JSContext *context = [[JSContext alloc] init]; 99 context[@"ExportMethodWithClassProtocol"] = [ExportMethodWithClassProtocol class]; 100 context[@"makeTestObject"] = ^{ 101 return [[ExportMethodWithClassProtocol alloc] init]; 102 }; 103 context[@"opaqueObject"] = [[TruthTeller alloc] init]; 104 [context evaluateScript:@"makeTestObject().methodWithClassProtocol(opaqueObject);"]; 105 checkResult(@"Successfully exported instance method", !context.exception); 106} 107 108+ (void) exportDynamicallyGeneratedProtocolTest 109{ 110 JSContext *context = [[JSContext alloc] init]; 111 Protocol *dynProtocol = objc_allocateProtocol("NSStringJSExport"); 112 Protocol *jsExportProtocol = @protocol(JSExport); 113 protocol_addProtocol(dynProtocol, jsExportProtocol); 114 Method method = class_getInstanceMethod([NSString class], @selector(boolValue)); 115 protocol_addMethodDescription(dynProtocol, @selector(boolValue), method_getTypeEncoding(method), YES, YES); 116 NSLog(@"type encoding = %s", method_getTypeEncoding(method)); 117 protocol_addMethodDescription(dynProtocol, @selector(boolValue), "B@:", YES, YES); 118 objc_registerProtocol(dynProtocol); 119 class_addProtocol([NSString class], dynProtocol); 120 121 context[@"NSString"] = [NSString class]; 122 context[@"myString"] = @"YES"; 123 JSValue *value = [context evaluateScript:@"myString.boolValue()"]; 124 checkResult(@"Dynamically generated JSExport-ed protocols are ignored", [value isUndefined] && !!context.exception); 125} 126@end 127 128void runJSExportTests() 129{ 130 @autoreleasepool { 131 [JSExportTests exportInstanceMethodWithIdProtocolTest]; 132 [JSExportTests exportInstanceMethodWithClassProtocolTest]; 133 [JSExportTests exportDynamicallyGeneratedProtocolTest]; 134 } 135} 136 137#endif // JSC_OBJC_API_ENABLED 138