2015-06-06 20:37:36 +00:00
// Copyright 2004 - present Facebook . All Rights Reserved .
# import < mach / mach_time . h >
# import < XCTest / XCTest . h >
# import "RCTContextExecutor.h"
# import "RCTUtils.h"
@ interface RCTContextExecutorTests : XCTestCase
@ end
@ implementation RCTContextExecutorTests
2015-06-09 22:42:10 +00:00
{
RCTContextExecutor * _executor ;
}
- ( void ) setUp
{
[ super setUp ] ;
_executor = [ [ RCTContextExecutor alloc ] init ] ;
RCTSetExecutorID ( _executor ) ;
[ _executor setUp ] ;
}
2015-06-06 20:37:36 +00:00
- ( void ) testNativeLoggingHookExceptionBehavior
{
dispatch_semaphore _t doneSem = dispatch_semaphore _create ( 0 ) ;
2015-06-09 22:42:10 +00:00
[ _executor executeApplicationScript : @ "var x = {toString: function() { throw 1; }}; nativeLoggingHook(x);"
2015-06-06 20:37:36 +00:00
sourceURL : [ NSURL URLWithString : @ "file://" ]
onComplete : ^ ( id error ) {
dispatch_semaphore _signal ( doneSem ) ;
} ] ;
dispatch_semaphore _wait ( doneSem , DISPATCH_TIME _FOREVER ) ;
2015-06-09 22:42:10 +00:00
[ _executor invalidate ] ;
2015-06-06 20:37:36 +00:00
}
static uint64_t _get _time _nanoseconds ( void )
{
static struct mach_timebase _info tb_info = { 0 } ;
static dispatch_once _t onceToken ;
dispatch_once ( & onceToken , ^ {
int ret = mach_timebase _info ( & tb_info ) ;
assert ( 0 = = ret ) ;
} ) ;
return ( mach_absolute _time ( ) * tb_info . numer ) / tb_info . denom ;
}
- ( void ) testDeserializationPerf
{
// This test case checks the assumption that deserializing objects from JavaScript
// values one - by - one via ObjC JSC API is slower than using JSON string
// You might want to switch your tests schema to "Release" build configuration
JSContextGroupRef group = JSContextGroupCreate ( ) ;
JSGlobalContextRef context = JSGlobalContextCreateInGroup ( group , NULL ) ;
2015-06-12 18:05:01 +00:00
id message = @ [ @ [ @ 1 , @ 2 , @ 3 , @ 4 ] , @ [ @ { @ "a" : @ 1 } , @ { @ "b" : @ 2 } ] , ( id ) kCFNull ] ;
2015-06-06 20:37:36 +00:00
NSString * code = RCTJSONStringify ( message , NULL ) ;
JSStringRef script = JSStringCreateWithCFString ( ( __bridge CFStringRef ) code ) ;
JSValueRef error = NULL ;
JSValueRef value = JSEvaluateScript ( context , script , NULL , NULL , 0 , & error ) ;
XCTAssertTrue ( error = = NULL ) ;
id obj ;
uint64_t start = _get _time _nanoseconds ( ) ;
for ( int i = 0 ; i < 10000 ; i + + ) {
JSStringRef jsonJSString = JSValueCreateJSONString ( context , value , 0 , nil ) ;
NSString * jsonString = ( __bridge NSString * ) JSStringCopyCFString ( kCFAllocatorDefault , jsonJSString ) ;
JSStringRelease ( jsonJSString ) ;
obj = RCTJSONParse ( jsonString , NULL ) ;
}
NSLog ( @ "JSON Parse time: %.2fms" , ( _get _time _nanoseconds ( ) - start ) / 1000000.0 ) ;
JSStringRelease ( script ) ;
JSGlobalContextRelease ( context ) ;
JSContextGroupRelease ( group ) ;
}
- ( void ) MANUALLY_testJavaScriptCallSpeed
{
/ * *
* Since we almost don ' t change the RCTContextExecutor logic , and this test is
* very likely to become flaky ( specially accross different devices ) leave it
* to be run manually
*
* Previous Values : If you change the executor code , you should update this values
* /
int const runs = 4 e5 ;
int const frequency = 10 ;
double const threshold = 0.1 ;
static double const expectedTimes [ ] = {
0 x1 .6199943826 cf1p + 13 ,
0 x1 . a3bc0a81551c3p + 13 ,
0 x1 . d49fbb8602fe3p + 13 ,
0 x1 . d1f64085ecb7bp + 13 ,
} ;
dispatch_semaphore _t semaphore = dispatch_semaphore _create ( 0 ) ;
NSString * script = @ " \
var modules = { \
module : { \
method : function ( ) { \
return true ; \
} \
} \
} ; \
function require ( module ) { \
return modules [ module ] ; \
} \
" ;
2015-06-09 22:42:10 +00:00
[ _executor executeApplicationScript : script sourceURL : [ NSURL URLWithString : @ "http://localhost:8081/" ] onComplete : ^ ( NSError * error ) {
2015-06-06 20:37:36 +00:00
NSMutableArray * params = [ [ NSMutableArray alloc ] init ] ;
id data = @ 1 ;
for ( int i = 0 ; i < 4 ; i + + ) {
double samples [ runs / frequency ] ;
int size = runs / frequency ;
double total = 0 ;
for ( int j = 0 ; j < runs ; j + + ) {
@ autoreleasepool {
double start = _get _time _nanoseconds ( ) ;
2015-06-09 22:42:10 +00:00
[ _executor executeJSCall : @ "module"
2015-06-06 20:37:36 +00:00
method : @ "method"
arguments : params
2015-06-09 22:42:10 +00:00
context : RCTGetExecutorID ( _executor )
2015-06-06 20:37:36 +00:00
callback : ^ ( id json , NSError * __error ) {
RCTAssert ( [ json isEqual : @ YES ] , @ "Invalid return" ) ;
} ] ;
double run = _get _time _nanoseconds ( ) - start ;
if ( ( j % frequency ) = = frequency - 1 ) { // Warmup
total + = run ;
samples [ j / frequency ] = run ;
}
}
}
double mean = total / size ;
double variance = 0 ;
for ( int j = 0 ; j < size ; j + + ) {
variance + = pow ( samples [ j ] - mean , 2 ) ;
}
variance / = size ;
double standardDeviation = sqrt ( variance ) ;
double marginOfError = standardDeviation * 1.645 ;
double lower = mean - marginOfError ;
double upper = mean + marginOfError ;
int s = 0 ;
total = 0 ;
for ( int j = 0 ; j < size ; j + + ) {
double v = samples [ j ] ;
if ( v >= lower && v <= upper ) {
samples [ s + + ] = v ;
total + = v ;
}
}
mean = total / s ;
lower = mean * ( 1.0 - threshold ) ;
upper = mean * ( 1.0 + threshold ) ;
double expected = expectedTimes [ i ] ;
NSLog ( @ "Previous: %lf, New: %f -> %a" , expected , mean , mean ) ;
if ( upper < expected ) {
NSLog ( @ "You made JS calls with %d argument(s) %.2lf%% faster :) - Remember to update the tests with the new value: %a" ,
i , ( 1 - ( double ) mean / expected ) * 100 , mean ) ;
}
XCTAssertTrue ( lower < expected , @ "You made JS calls with %d argument(s) %.2lf%% slower :( - If that's *really* necessary, update the tests with the new value: %a" ,
i , ( ( double ) mean / expected - 1 ) * 100 , mean ) ;
[ params addObject : data ] ;
}
dispatch_semaphore _signal ( semaphore ) ;
} ] ;
while ( dispatch_semaphore _wait ( semaphore , DISPATCH_TIME _NOW ) ) {
[ [ NSRunLoop currentRunLoop ] runMode : NSDefaultRunLoopMode
beforeDate : [ NSDate dateWithTimeIntervalSinceNow : 10 ] ] ;
}
}
@ end