From 55a07c99dc3f337ed3857b619ff201978bb90bda Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 2 Oct 2015 14:57:54 -0700 Subject: [PATCH 01/32] react test app --- tests/ArrayTests.js | 8 + tests/ObjectTests.js | 8 + tests/ReactTests/.flowconfig | 46 ++ tests/ReactTests/.gitignore | 28 + tests/ReactTests/.watchmanconfig | 1 + tests/ReactTests/android/app/build.gradle | 29 + .../ReactTests/android/app/proguard-rules.pro | 17 + .../android/app/src/main/AndroidManifest.xml | 22 + .../java/com/reacttests/MainActivity.java | 69 ++ .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3418 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2206 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4842 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7718 bytes .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 8 + tests/ReactTests/android/build.gradle | 20 + tests/ReactTests/android/gradle.properties | 20 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 52266 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + tests/ReactTests/android/gradlew | 164 ++++ tests/ReactTests/android/gradlew.bat | 90 +++ tests/ReactTests/android/settings.gradle | 3 + tests/ReactTests/index.android.js | 52 ++ tests/ReactTests/index.ios.js | 56 ++ .../ios/ReactTests.xcodeproj/project.pbxproj | 745 ++++++++++++++++++ .../xcschemes/ReactTests.xcscheme | 112 +++ tests/ReactTests/ios/ReactTests/AppDelegate.h | 16 + tests/ReactTests/ios/ReactTests/AppDelegate.m | 61 ++ .../ReactTests/Base.lproj/LaunchScreen.xib | 42 + .../AppIcon.appiconset/Contents.json | 38 + tests/ReactTests/ios/ReactTests/Info.plist | 48 ++ tests/ReactTests/ios/ReactTests/main.m | 18 + .../ReactTests/ios/ReactTestsTests/Info.plist | 24 + .../ios/ReactTestsTests/ReactTestsTests.m | 70 ++ tests/ReactTests/ios/main.jsbundle | 8 + tests/ReactTests/package.json | 13 + tests/RealmTests.js | 11 + tests/ResultsTests.js | 7 + tests/TestCase.js | 4 + tests/TestObjects.js | 7 + tests/index.js | 11 + tests/package.json | 5 + 42 files changed, 1889 insertions(+) create mode 100644 tests/ReactTests/.flowconfig create mode 100644 tests/ReactTests/.gitignore create mode 100644 tests/ReactTests/.watchmanconfig create mode 100644 tests/ReactTests/android/app/build.gradle create mode 100644 tests/ReactTests/android/app/proguard-rules.pro create mode 100644 tests/ReactTests/android/app/src/main/AndroidManifest.xml create mode 100644 tests/ReactTests/android/app/src/main/java/com/reacttests/MainActivity.java create mode 100644 tests/ReactTests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 tests/ReactTests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 tests/ReactTests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 tests/ReactTests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 tests/ReactTests/android/app/src/main/res/values/strings.xml create mode 100644 tests/ReactTests/android/app/src/main/res/values/styles.xml create mode 100644 tests/ReactTests/android/build.gradle create mode 100644 tests/ReactTests/android/gradle.properties create mode 100644 tests/ReactTests/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 tests/ReactTests/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 tests/ReactTests/android/gradlew create mode 100644 tests/ReactTests/android/gradlew.bat create mode 100644 tests/ReactTests/android/settings.gradle create mode 100644 tests/ReactTests/index.android.js create mode 100644 tests/ReactTests/index.ios.js create mode 100644 tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj create mode 100644 tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme create mode 100644 tests/ReactTests/ios/ReactTests/AppDelegate.h create mode 100644 tests/ReactTests/ios/ReactTests/AppDelegate.m create mode 100644 tests/ReactTests/ios/ReactTests/Base.lproj/LaunchScreen.xib create mode 100644 tests/ReactTests/ios/ReactTests/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 tests/ReactTests/ios/ReactTests/Info.plist create mode 100644 tests/ReactTests/ios/ReactTests/main.m create mode 100644 tests/ReactTests/ios/ReactTestsTests/Info.plist create mode 100644 tests/ReactTests/ios/ReactTestsTests/ReactTestsTests.m create mode 100644 tests/ReactTests/ios/main.jsbundle create mode 100644 tests/ReactTests/package.json create mode 100644 tests/index.js create mode 100644 tests/package.json diff --git a/tests/ArrayTests.js b/tests/ArrayTests.js index c07a3d7dc9..7772853307 100644 --- a/tests/ArrayTests.js +++ b/tests/ArrayTests.js @@ -18,6 +18,12 @@ 'use strict'; +var TestCase = require('./TestCase'); +var { + LinkTypesObjectSchema, + TestObjectSchema, +} = require('./TestObjects'); + var ArrayTests = { testLinkTypesPropertySetters: function() { var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); @@ -250,3 +256,5 @@ var ArrayTests = { }); }, }; +exports.ArrayTests = ArrayTests; + diff --git a/tests/ObjectTests.js b/tests/ObjectTests.js index 4e847ab3ed..d898f076f1 100644 --- a/tests/ObjectTests.js +++ b/tests/ObjectTests.js @@ -18,6 +18,13 @@ 'use strict'; +var TestCase = require('./TestCase'); +var { + LinkTypesObjectSchema, + TestObjectSchema, + BasicTypesObjectSchema, +} = require('./TestObjects'); + var ObjectTests = { testBasicTypesPropertyGetters: function() { var basicTypesValues = [true, 1, 1.1, 1.11, 'string', new Date(1), 'DATA']; @@ -122,3 +129,4 @@ var ObjectTests = { TestCase.assertEqual(obj.arrayCol[2].doubleCol, 2); }, }; +exports.ObjectTests = ObjectTests; diff --git a/tests/ReactTests/.flowconfig b/tests/ReactTests/.flowconfig new file mode 100644 index 0000000000..438e495d48 --- /dev/null +++ b/tests/ReactTests/.flowconfig @@ -0,0 +1,46 @@ +[ignore] + +# We fork some components by platform. +.*/*.web.js +.*/*.android.js + +# Some modules have their own node_modules with overlap +.*/node_modules/node-haste/.* + +# Ignore react-tools where there are overlaps, but don't ignore anything that +# react-native relies on +.*/node_modules/react-tools/src/React.js +.*/node_modules/react-tools/src/renderers/shared/event/EventPropagators.js +.*/node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js +.*/node_modules/react-tools/src/shared/vendor/core/ExecutionEnvironment.js + + +# Ignore commoner tests +.*/node_modules/commoner/test/.* + +# See https://github.com/facebook/flow/issues/442 +.*/react-tools/node_modules/commoner/lib/reader.js + +# Ignore jest +.*/react-native/node_modules/jest-cli/.* + +[include] + +[libs] +node_modules/react-native/Libraries/react-native/react-native-interface.js + +[options] +module.system=haste + +munge_underscores=true + +suppress_type=$FlowIssue +suppress_type=$FlowFixMe +suppress_type=$FixMe + +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-4]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-4]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy + +[version] +0.14.0 diff --git a/tests/ReactTests/.gitignore b/tests/ReactTests/.gitignore new file mode 100644 index 0000000000..b927355df4 --- /dev/null +++ b/tests/ReactTests/.gitignore @@ -0,0 +1,28 @@ +# OSX +# +.DS_Store + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# node.js +# +node_modules/ +npm-debug.log diff --git a/tests/ReactTests/.watchmanconfig b/tests/ReactTests/.watchmanconfig new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/tests/ReactTests/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/tests/ReactTests/android/app/build.gradle b/tests/ReactTests/android/app/build.gradle new file mode 100644 index 0000000000..eb2d457b52 --- /dev/null +++ b/tests/ReactTests/android/app/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.1" + + defaultConfig { + applicationId "com.reacttests" + minSdkVersion 16 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + ndk { + abiFilters "armeabi-v7a", "x86" + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:23.0.0' + compile 'com.facebook.react:react-native:0.11.+' +} diff --git a/tests/ReactTests/android/app/proguard-rules.pro b/tests/ReactTests/android/app/proguard-rules.pro new file mode 100644 index 0000000000..a92fa177ee --- /dev/null +++ b/tests/ReactTests/android/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/tests/ReactTests/android/app/src/main/AndroidManifest.xml b/tests/ReactTests/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..6e884d8314 --- /dev/null +++ b/tests/ReactTests/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + diff --git a/tests/ReactTests/android/app/src/main/java/com/reacttests/MainActivity.java b/tests/ReactTests/android/app/src/main/java/com/reacttests/MainActivity.java new file mode 100644 index 0000000000..562cd0e38f --- /dev/null +++ b/tests/ReactTests/android/app/src/main/java/com/reacttests/MainActivity.java @@ -0,0 +1,69 @@ +package com.reacttests; + +import android.app.Activity; +import android.os.Bundle; +import android.view.KeyEvent; + +import com.facebook.react.LifecycleState; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.ReactRootView; +import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; +import com.facebook.react.shell.MainReactPackage; +import com.facebook.soloader.SoLoader; + +public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { + + private ReactInstanceManager mReactInstanceManager; + private ReactRootView mReactRootView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mReactRootView = new ReactRootView(this); + + mReactInstanceManager = ReactInstanceManager.builder() + .setApplication(getApplication()) + .setBundleAssetName("index.android.bundle") + .setJSMainModuleName("index.android") + .addPackage(new MainReactPackage()) + .setUseDeveloperSupport(BuildConfig.DEBUG) + .setInitialLifecycleState(LifecycleState.RESUMED) + .build(); + + mReactRootView.startReactApplication(mReactInstanceManager, "ReactTests", null); + + setContentView(mReactRootView); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { + mReactInstanceManager.showDevOptionsDialog(); + return true; + } + return super.onKeyUp(keyCode, event); + } + + @Override + public void invokeDefaultOnBackPressed() { + super.onBackPressed(); + } + + @Override + protected void onPause() { + super.onPause(); + + if (mReactInstanceManager != null) { + mReactInstanceManager.onPause(); + } + } + + @Override + protected void onResume() { + super.onResume(); + + if (mReactInstanceManager != null) { + mReactInstanceManager.onResume(this); + } + } +} diff --git a/tests/ReactTests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/tests/ReactTests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..cde69bcccec65160d92116f20ffce4fce0b5245c GIT binary patch literal 3418 zcmZ{nX*|@A^T0p5j$I+^%FVhdvMbgt%d+mG98ubwNv_tpITppba^GiieBBZGI>I89 zGgm8TA>_)DlEu&W;s3#ZUNiH4&CF{a%siTjzG;eOzQB6{003qKeT?}z_5U*{{kgZ; zdV@U&tqa-&4FGisjMN8o=P}$t-`oTM2oeB5d9mHPgTYJx4jup)+5a;Tke$m708DocFzDL>U$$}s6FGiy_I1?O zHXq`q884|^O4Q*%V#vwxqCz-#8i`Gu)2LeB0{%%VKunOF%9~JcFB9MM>N00M`E~;o zBU%)O5u-D6NF~OQV7TV#JAN;=Lylgxy0kncoQpGq<<_gxw`FC=C-cV#$L|(47Hatl ztq3Jngq00x#}HGW@_tj{&A?lwOwrVX4@d66vLVyj1H@i}VD2YXd)n03?U5?cKtFz4 zW#@+MLeDVP>fY0F2IzT;r5*MAJ2}P8Z{g3utX0<+ZdAC)Tvm-4uN!I7|BTw&G%RQn zR+A5VFx(}r<1q9^N40XzP=Jp?i=jlS7}T~tB4CsWx!XbiHSm zLu}yar%t>-3jlutK=wdZhES->*1X({YI;DN?6R=C*{1U6%wG`0>^?u}h0hhqns|SeTmV=s;Gxx5F9DtK>{>{f-`SpJ`dO26Ujk?^%ucsuCPe zIUk1(@I3D^7{@jmXO2@<84|}`tDjB}?S#k$ik;jC))BH8>8mQWmZ zF#V|$gW|Xc_wmmkoI-b5;4AWxkA>>0t4&&-eC-J_iP(tLT~c6*(ZnSFlhw%}0IbiJ ztgnrZwP{RBd(6Ds`dM~k;rNFgkbU&Yo$KR#q&%Kno^YXF5ONJwGwZ*wEr4wYkGiXs z$&?qX!H5sV*m%5t@3_>ijaS5hp#^Pu>N_9Q?2grdNp({IZnt|P9Xyh);q|BuoqeUJ zfk(AGX4odIVADHEmozF|I{9j>Vj^jCU}K)r>^%9#E#Y6B0i#f^iYsNA!b|kVS$*zE zx7+P?0{oudeZ2(ke=YEjn#+_cdu_``g9R95qet28SG>}@Me!D6&}un*e#CyvlURrg8d;i$&-0B?4{eYEgzwotp*DOQ_<=Ai21Kzb0u zegCN%3bdwxj!ZTLvBvexHmpTw{Z3GRGtvkwEoKB1?!#+6h1i2JR%4>vOkPN_6`J}N zk}zeyY3dPV+IAyn;zRtFH5e$Mx}V(|k+Ey#=nMg-4F#%h(*nDZDK=k1snlh~Pd3dA zV!$BoX_JfEGw^R6Q2kpdKD_e0m*NX?M5;)C zb3x+v?J1d#jRGr=*?(7Habkk1F_#72_iT7{IQFl<;hkqK83fA8Q8@(oS?WYuQd4z^ z)7eB?N01v=oS47`bBcBnKvI&)yS8`W8qHi(h2na?c6%t4mU(}H(n4MO zHIpFdsWql()UNTE8b=|ZzY*>$Z@O5m9QCnhOiM%)+P0S06prr6!VET%*HTeL4iu~!y$pN!mOo5t@1 z?$$q-!uP(+O-%7<+Zn5i=)2OftC+wOV;zAU8b`M5f))CrM6xu94e2s78i&zck@}%= zZq2l!$N8~@63!^|`{<=A&*fg;XN*7CndL&;zE(y+GZVs-IkK~}+5F`?ergDp=9x1w z0hkii!N(o!iiQr`k`^P2LvljczPcM`%7~2n#|K7nJq_e0Ew;UsXV_~3)<;L?K9$&D zUzgUOr{C6VLl{Aon}zp`+fH3>$*~swkjCw|e>_31G<=U0@B*~hIE)|WSb_MaE41Prxp-2eEg!gcon$fN6Ctl7A_lV8^@B9B+G~0=IYgc%VsprfC`e zoBn&O3O)3MraW#z{h3bWm;*HPbp*h+I*DoB%Y~(Fqp9+x;c>K2+niydO5&@E?SoiX_zf+cI09%%m$y=YMA~rg!xP*>k zmYxKS-|3r*n0J4y`Nt1eO@oyT0Xvj*E3ssVNZAqQnj-Uq{N_&3e45Gg5pna+r~Z6^ z>4PJ7r(gO~D0TctJQyMVyMIwmzw3rbM!};>C@8JA<&6j3+Y9zHUw?tT_-uNh^u@np zM?4qmcc4MZjY1mWLK!>1>7uZ*%Pe%=DV|skj)@OLYvwGXuYBoZvbB{@l}cHK!~UHm z4jV&m&uQAOLsZUYxORkW4|>9t3L@*ieU&b0$sAMH&tKidc%;nb4Z=)D7H<-`#%$^# zi`>amtzJ^^#zB2e%o*wF!gZBqML9>Hq9jqsl-|a}yD&JKsX{Op$7)_=CiZvqj;xN& zqb@L;#4xW$+icPN?@MB|{I!>6U(h!Wxa}14Z0S&y|A5$zbH(DXuE?~WrqNv^;x}vI z0PWfSUuL7Yy``H~*?|%z zT~ZWYq}{X;q*u-}CT;zc_NM|2MKT8)cMy|d>?i^^k)O*}hbEcCrU5Bk{Tjf1>$Q=@ zJ9=R}%vW$~GFV_PuXqE4!6AIuC?Tn~Z=m#Kbj3bUfpb82bxsJ=?2wL>EGp=wsj zAPVwM=CffcycEF; z@kPngVDwPM>T-Bj4##H9VONhbq%=SG;$AjQlV^HOH7!_vZk=}TMt*8qFI}bI=K9g$fgD9$! zO%cK1_+Wbk0Ph}E$BR2}4wO<_b0{qtIA1ll>s*2^!7d2e`Y>$!z54Z4FmZ*vyO}EP z@p&MG_C_?XiKBaP#_XrmRYszF;Hyz#2xqG%yr991pez^qN!~gT_Jc=PPCq^8V(Y9K zz33S+Mzi#$R}ncqe!oJ3>{gacj44kx(SOuC%^9~vT}%7itrC3b;ZPfX;R`D2AlGgN zw$o4-F77!eWU0$?^MhG9zxO@&zDcF;@w2beXEa3SL^htWYY{5k?ywyq7u&)~Nys;@ z8ZNIzUw$#ci&^bZ9mp@A;7y^*XpdWlzy%auO1hU=UfNvfHtiPM@+99# z!uo2`>!*MzphecTjN4x6H)xLeeDVEO#@1oDp`*QsBvmky=JpY@fC0$yIexO%f>c-O zAzUA{ch#N&l;RClb~;`@dqeLPh?e-Mr)T-*?Sr{32|n(}m>4}4c3_H3*U&Yj)grth z{%F0z7YPyjux9hfqa+J|`Y%4gwrZ_TZCQq~0wUR8}9@Jj4lh( z#~%AcbKZ++&f1e^G8LPQ)*Yy?lp5^z4pDTI@b^hlv06?GC%{ZywJcy}3U@zS3|M{M zGPp|cq4Zu~9o_cEZiiNyU*tc73=#Mf>7uzue|6Qo_e!U;oJ)Z$DP~(hOcRy&hR{`J zP7cNIgc)F%E2?p%{%&sxXGDb0yF#zac5fr2x>b)NZz8prv~HBhw^q=R$nZ~@&zdBi z)cEDu+cc1?-;ZLm?^x5Ov#XRhw9{zr;Q#0*wglhWD={Pn$Qm$;z?Vx)_f>igNB!id zmTlMmkp@8kP212#@jq=m%g4ZEl$*a_T;5nHrbt-6D0@eqFP7u+P`;X_Qk68bzwA0h zf{EW5xAV5fD)il-cV&zFmPG|KV4^Z{YJe-g^>uL2l7Ep|NeA2#;k$yerpffdlXY<2 znDODl8(v(24^8Cs3wr(UajK*lY*9yAqcS>92eF=W8<&GtU-}>|S$M5}kyxz~p>-~Pb{(irc?QF~icx8A201&Xin%Hxx@kekd zw>yHjlemC*8(JFz05gs6x7#7EM|xoGtpVVs0szqB0bqwaqAdVG7&rLc6#(=y0YEA! z=jFw}xeKVfmAMI*+}bv7qH=LK2#X5^06wul0s+}M(f|O@&WMyG9frlGyLb z&Eix=47rL84J+tEWcy_XTyc*xw9uOQy`qmHCjAeJ?d=dUhm;P}^F=LH42AEMIh6X8 z*I7Q1jK%gVlL|8w?%##)xSIY`Y+9$SC8!X*_A*S0SWOKNUtza(FZHahoC2|6f=*oD zxJ8-RZk!+YpG+J}Uqnq$y%y>O^@e5M3SSw^29PMwt%8lX^9FT=O@VX$FCLBdlj#<{ zJWWH<#iU!^E7axvK+`u;$*sGq1SmGYc&{g03Md&$r@btQSUIjl&yJXA&=79FdJ+D< z4K^ORdM{M0b2{wRROvjz1@Rb>5dFb@gfkYiIOAKM(NR3*1JpeR_Hk3>WGvU&>}D^HXZ02JUnM z@1s_HhX#rG7;|FkSh2#agJ_2fREo)L`ws+6{?IeWV(>Dy8A(6)IjpSH-n_uO=810y z#4?ez9NnERv6k)N13sXmx)=sv=$$i_QK`hp%I2cyi*J=ihBWZLwpx9Z#|s;+XI!0s zLjYRVt!1KO;mnb7ZL~XoefWU02f{jcY`2wZ4QK+q7gc4iz%d0)5$tPUg~$jVI6vFO zK^wG7t=**T40km@TNUK+WTx<1mL|6Tn6+kB+E$Gpt8SauF9E-CR9Uui_EHn_nmBqS z>o#G}58nHFtICqJPx<_?UZ;z0_(0&UqMnTftMKW@%AxYpa!g0fxGe060^xkRtYguj ze&fPtC!?RgE}FsE0*^2lnE>42K#jp^nJDyzp{JV*jU?{+%KzW37-q|d3i&%eooE6C8Z2t2 z9bBL;^fzVhdLxCQh1+Ms5P)ilz9MYFKdqYN%*u^ch(Fq~QJASr5V_=szAKA4Xm5M} z(Kka%r!noMtz6ZUbjBrJ?Hy&c+mHB{OFQ}=41Irej{0N90`E*~_F1&7Du+zF{Dky) z+KN|-mmIT`Thcij!{3=ibyIn830G zN{kI3d`NgUEJ|2If}J!?@w~FV+v?~tlo8ps3Nl`3^kI)WfZ0|ms6U8HEvD9HIDWkz6`T_QSewYZyzkRh)!g~R>!jaR9;K|#82kfE5^;R!~}H4C?q{1AG?O$5kGp)G$f%VML%aPD?{ zG6)*KodSZRXbl8OD=ETxQLJz)KMI7xjArKUNh3@0f|T|75?Yy=pD7056ja0W)O;Td zCEJ=7q?d|$3rZb+8Cvt6mybV-#1B2}Jai^DOjM2<90tpql|M5tmheg){2NyZR}x3w zL6u}F+C-PIzZ56q0x$;mVJXM1V0;F}y9F29ob51f;;+)t&7l30gloMMHPTuod530FC}j^4#qOJV%5!&e!H9#!N&XQvs5{R zD_FOomd-uk@?_JiWP%&nQ_myBlM6so1Ffa1aaL7B`!ZTXPg_S%TUS*>M^8iJRj1*~ e{{%>Z1YfTk|3C04d;8A^0$7;Zm{b|L#{L(;l>}-4 literal 0 HcmV?d00001 diff --git a/tests/ReactTests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/tests/ReactTests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..bfa42f0e7b91d006d22352c9ff2f134e504e3c1d GIT binary patch literal 4842 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 literal 0 HcmV?d00001 diff --git a/tests/ReactTests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/tests/ReactTests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..324e72cdd7480cb983fa1bcc7ce686e51ef87fe7 GIT binary patch literal 7718 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 literal 0 HcmV?d00001 diff --git a/tests/ReactTests/android/app/src/main/res/values/strings.xml b/tests/ReactTests/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000000..a351b3d5d6 --- /dev/null +++ b/tests/ReactTests/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + ReactTests + diff --git a/tests/ReactTests/android/app/src/main/res/values/styles.xml b/tests/ReactTests/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000..319eb0ca10 --- /dev/null +++ b/tests/ReactTests/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/tests/ReactTests/android/build.gradle b/tests/ReactTests/android/build.gradle new file mode 100644 index 0000000000..32bc6f5dfa --- /dev/null +++ b/tests/ReactTests/android/build.gradle @@ -0,0 +1,20 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.0' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + mavenLocal() + jcenter() + } +} diff --git a/tests/ReactTests/android/gradle.properties b/tests/ReactTests/android/gradle.properties new file mode 100644 index 0000000000..1fd964e90b --- /dev/null +++ b/tests/ReactTests/android/gradle.properties @@ -0,0 +1,20 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +android.useDeprecatedNdk=true diff --git a/tests/ReactTests/android/gradle/wrapper/gradle-wrapper.jar b/tests/ReactTests/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..b5166dad4d90021f6a0b45268c0755719f1d5cd4 GIT binary patch literal 52266 zcmagFbCf4Rwk}$>ZR1zAZQJOwZQHhO+paF#?6Pg6tNQl2Gw+-`^X9&nYei=Mv13KV zUK`&=D9V6>!2kh4K>-;km5KxXeL()}_4k4PJLJSvh3KT@#Th_>6#s?LiDq?Q;4gvd z-+}gj63Pk5ONooAsM5=cKgvx{$;!~tFTl&tQO{1#H7heNv+Nx|Ow)}^&B)ErNYMhr zT!fjV9hGQPbzqX09hDf354Pf*XWlv8I|2V63;y`Goq_#b(B8@XUpDpcG_e1qF?TXF zu`&JsBt`vKQg>DEo zGsuV(x@*CvP2OwTK1BVq$BB~{g%4U4!}IE?0a$$P>_Fzr+SdI(J< zGWZkANZ6;1BYn!ZlH9PXwRS-r?NWLR+^~(Mv#pQy0+3xzheZ(*>Ka8u2}9?3Df&ZZ z%-_E{21wY6QM@Y_V@F0ok_TsP5a8FP%4`qyD3IWSjl}0uP8c#z0w*kv1wj}dI|T1a zhwuAuTprm8T}AsV01kgyEc*X*MiozI7gJkBC;Pw5a90X z@AMBQl&aX;qX;4SVF1F%77i*6YEw5>y;P5*>=z7hpkpJUndGYEWCd&uLCx#jP3#jN z>Yt)*S??j=ies7uQ;C34Z--{Dcps;EdAeT@PuFgNCOxc3VuPSz!9lI5w%8lvV$s-D zG*@r%QFS`3Nf5?{8-jR6 z?0kCiLzAs&!(^%6e=%K0R`w(zxoy$Eu4;oyS=*ydfm^*KLTWmB1fUFiY9X3V z*-Gs^g>EMIh^V?VT!H(IXJH)HiGcY0GaOE4n1O1Qeh*Eg?DvkE| zK_&ZGRAf4fAW?a?4FS_qCX9%Kbv6+ic?1e4Ak>yr7|fa_IL;7ik?%^`it%EM`CCkGRanQGS>g4pPiW(y*`BX>$G#UA$) zfA7fW7!SyAjB+XKJDkIvlt(%l)#&5HkwslSL zht-(aI4V^dM$hPw$N06(@IS`nzx4L>O4GUOue5Fc9VGu*>ZJZ3)%u4_iNy~5RV=u$ zKhx(YXvjSX<8sG?Nl*ZW}43WU8AZ@=baBGBsAbh6uI% z)|$B#8Pv>9DGj4kZkW6)LJDKU8N4%Q=#>8Tk`moP7V}+vq7p9Xpa|I+f}uNQE8}{- z{$z9e(;xI-PYPD)wXOSCzm)#!7u|n8sl@*_SZdCuPLlSvrn2_-)~*i!ICQLvjslJl z+P8S(kJV@88bE8Cl@6HBFYRl!rQxZnNL45zXa$o{=sNmt6D^zH8ogvzR*Pf&PZDf= zL&`Mc!QB&`GwyxPC)3ln0s?*@nuAqAO4Ab_MSE0vQV~>8272PUZ;?pi4Mh8$K?y*; zNM1_f$`*2iGSD(`$vPh|A41gn8xwW*rB91O@^fi!OZhHg4j1d3Y^+la)!MVpa@}2% zjN7p^rcLKDc{7+Y-d>4@7E6t|d4}HLLsm`){h@2Gu>7nYW*cR%iG>1r07fwOTp040 z64~rq4(sr(8QgFTOkYmZA!@8Ts^4ymd-$2~VWN|c)!Hj;)EI00-QvBoKWxj730OP2 zFPA+g9p$rJt$aH+kj=4TDSy*t#kJXL=P*8K|FUu~J<2K5IWY<(-iT(QN>USL6w>AQ zY?6vNLKY(HQErSuhj=!F2lkh{yJ@WO2u4SLMKa4c%li~xYN6gTh5E5n?Gf$1T%Yy? zTkR2#2>0lY2kCm(FZpqok=`4pcvG`~k27SD>W#fdjB^`9jM48)j?!y4;lV(Z>zHuX z;VT_xF;mA#yA#>O2jnQ2cNmU!Gv>WKO1u4`TFkwK$83#$GMi@ZFONKwlO3<3Dpl$NRI^>&v#&Gi$| z2!X8p=32f(igbqa52t+@w7Vh~b}CbId-*qo#5?%0IRXv@^zj!Nu>5B+74tB*adozI zGZnYAF%>d4Hg$HEGqf`_H~pv8PgR$3KsCktW1B@`*=0*CNUUfB6xyN~1i)AdN?SLw z&@O;41xIh6VE@sz9h)sD<4eSU@#%VZmRrnBN~Z}qiY*~A7R-GZct1FT&5(!1Krp=9 zo}Jc*kMK_L=k)f^2fM)c=L$R!;$bpTTVXQ@a>?-Gv4lI49^UJrC=$O*)RdIt1$2SN zm8B3Dd0HQleDQ94AkZwB5@`e*C+;wd2fL)o9JnLG+-D&eBLIyB*d#OyN0cs%I&sJW z31?Qr2&{{+*bmDu17)=&j*@%Ml}zRO)JwtDh3u0&MENw8iM)(PoPO0>Co9o9Q8AS< zHmDZMEx!m;4H~_Ty(&wryP8NyTDoF3yDN{?W(7yZMd+#3D$I;9O_4y30{4T=1Jx`o zij8VUu{*jrxGGg0!d2~!g(YgITr;a9Jwnf0vp7|Avc;(}r_{uijopswy~k=~gTds< zNC;PjhxLc;l*zJip$t<>jumo+f+G~lMv)y}7B;FA-A%29wHK{1PG*s5Wf;B;po^Zj zjdeQu<89BA&3GvzpIFB&dj=~WIoZxkoNT!>2?E|c41GxPIp{FZFeXB_@^PPu1=cWP zJ_TfE`41uyH1Pf$Thpj=Obyos#AOou+^=h`Vbq^8<0o6RLfH-sDYZW`{zU$^fhW+# zH?-#7cFOn=S{0eu#K8^mU8p{W8===;zO|AYOE-JI^IaKnUHqvwxS?cfq$qc0Cd8+; ztg4ew^ya;a7p5cAmL1P28)!7d3*{_nSxdq~!(h10ERLmFuhqg_%Dh^?U6a#o* zCK!~*?ru;C;uVm_X84)Z;COF>Pi5t$-fDtoFamfTd z?IAH-k`_zfYaBJz9j^A%O}fX?OHcf%;@3lbC@0&bfAfArg=6G%+C*H)d>!XJj28uk zXYcq#l2&CBwqj$VyI^A!3zw;GQrAg(lOtxs!YumgSk-$i>^BzgZrT(6`t>F_8b1Dc zpBNLLXr7l&6&h0ZndOKubdZ;%h=I;lKUw(#E%u~fX;lOt9X_X!XlI%-{k#x%Ou(Ig zXKxZo-Ida-TC6I_RNHo*M0TawHiC(Tg3ryJv{DlU`aK;~;YA74#yuIvAQudfPcOU7 zqM0rSj5DG%llIxNC#i+`TvmZhN88GkR)y_tLco^kwXC2<@l9j@pkMQCuF&wpJ&Q+7@9Ri$u75pA9WwZtR#hz>D85Rc z=?ihhi||`h;tg~XY1HisXjgQH7m9?8BKI@_%S}Sq=#s<1_Q*DX*>uYqr<|D0t`kPV zcv~&yhhvI6kCk5CW`~^wIK0Nv9f2}Q9ZpsQri1)o>`_h#DdHT{RWaJO$HiM=I`9Mw z=#jvI}mBkDEC|>Uu=)PQ_B22OM_YJ|5C5)|mpg z0x+VM#Jtc6DjS$kPl}?MW`nk^EoXdJlmm3bqOA)oGKw*Z{cUHYx;GL6T|Ej97CkP7 zh6f6kcdjzW=*+Ir-CSQnzd`)d@Al?&uFU=jue$DxSAg^SPgxG-CTPfv`(WPEH;!7u z&v*L^WVl4`ps@rAmfhjtju3U(10=rI1q~4WV*K3#(A@)o-_NC|wMc!7eGJd`iO=93 zfr-!P9-gBwk-Q2gM35Gr;JlaSAV?+={rIF&=~?x>a?mGQu5zQh zjL{y%ev~ERltaeUBd&K!z#lRyJ>`o?^`~v*HoAVOQVhPS?ZcKc_X?|?zYaw=jKek5 zgaN#|;-t-rE*6wh>YBVaK8JO)br-rMjd^8j6T4!wL;{{upepl-QJk?9)EWhhk1e!q7^O8*{xLrj+TFVGI%TP6Y`)vIXY6gBHOdqb_ zzVAS;VMAby2-40p7JpT8&|a{8+@h7y4=5*0 z0L;{ms9dV6W>j?&0_$XR9av%=tl%Q=cootSL>y8;i6;_1TPrrvQ}FzN8gayMunm-u zU8E2hfe9?zGd7Vnh?5Rf(yWkru%bvK7G`5ETWHdk7ITViO%$Ck;fRXF_?! zuUuedX~ESD@jtNtDymAp_?E|iF*f#J0K@p70nERLuabs#e-j1&L@%-Gm(HkaXn$<8 zO@`d2iWQ}$L!m${KOzFqZD6S9rAraX6lsIH0I zuzt>tyZ-?^yK@xIL~odR-SnQi&b{Y4&t2{Q`TdR=@b#uOL?2V(AtHh*&YCk^5yipw zM*f%rfo}Z3NbinHO`(>fexDYm9s}kmUI#5TEA1p799Ky+Ywdx%w0I>9yE8C?p*z@} z)I-U@Ls@!j&B#b9r94C%qMBzd1Y?O_7BvL}B2s4BC4tT=(N&K27Pr|fJP^jTgn}A+ z72`0A!-DO!F?v;!n8}Q%k~bxrpUwUV<27bOi7vx6Y9l^;f=`-`Do@*(;V$;lV*I$5 zMdH8M0B}2iVJ{ESp;2pKVRrk~VKyww!)|0I+SBbq+hIn*Zg*sX$yyt72}N2>q*}^j zbqr%CCCU~W*vc>^K^cyjL~@$dCZ_d>-Ux8MFToy?9?mTueT{clQuPG?4X&etR zMYckocR~-atwpK_qGFlArnhg!F?H%9i;{V)3Zg&B!*DJ5*eLXBxZsjFcla?Vs}-i> zaAxfBY*hEFJgos%UO8p&!b@D{Sw;oFTj-3VcFTEjyxcQAiiVrnV9CZZBt0n3yd~+$ z;=Cbo$x-cNXRDwb&7}^^ugsv+OkEX<$EulIosp%vX~GSWC+<4rbZHRA+{QSq=}y{p z$T{XX0s+!fN*5noHyL<_W<5hcY~RSgL|~)VNN9|Nf8G(FuBQ{pmr_6mViTOydF8j?rr8sfNh3*Z^ABUDhQW4eQhU8+wc@;?|(m4I_N0L-iv z&h65V_fr6z_!DpTsYccIFXH(_9=a)aWN_{>HXGwr8K{VY?CLILC8YIp+>g&w{& zg_oX0SmVW_@4i6%=f23_CZJ*%gmTMH_eAaWkuTrsw}bi5lCu+TC-_1r(+U(A3R5>O zH`&n|6Y1H}7gk@9vh!PPJwsk1cSzd!#lwSy^v7SZHqo{QpgUm`k8fe$qt9rKJ`IS_ z07aJwFCid(Bzd^1B38&eH$}aaB`?yoxvD-f4lJ{~pRY=DzO1N;zGvnjUmgoOBAkEI z2Z|&@8Nxj02xT3pxJaWE7vT|G^wO`$aReZXbI(X#mgr(RIgdxWBvotY_Y?wcc8*)y zqe5FFG93ytkepY6+>q~v%koqFI~Wp}*G600;*@l+k4u*nd;|ri0euh_d_Pf29AOxi zq7{PV73v+}4>)!R%oBy*&_y^04|ES+SCx9C{p(X z^{>FWT|Jh{9+MEA(d>5MhX}_q5HrAg$MqSS|>L8nenhPVQ5oXUs5oQ97 zObBg8@mZUaT_8b%&E|x>Jm*`k{6}j4@9z)zJtT!> z$vrcWbO)Ni%?b*oU|P{15j?_MsSZR!iSq^#@#PTi*z3?k8!SW2Tc>c17gE<5dbZv_ zv73Gj9n_Z(@w@L-`Xcej;gja3;#@o>g;mXC%MF1OT0WV zE+0W+v&}73yw0m6R2@;J`*GeGXLwGRsEG40A-d8FM}wf6AD{&qHfrSasp{(G!+V@I zs?!=8jhWXDkSANEFb*@)#1mmj`E?$me2A*yI{d_)GC*TnzJc&;hQntYW-^z@jU&K3 zysrFhgCHu4gN;{~D6B2a66@W;urGvzs3ch&AtB6*aR7Y`oy$Bl`scU(hq-PsNc${J zq*Yy1Bg5M(znm_A39PrY5_muAkowLdjIK7AM)&zWs(58#^^a0Jz4r%gjd=AJw zz;9|mv+sK;h;jYt{j`NNA${`1pRi|Jc)3I9(l^CZz}m(1#!s`KXEB25?&g|0p&HP7 zq>|ggQ-14sd5C+$o25G>d2JHf%Q7BxJ?V>Zi&osBi)?@r>_wSSZuH)*yMvcM!2c?e zvrd;$=#W4_b_hT~6#rQy6%Ac1gq)pCZH@lhcc-eq8{=vqf3L2hdnR*6Ij^?{8&Ss6 z{=$$_0Z5_Vt%%mve^ASBbXZ%H+Ed?lbyp9EIiUhxeZfFdJ|Qr*sfJsC{f^>6`hNY; zX`^0xf$ZhDwcMHJVA;)X|MNZf#Q~f%+JC?qHAs*%qKpS&H%!$_B%%~{43PcRX3~f< z674vwlz^{8MhT&DqKv1sm2$1aTqE9yF(%|g78gJ1Z+@=~M;Lu@=;#BIAG5FG=!27= zIASi=g+Fp?^6i5+cGm=_A8`<^KSlbdeZHlu7;) zAsu>TQ5i~pOdpd7KP@k#bT&>$BNMl?;Api`VuAfdg~JGYihhOPB0IJs>#k0d<^ujn zK{1w(N076_-CA#8{a(a>c=lpyt;OoY5|-*a2)JNH_S|BGe=Q0cReh}qnlDH#-}puz zS{{?0g6-m~r9*SQXV^1m+e~n6z;;T9E4smJyb@k@Pwh3erlIM|&7I#W^%HNEmCKGp zC~@n;u>XYZ>SiH)tn_NjyEhm2-Ug)D$hpk9_t&nW+DmmD**JEigS*ZwyH*gj6>xoI zP(;QYTdrbe+e{f@we?3$66%64q8p11cwE%3cw;)QR{FGMv`nhtbZ+B`>P1_G@QWj;MO4k6tNBqZPmjyFrQP21dzv^ z2L?Ajnp{-~^;}(-?icZxd#?b~VM)fbL6e_cmv9N$UD>&r)7L0XCC;Ptc8MM;*`peo zZs3kM_y(apSME1?vDBX;%8CRzP0}w#^w}mK2nf#;(CC;BN+X`U1S9dPaED{mc|&aI z&K}w$Dp-eNJ9b(l3U^Ua;It3YYeiT9?2#V3>bJ_X-*5uv;!V_k#MQ8GrBV8kPu4v} zd(++K9qVs$X#HwTf#q6V$?`8`GHbeGOnnX_`Yy$9xly}^h&^w`BJtw)66pSe`D!(X zYUut0`sghl5^3l3JO*e^W!0Eq&(=i_!1b^PO+mq~83hHkT|8RMKa90@U(7!X)TmFA z%Z@41CAUfp>r%E#6mt0+e;A4bwuW|9x5mPv`enp#qPtHvASw^wd!(Gea^o?Zht1Z~ zIj#T%6>s5aXCU8Fb}%fnRUL@Ct-9>-MVi0CjfNhWAYcha{I~mhn#a~2 z8+tdZH&vR0ld=J%YjoKmDtCe0iF){z#|~fo_w#=&&HN50JmXJDjCp&##oe#Nn9iB~ zMBqxhO3B5gX*_32I~^`A0z`2pAa_VAbNZbDsnxLTKWH04^`^=_CHvGT`lUT+aCnC*!Rt4j3^0VlIO=6oqwYIa#)L!gZ$ zYXBQ&w0&p)Bcq@++rE^^j6(wzTjos-6<_Mjf-X86%8rzq+;4<_^-IvFE{LLTnfZm{ z#nA%Z5n${OK65&l-394(M&WkmrL6F*XaWj(x>&ovDhW<^sk7fgJjgVn*wsjAiD#Gw zxe%;orXk#Y6}$s;%}(zauR9x!zNY;~lStgvA$J45s=krBjreKi6og<^Z( z0-xv@@E6XBFO6(yj1fV{Bap#^?hh<>j?Jv>RJ>j0YpGjHxnY%Y8x=`?QLr!MJ|R}* zmAYe7WC?UcR15Ag58UnMrKJ2sv3FwIb<3_^awLhvrel?+tpK3~<48&bNV zplmuGkg@VPY*4r!E>hUxqL5~eXFNGAJ;^5T*e$I_ZkEaU_uhv6?$6v_k=BNLh|k~g ze%yKO`}Ej-Xub7+XCv8|#SB6#=P-G5#{L!#vrjd8lfnL$=KsSjY3QX=Xzv}-|DH;e zy6Ap%MTh-OA?YvUk6CiNxC?m>{Q-&HS3WNQK_&W!tl&@0e1FP9|6)JY(=G4^V(2%E zr0bKuP*usFw68zV^M59P`@?+sC$KMO3sn`|PC0;rqRwUvfTx44lk(_=`oesI)_`#m z;g$+j9T&iv3aNW$4jv0xm2!ag;IY&rWu!L2fP13Xt9J(~m+*8_OL}wF+-(rG z!ru4#NCd3y2d_;bDSL<{aC;UHCK9NM|8!+ugKdSt z#zD7(Sv0guD=dxC@$81QY_0#x*=6 zxRoPGAxk&gQix^H!sAV^s+`5QnkavHC;~mu)43ix6w27qqMnZ@Z?ZUA`~gf_=njW? zdG3;*wv4x<9c6gdc@AFi*p4eTv@_?@^0C~AMuxvXnb96a)X$R1k+`<=MIGV@$q@;ZH7rh^33*#x-VHJZv(0`I&x%T#SBgc8%~R_;s+&mpC9_-B#JPb@hr zx6wsR8e`%Ql4-S4*KTuV!r66_Im2xnjz!A_t{em6He+EFNVWH`+3E2JyYqX}E)4f# zcH6NTxGQBP!H)pTSnIZHAP>|C<~=ERVq-L{%LY^F-|l8HA<>a4jPFK3Tnmq91Hw;= zI|?tyGy7W+6he!WB{qC|P$(|GF9lo(yi;58^v*uIG9+wO9fsPzL?NtT$2jMQ;wYJ@ z%HCF&@`8da+w~JOiye9MTvz*xQzYn6}-v;imLYiGTH>#3HlDaAB$9*!7 zxIhQ(X)k_-j^3S1ZDvhw4lS_NwGoAQ9f=yjj7pl?B+R!uIv(OBiGY6!ZxElyUMAI} z4OmMiXkZxJNSTd3``9VX9v`$gF+JB*(-X3*s4SQOf1Pk;!o0kqpH4ovAMqMfo-$o~ zWciOf3jfR#J$WD#?H8I^@O8Derctq9c*>qyk&!1PPp)OQNjDtBtGpJj@+g~2q|WMo z1m_O72q&`A=Pnuq$s1~YTOxPKTV1 zVXNsTs5aZr0+%g~e(I6du+T2eFV|N*H-2(VB`6D#hR9VrxAYP(mFU1_O@9hWl;NY! zOi{MXQB+5)@F65r<)nV>R`ug}t=byv^^n=pO|k00hOY8UMZ7n>(*tA;zE=B$@W-oi zpSDXdOKoDUJyOM=7k=VxB@T9B{!&lg!HCTE;!a|{hSI}sGb1C_c7icT;kvzUptY6O)jURh@=R5D2&T?YTCwCWUOW}G9v~*oRO@N@KvF)R zpW7F^@ zB`sUQQ1Xm{Pn`o{5||c&p;RR>cOkHj!Zct-6Jsv*E^|tf+h-sjB7Jm8WtgYdi5a}A zm0BYk2|CAH|1DhIL}!4z)3?gJ;+~l)y5-pLL?T)&59NJNoCf>71>ndAbu?2DZDS0TK<+Z8GnDsndcDQF?qZH zTJ;-Dpz`5!7??ULjUFJWJjmwPKS-$f-orTq`7XlM%23rzEkKUprOjBUW05KH2;-n; z_=Z6csg#F|>#JF+U!<@8rj;r%xDDg4dVKn3Ozoc|5Xji?S@u(hqMei&V(MD+1C-C) zZmbMEY*2e);hVtUiA8GHcNU?3Y`NmZx40WxwcN}-HJ=Dc7>NgqY~XXRtv6bp~W zS8%{oJ7B?GcmCv3Fy&&cX>KI0=$3!%Jb@~l1w${vO$HMnNp?)_CUgOwe*9R?N%B+j zHKyE#7vqamzJbR+RV+R?IXZC#-Mdm9t@E;F(eg0orUP~Z6;YMEV4;Zi<5_A=PNtL( zMJhL~*iLCk#jK>;*^@xB)x!t)3$NJ2&Zg6q1BzZFppl-=k^=rMumfW0Vx!2Zu9EIS z(Onprq7CmH=62>8K!a&3jj;%aTd8gXFOle0T$w?DX*ZbC3A07n<1sSj;CO2oopWNC#!JJuk?-}SL4Al}YoKQwF zOF#w7$5CNowy5Otx&Kn#E}AXymz@T*@hV1@x!S&MKqgh`|7Z$xIAGz$pO%+Ld0pOmp zl8cf@%)SqL3aJV77dld-oetA}Y;P?H~^2ORw3d)8&*ZP3E z^Gzu!J-C{6UZ+YdW3UdaH&$nKpI#hYhZFlS2#~|Hq%52HlB>VI_j-Aw_Cepl1T3oV zZ!Vl5ewJHKi7Dd_eOIgg5FVTRd|QmQXPaf}9}s#YlJ$m}&JQ!3Rixn)bvN`y+|mT& zgv!v?mdXd(^aJz-($6FA`=Q$wD=Z?4^zaZp#T$^9U5~?VB%-qd*^uZ->G8Usa$Wtd zIK&bN6KLtG8+e0Pq#F6warn%NKI-L_L2nG3U&Y>79s6ol#eLK-?#iH46+n6n!+|jB z8@05;%P1^kw_oRxo3ZU{u+P%YE2ndi{6pI+thFh^Q)WpCZaS#ErR@1yb;IX(KH5Gs$@&-W7O~O) zqNknOGF9+jx>VJW{QXn-zzM4hF?uSYH%PA}zf|7*8^zUJ2ru{r-r~woJ9Mu` zQ1eE#$wH*-OtcCsXp{ozi>&3FRy|+5qfb%+Xw&$Nl(3w^;EOzD7CmH!wxDk5^9&wr z-rWGZ(Kc$*p*oXaOaP%)AQJ5!^(ndFjkOlC4tah%(&Y*JgG#d#p0`I(0G`Glp&=g} zpW$xu!W<9NpT_>Z{Vd7&UF`|p!D%P)?()g`CnZAcH#=??>X zXuDgRd&43uW#9aB-_No2y@J^n_^(#F{h;4$B6)l}Ft?9Kk3B9sq>Ui+BF?flVZul$a6hCmFORb^99h=?~fr3`~agAY4BT`!AM zab40!-JW;l`4>uibgBq7Q2UM+~6R#WAX^XI-C-(W+EQtdnDo*>V zK-TGpiIyue(K?t5(J)W>PxBvVoMM~1wYmaH1@DOqbu8+bbPRR!Dk^3+SZBa?D(Xf4RdY$va$2U@ID}6qv?IJD(D9Wmy5o>_lugu&E`c% z@;zIOy&b>~Lmn~5z}T$D(hqG|v%r@W4QRuOaE=2i@x-t`(>T+>|NB`Z3LyIv`^5dl ztw}4<`yc;lCHNB$RAM8*o!gvrgZ*K-o{iLIn3wYX8 zwhef2KXY#e=rB%Ys@nNGhE&1skqjU2ijXn%U3K?P^~ZDf(%_3c(pj@Wk>Ue8S( zxSIm!*)I~J4XGs1+ab;oE)tqv3+Q)}r$>``c^^j&p=;m7pDRQ$O^i71hDcp~SAzaA zAKyv>mq8-f6)O{W-}||M_-{e=_D|W!;lDNK)W41M|CioQVS9TQXP3V{5^{!?b}BB0 zPA>mbaMse@UiT_;8tf6%<-^-_!k`UIL}V^8h^dd*)st51QMFQIckVA zn344`7^;iYoS1A4^~C&5E*eUOK{8=aY3>hwdGYQgg+FViBBe8u6(d`tteV;ws0>0r zOFD4Gzcq}6k3GLBj!L{~4pKfVzB}oNV}gZQXq75-WR;Vrxi19BXdWde?6nlYg1 zoMvxcUAE07`_9NzeTH9IeCs1ZyZ%8(Lxjgt>%wYVNtG*>uYK{&-(2J_w=}!aqNUD8 zYFC{$QzHeuL#q#ShG;wTvJA>rRV~hq(@r-dsnCTo6Ekbco$Yd0p`Jz3vdoA<)J=Rk z183Ozx9?amxcY}Gop3%Yd^Y|DOIOy+s4UxvB$k5$)^uE5{iw9+Z-+2N9unXg@kBce zvNPBdKg_sHyoAv`t4!!`EaY8Pr!FWVb=16au}hFJz?Lmr5)RE~rJJ};RSVSjNw$K6 zi0Y_3Alt!QbQ8FNr7Oh;5EfC~&@I-J??eORVnBisg)&fH(0yQJgfLtvz0PpNwyMOQ zKn}bgkISgFQCCzRQ6j){rw5;#-m1{h5-|Kjr(!0dtn;C3t+sIou;BU! zG~jc0Z1+w>@fbt#;$Z}+o-%_RFnuHLs#lLd)m%fX%vUuAAZF&%Ie9QRW%$dLSM0DG z-Lz-QP#C@tn71_$Y{dY1%M@E%o-sZ!NXVvOWbnCrzVMgefPp{nEoZSgpfo~9tuxPR z)GjIjU9W9SiYb~_#fBI)tHnpI!OzNy6?PKt3`ZDctb@E7vdt*Y z*UtW|B7Q##?$O1LUbaLp(#~JubBEmpVYr?ZFPuX0%qtWh;1~eaFUiKE5;q-$|DoWC zJees>G+wUF8B9j<56`%ZIoY2X!W0Nhk@#Z5p%_LT2WE<211ZvwjMtN!4^Wz+J)qlS?Ymd9Nu=W)wPak zlFOOPd?u-5p-E>eg*gw7e{N?H3Ev?ovpK)m`%1su!EtqPut(zT5q}!{NW{ zq2PBl0Z9PjP=^9@xXP%9K2Tj;FYxlljGm2$y6shRIf&3?qtj=3aMcHUjUGV^VWMG09G}R2cwS&6 zh&k}Vi`gU2B#hfLM)u(ik|22#1Lo2U zhB5l;ZrRp0SD%t|DYKaxm#fieXxN-ax1lq)UuhEiF%Sg<{3BbrmmgZD{T2RJG8Q5B zNj+b+3Em#3mp7yKf-I|jy2tKUn4V(8aBIBjk_#@Nc03r8uqq~c(F{F!IMy8o@=$8b!(o0#j=53a6y7<7^i#9s#((+uAHhG(6 zL0z(1n!c;c%tL*mwp>)K;O!BK#--;Qs#2()A5POs?%uvwyJpLjE}QX?1AFpf7}OTl zzT8x}tN7!Q+iJBM_&TpbNgpMMCe4B7KgukZ_~`@+A|uk`;R089{Jl|HICLnS8Bcd&Gw3@RMwzx^6JXs zyOrq8&T_48?K~VzuX0laj4_Wq6I9 zGFh%W`qJNb21FUAaB$MoFh&toeM-_h2D$XyK;hO%e;dFNy z1)6@y;dH0NWdU`T5mK>9YsP{Ax2SdC4T97>O$FJAFtG1VE$evjO7e#IRvaZTv6kN$ z-Ak&nAlZB{6WA$whf@~SlR#f9zg$<8I3rmY8m;aY;#zvZ@J7?^YmSa$#|Mz|I@;Z- z(g7bUCjZ{PsTqCRv5eSLge+9L=iuds6gMqbyBmjo3~g_nVP+U+Da9aIb5<3r!k9Zt zd-0HIZCvrrE2VR!ORwam(%D=@Cd^%i_40{NoEaT^?kH8r?5=Du$m)!Hb5J*5KO6}% z&w66lW5zc>CezP{I=l_q5m4PCd1H9SEUMp^;rvs1p#SEM^+)Mmzp}=69ep&J`g=?e z5LLAdcto?oVLg;zE8u!D`EBK!U)`3lwq#@%1_5R^i|0mLr}8D0upt3>{a9=$bRmR) zcbnt=t~RUNZ@iwfPIc^4838x%>@7Q(t?)*)J;BanAbwv@1qz;4F)Q`5d8<+grjr5jT9QHfZ`ydhBCwe%NA!|Wu zYD>i{YDGzwny*quj6TIXF1|A7`sH&Gx9T^u9d%;)*0fY|AaG@?9LX@0<*bZ?&_jux zRK2O9!!Y}4QO~|5_-jVHy77Fo$^e&N<#uvb>S8_BMQ4kiq58^HL3-RR)doDky7+H()lP)w zcjbp5-#_byoZt)+s)_5Y5{|sq+x14DQ~RFJb>rVwXLQSbF4ZC?Os8%$w%TW>Y1T45 zQJwW9bLR$}C+>OcAei!Xe@1BmjGHU4Wrj~?h*+aH8nLJCvxVLoNZldF-j9H_?|kB9 zbm=YP5Z+PfYCvMrO>m)jR40a6N!$&7(O!%iEzAdNGO{xyb|GHCVer#>p$1-DFvT0= zhPEutAmne9oM!oSS`p6?Y1B5Q;k9mc@-PK^Md^tyl;aH?h<+juqu5H!CrA2rOt7YL=Qo-%%Nf7JsmmU!y4U~O);Yh*J-Nxfxf#jrW!dUgyV=Q{ z-MJ94(8F}%71(_4k>k}T$P$_wdYwOLK1v;0cScnS6Br5g-?)SrSvKQOZ%(cLgHa1KJ^z>+3BCO=7nk@2%6czqkeE$Wdx zQu)vaI_mLlh67syS})AUsV%FcjP}IhvhYQ( zq9f*f{WN;hYA#B_z-|GSCl-FnKQt}!uiTr z%U#c{22tr0k;!>bq51z0y`d$X zypY^I*egh0I4cJ}82NfYF>-2qNBF3p5%InbSM&}ONRMYh?2F!L{}duIH^4cGOGl*m zVnK9}VzjjqEd(75RaI?_w#wYcIK~0>)T{~>^bld0My9oUaYDcnJC@ZQv2;4KHQnFG z$J6$RcNS$bLPx`Q1-^0*)_vGnZJ^a7aBTPdehtQ-?Xi{rWCP_9HnJ*ODotF5C9<`9 zqh1qJx{c0!L*O#6>dKp`aVvhrL#h&}6z^n`e)RDxE)9!H?_!udEPbE*LEQ4?8H`*N zMDSoPA2tv4GItSdFp@n~u5=^x(gz)bo(k>|f^wNn-ro@%dKAUL(t-)YVa(tGV3i!c z$<;ZZRyR2T~g zi26SR(SO{z{3jg!uh{&bWp7PL5417#Z%Fx#B`Y;f=#rrnP}t>!*?`!_pGaCLLTgqU5g7DCOO~ZfDMWdEU+4UAedE zg!TInXRdoZzj{4y;T8BF?}~v|qhqPt_UX}a@0dG#bm{9A@1)VeQFH?|s5lSDs=qv9 zw|f5?Ifr(_*SC8waC=21ipI%1aZiu>D31LZn4O}cMc{t55riJO2cK@;9pZHNst&|k zq)isOd_ zU4j?m$@ut+yF=tof7Jmlbixs1YJ#ybRUf>3#d|51{raM_j~k-vuZydxq-D(I`@fVT)!=P|Nir_c2ytTU8TDp0)3Q` z{q+ZsZ-u&kB?n_~kx}^v<}iMBMTq@K6&s!ft-aNU4*vFIfkWM1T|5Y{SC^Mpzi5!o zxXbeAhnV>IQEpmM7T(4&0+ZNT@>-rc*b2s!!vq2GJ-x;CtVu@sF#Jc+8_{3w{i ziKPHvb<2!Qypt3rjKkhfhW7Q@k_>U**c38ftCcupo#YtR4XsiXA})r^;ujP{HelKb)?1#O#?;0@N*yh<$%^d>IO#w){mm=7;S|<<7NM6n zZ774u^-@}6LCXu8?#A8oQF%r09OH&DI-Q7Ic_pT&bk>9@rEwz6Esvd;Vv5o~3hVE{ zp622`RvE!$D<8_wn{x>onCjYG%;Zf8TFq^Q7prkpuy#7?lvpj-7W2@>%POQdg>SIc zF!%+@?X56I_oXUsc<^Q{tMi^Kg^j7!wTRAQK$gTVe%un1Q|&P*?`3I-m!}KmcLs6%b@OA5q z!_8Du59}r_xK#(lnibXn9gf|o98TOmg?cgU4>I`v;UyQfIv#Ac?^K==IVvOeSY|5L z-!T2^cewEVBexOGx&?b4)K>H6xPRhlD)wLBg2Mz36kxt<_WxqGWUCY5>&4{a?T?PI z{{35=znAi@Bo7ea%kORAF>X}v7~ubm`h%r;b=0e@9&5&6&K@>w^J2$melS`GI6M6> z#@;DB@@`%CPDdTvwr$(Cla6htW81cEI~`jct73Jmj??+-opY|e-!M;J+6>^3Z&YlT&`p*$i9u&4zWp;5${7P2gxGI`an7VazB5B_AvuPRQoJm#hdr8vUk zbj!oyD&KaLvnnIaj63_=IQR)TYv&t;Jz|)VMG`aenPJUMDlIvphj(uP^92-lKd=IHsL~x%@6l)COKnM zjpf`&kj`Rus9aoM5Mgn!d{+UX%WGfWfoZGa{zq zkZ?(i!K(N;<`8j@^B~6=o7MID!nQ54xcuZicWa1%!N2I{8rQURz`{tdoLn23xRin1 z&QPKgR-XeMCn2c}ZyLPTDg;dSy^h*toXU?We zD5IWo>BTZ66TvfX_b|n)Oq#rcDp}t+!0eJQhZ_@Dv~7`UU@yz=v$Xkrzb41%lUU~> zoa`%IM0GOb368g?vnJiHr;WKCr@U9qd5pqHD(GicapL7zT6N;05gwbeOcWQRQrBZHucW_Og7&JKMHGnsi{MJRvdfd z5||D<;L+IRg!l}L@s4#Y!8CWj*JTBR;7dO1hCqcyiW@tH?MFd-`=G#f;ZQavMJ>*o_miXO(F_EuQjwZ@$qF|JEik~m z;w(V5peYm;i9^$bU?>zOQAICmB}u3!P%hK|DfnT9BHXFHq0+*j#TFT@vsAFb6lx|q zP()34f}_P8nTiS}Z?vp5FBrIt+TjVqe%MM8+sc}DEfH{z!}FcquC{dOOgR*iPLh;i zgy%wp^>NWo(}cgb85y#$yaBr1nAKhq)*z^sE132cOULdymY0BJTbb7<{*IelCLUvt zSnP#d^p1!ytyoKn`{@93IHHwsj5&;}*N?x~K1r6CTTj*!6vnL8i3&e7e}UunXBtU6 z>(V*60t-pGEjK9O{kVD--Zi8L$vMioPN1{ysA0Bhu(n-uF+8Y+m=BSCfpD!L9ls|Zy@2b}xVaNB6;i5G#>nAn1 zV%^?tVA#G6TIsO_{_ec!YF<+}Tf6;z)zqC{m;C*@u0M>8qs++)C%v@MYR;GHSJvQh z;V878Qyhy9sP4krcf=}kCdbliWLsRFwRzsiOH|JlZq3XUXg#-;G*Q~r~2 zU-Gv3frSaXN5+QSiJh5iz+=719ONtNJ5A9sIo%g^xsp`55u7p?QeWJ%^m@akb|yOy zR--2-?b2BIlzAyxhw{rNnbv&>PvSjVXkX-HEu`iQ0?$VLVzMj8%WaEthL1HQDjAa< zK!s~kYW9Z}UV=cr*tOhY?nMg~acHUBXC|DM(Kp-)z+f)J(+tDY0`)_p6*ReAfgoqR z{q(-dnKN>aHOhJE=fBZL_Ujx?5rLO=AK?DqT$O*uJpT(=l&kSe6IB!Klb?l*IR?jx z7A;j{Bg_ygY6HenT&Pq+4N0lGR+J^|rx8W2oRHn6v5gI8x5JumYc~CNnc?qom+g6r z^?n!Me)<<&_GW@hMLf*sB)@HUpI-yKcf9Y%c7AMuH(+R<6k@z(KCt{US-2KO`pU<3 z8jKsx=ehQk5#eT^X)ez57AiiT<%9|~bOI!~0ud15Rd~0L#kg+(*VJ}AYElDig*xSBR zU~%3I)@dpeE}${ixpmx9G48@4XiO0kX&ua!SkQ3I{jI|$+T0H13Tdu7J*H-x3ah_K zNz|IjyfHBtVP2tMS@>mnqaN;Ndy=$gSzu(rGuKQ8P8|f)x!kBiBfE|)nZ`+DHmJg! zJ}`Y8+ish%f_^%4jzC7vdVni98Ec=Bcu31zd8tkS? zSxv>6t-yOYRRhmK7qh;yh_Acov*nKCcV{ zp;6d1x&|K@Geq_}cQo>({&bQEAnv+_mP4*IqY$G0J)=w_gMvc1f`b4^Xl5_gS&?4`31dQf|@v z9(R*s9Mg+h|#54;n+)WVGsp*i4!>@q*Jh5Qg7K(5p8tyIZpa%8SRl{a|g&9A&1@ zD^e9Q$hN>E(F{PmfA6rqR>w+PBqq@Dpcb_@^5+RXq7C)Mb#)X8%-qk!Sl1vDt+(T$ z3tSE~_K?dX4bmth-*j1?>@Q6|TS-Eg4Gn2_BeFW9)&*3r1*c$<FqUUYrCiVW3J(d-5g6_FS0FJ=(5Uchs`V#M-N zh49EX@;cAoa+HS+lp#HL+utMYv3D#>su0r z7u_#Pe|zKH?k`URyK_|1LoQ(3!K+Mj+Aj-KwCRy0%%3>ET*#}bql3yd6|zHuQD(zP z)2`sr6iNceTCa?Qr20XJ8+znQtAqX+0I2C86=xZ%r7S?=QLPi9 zm!fu5e=Z3Az_8r8B%*P8n9}5x)hy($=CZUdD~)_~LM*M6o)k--z&^MW^b> zU_h9LVkZ=^VTj5u5)$Q>A>)-I6?aT*9V}Sc+g5~*(k|Mj4!RH3mZ-Md zP$8~c_Qhe3hNl6a;jRaYSBl2SqHO|CoASjsf(ymT{Y4krWY~(++CI^0WWf+8uu=Pa zD;uog0{l+^_6NhoM2vSMBk8#WB01Piq6R(75C4C=j%Q6|ozU_H1VjT21cd8fgGz@bHK7|wNq=`hHi^jgw6TJzOJk=3OI2~ zC!Qs3gF+0lX*3aPrnfv z<8SrzS{C0Q`Q>)okjQ&R%zD&|P_61NKBV{T;a2+RgzbI8?n+Y|86BG%jUc?YeB}>l zNR&Z|6_km>`N_kBBAXZ#47>W-$5v|um(aq{TKO z1v$H$Qc+>lnv z9=?Z&JeY$&#hfEx(1m9zPcNA*A<_{GN79;^o6upr1jojtnUEISw-6Ya)u7+Y`^<@* zQ04p~eX>>79o+qHC@1CVL%G%qEzk*eu^Y*+xlaFlIh>36j?xAC-z~Ky6B%4=C=d`? z;2jd+6_S6z82<%Y{4aXqf9JJ@YDW5_Sz!B_H+Qr0!f|7uXi+7U!P{Puz$CRSktMiq zvJKEd>nk}m@vhSWrfn_Eq1EhqtA5+J5~!CLpzFq`wb@e5@2jiv>C|fIzGJ>)E}dip zE|4{*8DHX_-nI|C^H01_rc(X${UQ3@-&M^_LL0!ie{M12=$ai+IjSEz$&D7lK#Zy9 z^n=j|gdj#AlN!$j(+~_wn)%3$j;XU9pweXBNTVYjs2aa4!Vo9}%`FYKeAQboAK?+q zTk@ZLI7OFZXg=B_nl~LW^)$~}Q8UlqLAK|_x`P}lJVAHVZs~K>8dT-_=wotFl2l>x z)Nb%0cGPe9A$Bxxz#tSSo(rQEpA%!s&G<+U#!!faqch8l;?3R0nDLYV?Du3 zPvuON+_yEd3~WQ=6b&{f(NIgRq0mEG;9T`TsMVlZkK$lWnZh&5X)Bi64i#RHZq$kq zn{nBX(yiOqETEw{fXN5tkudBbIq152 z8U-0y`qWaGO}cWa`Gg}i*zn6kzSxo4o?JGuDlf@2?0Lou%e81H`1S*SoG|7hBQ-V; zlbpz04}hM(f|4jW<3Tx&Uzi2?MJGb7{hv<{%?=-hQEd3R0|;zJYp&>^F!G#5rdVif zMk}s(*uxWN1xY@kST%Nz;gT$oW!b?2@t-|(2k7wWH!kqhH>XuxlKJ65G2bko$^AizQycD<<50V$c*N*^@OdG*H91fYg5#Pj5}j& zV7is}$~1lx6J@XbHk!}=4&gBVTn%)}*tpQvISkpoe!jph2$(V=}62#;K-r z=px{4V=SM&*G=uJvW$W==2-~S-Tw&1LunP`!S#K40}R=1o4hY>&d8@W=iojNb`+A|?nq)n}Z!cpU>tUAAOR^O1p%&9v1;e~Mr!?1a_tMZAv zG7he;E(v{J#iFLmvATrZjIn8ek0^#1?>b^l^(ZZA24gorKzagWWvhaQugIcXO zdv?~F|8oVpSVr!Xo4HtnUjoMP&&f$19Fl4>gF~eTLGJ2hhg3}_o3#}G#U%!zn?!RP z!4{mw&)JT{?CF+aW0C;KK6@%fbNaE0UTuSf7~|O{OjiOUk6cnbf^XVbX8_i%@uvg# zKEQS)2!|mjBsal+_k6f6_m5iZzOP2NzI$AB0?Y=2XTQH(tw;OXj&ZqkuFm=SKB1Ic z`judhBRFQ^Vxk)&K_F!Gdf#ou14?8X#gV$8aQC5b!&aX#wKA5qk{RwO!ly zj9#S3fpfT#SU6nAV|8c)SSQA-8;&=4hf|h4AmqgK#I6X|Bi^JQUvhn%9ZFX#PLyfS zQu$;$zM^i?+bX!Uuk9@9_E&+n1OxbcWwm-2^nejN=dF`W8^)>>#Cc$L@=1?vuQ#K} zJjXsYEEOT{m5D-P)P}ys7UNH36m!HX{b7{zuY4R~4pfGV5Vi^- z?R147D%l%2-?es1+bV6G4n$6GRV^?5ko#`rA+~(xQE|GL`XUzQacBzeAN=zkHQF&6 z=utZ0$Wf?>HaxHaz7Vdtqw>KzA8y(;k}a|po=YGKccCDE^dDZ0NeGE>hyCRQSXcu* zjL_YUN!=4suPJ1@J6XnmB6T|AChiP{Y{!9n6(*xTCBh?gJ`=4!L#e({8F5LQ^NHK@ ziL&LBgD@%`@R`-CxQ8~aQh5hAwL^!2&`ZWw-(Z4`t~Sf4PcwYnqZbg3OF+Q)geEkt@yolEpC*~;%L4b=P0^y0Dri{E zl=}4S$X4s4+!}Hx*_v{nC%i({C)#4{GV~O3b$(7WKQgmbWK*gp&bxUUMh%oA%7c;! zx(&fgJb*6c%(FyzY$UeZKe>rJnXJ6N!JD1G?UfS-rRUrJPT&TM*qJ(ZaX>5z8WWQ`6I%l)iK;Aw#p*5+1Sy!PYF$v#d(F~e zlJVw4(QrzR8sIQTuC8dICuw?1O_$+skzN@fn3j6>>((^zdtd`qFYxpb#MsTs)|B4a z%*4#f(e-a%f?bi>euxQf>m`*Wh>X{X&2mDcV0@v-Mp(6_xIYO_n&b6-LtaF|W2_tO zZA9^^Dc1Ci7wWD=a55)8vNT%E`L&C86`b5`mbh@Gr4j_ zJ65U{1#E6h7CTW#*-{BOTl{*N7;L~W$q};8OAJ@KZk2m~CDWGEh{Nnixn=5U$a^A= zO6S!vB4PRte9wb~B{5?86_fMf1@v*wmE5ub4AJ5}vlh(B=O394d`*aR(u1JTT8v9r zL3rHzzfocS`UikN`u_mIfnx9PO3%dB>c26v|9U)O{2`4G2$4|*LS&f#^KoJ0ztYbp zuA&Zhc0k;goRz&95EbVRskd*QXR>sT$RK2|atttr;E?nmr)Gj75#sc3S% zg{HQMpgQRV8-`_my7Aa2dgk3ABO8PM>4BZE%xJx*DXG{s)S>6xfo)V)rc4IDjb7in z`Z(ts#~iDF@#K+*2i08|T5%Ljesv|JsXb_jvc~EXk*k1}SR{nW{^71p*sS^6?%T5T zV8311wA*T`81$QT2A9-60RnauX9iN(QV&JgCAnDW)U?=g28yZX9h1 z4vh|wH(>=d56jrEhB&k>6k}hs#G@_%vQk-e#j~}_c|~s$8l>GXu!-@Q5qW4bq?Vy7 zP9baCP`B5MFtnz^UeGm*exwy@SSJcJ)DF4Z4gKAUiXla+o&n)0)w7AvTpW}qSYv`& zqk?76l!rDUd?U?5-^216(?>K6+y4%a`Kv3kd^3wL19rhv;OpP=r+@X_zjZ++BWECO z`M)gC&=}#rnC;@9maRIl?nhk_HllM%XyD=lsKf3R^j4tKza1I)0>V*L^|~Ad?ga_W zx6eO3LC2B8p+v<(PHpYmcI|328ph=}W%RFXW+<)jH{D3DlYo0s5p2!#vwpyG3bA=e zX=7?d4IO&4$nyS)S1PhlgojS^OsZ=fKJl+a5o!I%gVMbs(vnXp=`(IHAB$6n9ncsb zNG$LC*VuRX-}IS2|29vlh(P040EgWZ(Cp>=&tdnUzg6DK#l_0rLecTBUAeHc1@JC{ ztJ%Lo52^Z!i-u@ppK}~twdbY;TmTj2*_F z+fm#PA_J)+(%V7A-EbD*%_SFH+0itLOKwFV^KP}}AAF~R5Oj3rL-k?hh-5bMKQR++!1!jkqtL^Suy4@riZoUe8XE7$ z+A@PJ=Ggr#^=c<&YFv@04~jUUH0sGHVz?)aA(1vhA^T+FCUbSFd||7OKF!UQ%W|L1 zlH|Rn)}a}Bdt4Pn1kx+m;01gyQ?5ATDuKH;efTP!i#%~jMH+JT1BZ6E1>04BN#&-a z^mlZ|EIqYo+&X#tsZRPZruJ%=FcPFOTQS$38cIz12< zafr+!DU!R3L|QFevX%8LK!)!7!nOhBhx8JsGci4>SQK#wg9Y|l-j8v9a|zKb--pe0 z9z}#+pcP>7@e3)(&HZUtOuf2*HNL10U-S_rOb3-W zA_>?co@&@>0BiVYGd18;U)yS!GB_x8g-A9K*PdgQWCz0*v*aSTM1Db~H3GlG)EE?B zV0{pydHh@2{IAj8QzOrk2pj>yz=enZe=`F9+4WU{)|9;kaC|r#0b!;8Rk0vfZB7vt zXi%AVnHkv?-W40R2I&+knNkx0(;Ov{(2dBbaFN?(mt}C;?h{vO&-MKi*Zm0W^j^VMae>N7F{0s;qZ_VIIQ_r$h z9*c@o4-2IKHEx(qoR%+WI6r9*FvhBs8vDM?SEsX$tK3S>qT^&UD1elw_C{3!5x!s{ zb)5^o;Pwcn$P?S-?L)$c+(95}yy`?(ZwtHA4%M#h)El;bBL--j&Z3teB!Dfi%j(6* zbMWfiPL+ZCPQRtR*y(d5l>@Vgp)h1iDho(_(dRh`TaJqI#VklRAVz){U4?}j+y2M`Cz>QTWQY@ShknOmmvx?1yyXUGYQ`F`W9!lr`sLpz}*LTSh>tk zu;`0abx;gWkzg*Re=^hHG-TDKQbUh101Z*ryRlq z#^aZ+M`Rsa@7rrYR~mmXb73y&tnRwYQ66z!YoCbs6az9N()WU8E1qWzN0(_;xo z2N_4Gv)^7HXss5i+d}`v13>Y(7sNySYaci579qrj5@O6fN8)SIAws85Ec`7NbpZfOv2}_eoGW zf6!~8zan8JrZV#P4>c!b_xLdIP+4wsaP@px_v{hUGDuf6tJ34C0145mj)@av;@q2% z-Qjea2NCfx9N-W&*P?+Y7$cHm-LqzKIBH7(hI%!MG${%`2E$Nj?4wxMbf`Z(ZNgmrq%lEI&U{$r`9UJq$r1&h=dm0$7>>A_|5#75}Pz>>kxzW z`hYb*5}F3b*U$a!nzz`!cqJ!naPbipM_$e0c7&kuyOOzj;Wew2i^@cw6|S1a0&t4$ z)!ThJdyCeY-@p%OaWMMY+ypV5J2YJx1#jcD=)NlOH+TH6RuROs{2T+q>cWBLWd2t( zkgPqhTFgJEp?@lnzb(Q5EgMg?BXqwXrpekAU}2#kfg0sm38pTHU!vz*h>J?XgmC3z zS~iS4$YB#}#Yo@Xc^TLm z;2G$ZDN17@nurV{W3TR3z(II0KZG*%X$3OwP06{o%kBRd-1H{%Q6K&8!yn^qW;^7| z(iiA(H_>hi4Ez}lUWeWCk8XVnygvBa^R6@)|NP8FC`fdGMUZl1g6-BY_zdk&>E%Tg zlYjSQgdM+YA@_C<^A7qX`%GT#r8Za(w91ugN^G=_18i`QBSMlx*3&}^?dq-0+!aM! z@Bqk`m(3T6E6BP)TFr{qpyg%b=qMZOwnfIP-;BF!H$}F8xKL-k@b1}E!z-VdK617s zhT*N+a5Gk9>9iBOX1Zfkhc7B57V*5w)(YKs4mUm7lIOHk-|$waTJ|HH$Q6Mhr(d=s z0nEnM_LCF??67ejuWupdaV?NfSH@0P6?;o9`hSl5Amn-%nc&-HcSU@i?#v_#J5Hi` zzkAKvVxd9()^fUAL6=*|$Kfs6{MsT4Jt+2ClaYqCWE=eSg=KgfMav`ENo{^C6U_owA?QYOko)Cc&$(R8bTXW8G>m{#{J^N$~iv2 zv((|Tgn2B`9DwggETjZqnGSE-Y-=svvUomSg>f&G9MG`Ubi{Y3T8oUQJ{4&X5{83j zW3X4{Np>fU{3ZO{4n8&m&7=9DQM z(t2Wu!ps^=4W{(B6*27Ca3Pqb=5xCq75J;64>!*&lC|!<5{1!Z3~)m?!_1l}47hko z4Bo>S^hd+^jSZY`WXp6wE?Y}<6)T*!^_jjf?meOWDcFs_2o~HEiM#%|Q@&y8{+RO= z9}w@MY49T+sY^+WIOq7i23FivwafkC3hqId8MnIZBylhVL9jso;Q*}U> z?%nQPeQ*bS$vCxY7iAl{;}Pu9IxvpBEe@}28NzX9>P#3^e#(mIp$wDJH?V8Jm&KB8 zX~T-X+!kxGV$p%|MgsprSIh0e7TxoE6-=)K9baKK=~YE}b-F?N7IxUY4qsmYZ*7=C zE)>56AToqK(JTJ6F%8aw6Z6Fkb?8TV{{T4`>F2FM6&P)cmYhdU*5fRP^*X=oN-8!8 zjHmNn>74;S4(x>0ukwdB&^X3FEl05s(fs{teQ{2hzqWeVAX(y!Ij~|{5?{mK3*Aj9 zDt-y1qHi@I#~?je9x++OVkG*|nT=E&-)xCOW^Y^A`HK3fIF0Y$zU-An*>(z83Y&f; zm}eX4AG25(Cr3VM#63Nd!;uGK4Os&eS+vu^K2eXL#!H_Hvg7vTkJeF!E%`Ii#A^r z%`Fy3RC0$*j!3O1UhF>f1F}5jq?W*=G2yPTtw-e7#-mb#;kIzTh+5!*>f?bbHZFO5 zpCC_cRCt3G!la|A*{N3z4nu5SD4QdK=5)c`$f#9~0-@wxJT!wt&PWytTw+0MIcxjc zI02HPFp6UG@A5|N9N~0NjNbhkk6^dH$7%T2TPwH(JJ7F=E`|q4+KLAp*3z<`z#u_| zxo@);B~xUoi7k_GsfmXQW?5Rk{+s2zKIOMxTUeOlSfUT1I)=> zID_!EpNj5I@9iaYgzpH{qKVXZe#eJ+P3R6Kx}h5-y))Zy@$KwqLcX34VqDP2 zg?z%Pz_X&vvbNUHul*ipv>Y86OQhP#aj-p*XmB5ui{l5gw>jumH9txZ0j-Ac?AoYJ zi{`aVaSdvET8HB%d!NNuocf91`U|`4wH^-lR(pfYy3?97H>=O&rfu9kB>!XyhUHZA z22vNL4O`=S4MjL@Gn*FIZueakWt)a-58v%*MugdRB#h3g&Y(>X;0!;<^^?~meuM}u zW|x1+Q*VXKKBds{y0gQ*vA`KlRJpVmBi;d)MqmFah={G?qtizhSIuoZseOyw&`3cRn3FoyWJZ&~K8Id5KHmp7G~%1IVgSgcnvPXn zLXJTAO)&VE;D@Vy8TU})q*RaqBR=qaAsXe=_uTQMmb&R2Vy7>+u)LCYlwAzOm$U8_ zDTcDaARxB8#*7)?2XROd+n-&!{;z&sNjV=X3<~Ji=abs?<#>>zFMh$t1Bdf=$Y=!j)Phr{Df>uHdf` za%j9vxd$8}_COu|S9Qt1iah=+SMWc3cIx&v|350aSA9waxR2-OpCB`05rRUx4UM3h zK!VyUB#9s?EmcR;32ic5B~v{(H4V#>OZj&5O-~9vo(9t|;B$9$bubo}v#X(pKNAL7 zgxqQGc>8MeDW}i(YUc3cy8RmD&`DPq?f`~|>8EgY4pZ{r;mANrkkz!96MK{mob&oY z9>EBn=sU83{l3K6 z?mZmw6%O1)s>M6Roc0!nvrV4O1|}zi&<>x3Kq! z#R~S|ltNO$F-z;SjOgTWzMN9(M<>P4{Onzwb56qw@0N!$H`U&m2q+(&v2 zeTpMWM&6Fu>9((dfpe^kbUVKaXYP7IgNZ8eEc|S9J1N1NCD*E5G0KE+VcV*}elv#I z;DFS5a=Xcu*_acn|K?1Pt-;HE+o7q2pIXi!gW9MJTSDi{;?zn`lX3Oo4$LSc zHh?v2SQh*jQA$RPYkO~oZzmd|j~}t4tzVWKX_>_c2N7Pi!V=Kn3)NLx#-EnR?~tX6 zeAya5T4;YV$n||Q`I^wu$RE;jK`^-SOmK+LlaN4?9VEy42btv!Jk(c$^DRi=5xx9W zt{TMhoWb;uj2`t1t+HH1k%bdO2al|Qsr24zt2YVBU>~sR)^E05Gp_gnkWAQw zrndO;Y|`CpH^WZIKA}mq0hhzlC|v z%QcaD$&x&~;hVK>Cw{HPtAN0yn%zKonqtx`hFnQlbRaE+iFDA}v}V z-l#6AmZ+zFyztih0o(IXdsK?pqB>YI?fN<_YVk_>D!Sn(sbRX_BwLmoIh(hf2XOHC z!GA~S|M`j=kbY~2$IC=+!V||K=Vr*eecBIa9{Nz`IZf^eb`QNZOn>VsJGu$I6-Hws zEFlm#dsZ2gz((9lT2kamH(D^}C`q*wJAhP0?zDo2C@Ud7>WyMreR!Itoi@+zC)rzl zOcQ5+SjJ|dB{G&`z@}bqY=iQ+@&mup9)6kbxC~F1GkS>9OGNq7*i4!=_t#f)f(@hw z9QGyWOp0tAH&SdT7UlU#FI|rTDXB1ks`k80TbgF*M2&U!l1#+8d0&%I?wS-QRF|c0 z>O##Goeb9&)J9WuXHhK%9DO?H!&XIWOG#F!6JUt~Fm8|X69`1iO-51q1roz7*}M!P zic64@h=kn=lSPHCsGydH!RD>ggW6x)V?ABb#_*WOV(n$s`s>5*i=I-Q>R1yt`##;- z#b6$$NlkrWysU_#uVY(3*gRc42L5#2y2cW*!BWnII;fo#VhB}Bz49uFt+6tF{$mHJ z5fwhkY`@N#GoPzMf{nc7+oBDNDkxW`Gv&P?F4LkIob5Nm)Jxwg zX4aHChHSE$OuGW3;?K?6c$bSdVIGZs z1S#HB27!sZ!sSO_Vm>f`vk}=bBxG#Wg;~Hd+&i)Hz<2v*tTv$etTVt#;=U72qaN<# zycd_|p{Fukv+w?GT8qb8YKzm1kdg~ZV5e5nYPxaU@9(>VcV4NIg3JtyJ8X*kH=9FM@Z zC+l3~VHjTBwf#oPQM?lFh^_r3c}esb&GJMh`9wFjR9ggv$?jQK_=Q`_5}Rowq&u7) zA@ETMjB!IdhVLUIrx_#Q>V&L@E{gsCyhd(sBp$dR8v9(8e4=&DM-v=3Wov~+9`Thj z>-304!_kK&?p|kp@MRunYdU5;N5Dujfp;t@;E~^%q@dTS&o~LzYf|SHq+4rnUxm!@ ze7S72NpOj#N_pEVP^Uca0a2$UUFr=>&P%q@gMi{rMo;y;I6?PV2II?d(*LbC<5SbL znu()P`0J@L&v~e4wj9bO2FGYIaXn(#x}Z&{K$I^J*6`{ERGJI0H1TS#fYAM%#myb8 zJU5YVFu1|$+Vo5RpvK_Ig-W}T!DNVT_0XlHd1~z$e}Da|&&)P!hJrKNW02|>%ml$4 z$8V(G*tXuf36{1ckUS#t0gchMVTP;k>*4xz^M3Be3D^WidG*N0+JE#%x%DW$jvW(! zh%iD-)_XyZI7Yjl=z->pK`^$e4j8zHSFsKlD72lHX3*?iki6))xewC1bGpPhEA)lq zd4)*5#lwqb!z^`g)<2aV`>nMT>O5!Kot-$}A0`zZ9%pXNU`*iOB+0(X;oJ#LWR9bj zh|JnAX5#ddzIl%N5w`dW5d_)ylvQacBS0%HeGNj@m#8696+oOFWBe4`h3xY}Hd*+Z1 zyBs&yFsCH{EdEiV7%K1#_F5d}!SMwd*2{;qCjx&8_VM;ZrTP<{$cCgM85eM(__MH@bcJ6=dm=#ccqr7-8Jw6o!Zdbfw_ zsnb4ExXMSWWHC1lLm***GtB`VO z%U5+KGz0yvOTH)u_!l>vbgao_Nh2zGl1}pPgA5nxp(Yk2n*3c5A*RgckNyKM(t*M2 zDW<-kfrw})65!9zP#rBCbR``Tiqs57+#^LZm~<{?bbcbIF(d0gMxsdvrTAhs8q?Bh z%irOx5hu+~ZH;DsCsNWO`B8`&J^q{3uj^@_kpdLMW61yGlKzhtH~pL8|1W=EbKM_T z6aA0G=Ju0zj_CQ=_SD~{|+2QwopFktb-d*Wl!xd5!dIwlDA z%(SgofEotJ8i*8waj2Z;L>*Ys-7s8CGNe#20;r^D44IPF8))(b24A(Y^JNRrB|tZC z^-%JGF^)OPThKnFv1pdQjNL{?^7*)QQy=a?dn_j(@t$vS2k5tc>Xtne3V!U7^?OZP ze)=FjqNC?dJ&8hyeVN1Ap0cMtvV48?1P&9=aUqxH>nrlb&Zb@~ZLY=Rxs}mpNjzGu zzZZ5}bO;jXS*kJNm+N%0LXu;@NdnBI*`tCP`o~kO(7#5f=}=h(-;?{^I4xIMhC;hI zDYL_JO_e&#G zXMsC$z2F9v*41^YEAUSnT}7%6|K&J`&BM>^6^P~P&PDt3L?QxQ&NLg!?j|<~UZXUb zjh>-)uHIf#jPe%p+QTOc$%dv7z1?tmP(r9SY`oV_croDG{{3q!I{VvcSZ7k5y5fiF z`f5w3G|1+X$bc|kaaz>|#Y3}RvFz0o#@Q;AKabGU)zPPaNOgy3t9gC7)e3mQ;_7gX zcI$DgNtfkK9L4j;pcO>;EeEtd<*yDM?cLBKLy)&@0mmEK9tT7!t`IPkEA3And+oC( zBCP?*8)a-w^qyc3GatR z;-d`X9c8;b8t6UYoM#Da3q=knShMX%;!?BH?XZ8XSZxfb6X+pv4QDCdLMAQpAhBALYJ-~;FpllJdO5l2^PS-G9si>ya4%QC5 z6zKLm3z-aPlpSRW5pOiDDgDJH6EN@*p@a28Z;0#GPyf6Ut%h^d{PlsD>_s4kcycI! zEr7}Nswb%%g4zSOuu~UmM<~QN#rOj9(2ZH4G1Pb;GU>xciA?TfwLyMRJ*Olg=| zqa|;c|BPjj?{mc=IV3%!dZxG&436d26AOQd+sE3Kibob7gr0=ixtc9e+?STg!ShKH z@d?rhQSk2~eWY}q4Rwi;?F-Fqc0nelz-Oiz?m+qssIx(cfm-0-IN-Xc}mg#q#!w}_a~e*h(CN?ROBur_UilBNT1if>@_!z{O!x0t|GVUo3+W@ zA14m`e{2K*Z@H7FqIle7r{Zbo=@zy4rt?E&zBz90IcN&b7Fp~Rd>G&sjbGzcqnZ{Z z@K{I(Rr9A8OSBTOPbL=SL?TYdZo#c!SCQ#jW}m_HONWIokbQ!9Nrde>|74HnpkJ`O zeihOBZ6(JAGngxhH^#FC)`x00{e-ngmh%R(=E-zHW~8_c@hHuAbaW=)2La{_zNxxO z3}{8L%AaUtCFqH=G<5?u!cesz43AV%MY+97V>sDGX?^d5R>mxHOEv;@aFH3SAK>xj z>S0f{=IONyoj3o{>I074z}?^-y(lC!&Qg@8n^WvWr~KZ3Xm;~7Q}#NVYk7+i<`Luj zXVSO&jTTg+K>0G|J|Rj>JW5su!(34YLF%>|%U-0T`;4ay9M=r6q9SRIHnGY&@*;u) zT=77~SP1|X!SALDC?ttQv)_6<3H>axZz}qr=sUs?;$y;0AOKOe9`GysT{DRk{q0Ok zUpD53D~CyF9l0Eu@`a>)dXi^%ciu%Q=Mw0#6Eq!snc?;5=NgMQ__;?Ve>?Zr-^sPr zgk3BRVR{jp)XMF858=b$A1B{W?V0(9h+pUcUUBXH_c?Ej&sUfGRK9D}W#HaFG~`74 zrbOe4NkqxNy4?EzccUv>nBCR~DC%H=qK@Z3jV>i;2WvAESKyl?FdJ!Q=JK~C{@((V zxk<8$gFK!Y}6IP!1b~{ZcLS=4!^{6hgwHPhVhk<(zNjikyGu; zY1l#`{y_k#UuUnq$~mhe%QOAML`Lj>ZTd713n@-V#jCA6y7qU!#Pp-~={kO`*lFhJZ2T$ts@(Gy zc?#+ZWE{$ETxc8~P58ISilbh^-zyP3R3zbifg2&l{xZw4kIfMp0ERGU#<@L|g^%D)sxqxwKkG3&+eJ?NY{LDKt*E`B?e0nN%2 zpNc%S2F=P8r-iO~@t~~y{cjN@7F*3W8K8Ly4zyq-{Y_$2X23E#X7(;t zu2$}5|8o|pRP~>MSXLjpUE{>IXYG-wG{)}IS7V}B8DkMLYmvpLFOWIr>vrzxz_N7y zyCdmY&xZeBXI}wS$Fg-zaCdiig1fr~2*EYz!QEYh6WpC3!3pl}1cF0wcL~8Ef&b*) zDfKAd-vL&my$Rq^mxzUAkjpVJ$6PLcSiYLE_W(yR-UkZ z;sXOyV3FFR@Z)cdM^JWbFweGLE%NgUGLq${cY{$J5ywaG8{T>E54f zqeQ;q1l1*gk~wiljg2Hgo3$pabzQY_J#ng%J!;JODW283IgWKLwBrIOy1OA&VFkC6 z6#uE|z}?W|Ff@mu%&&~TOFocwN<|R*Lz1o;f^l3Yb|7z4pKhZE?dU6GI1|f}n2{~1 zd{ORWjco10oI4Fr`qxNB)j7D4*y=m5cX#(i_~0X3A%LAM#HVPICbxO|9R@;D^>sHA zN*{918HIuz6(R{xp4Fn3wd*+HQZL++y|ie&Bg-8+Uo7H`wuvXS)-PIYlV^$PWJiNC zP38ipNokfbHbB#Y%w%r)vcmk*Ad9o7vbLBkXz9Y7*-|2Ed+sQLU^cEvp!+fmDi11E zHybDHU{@M7K!9^77l{e6+$lFhnm3#tfhcre?Gxjst&y4BKC!|&&&@WzFT!R{7K}7D zMHDmvRa(U~BQo#&O+?S=v%Axe{xlURe6PqA$hujX8gZ&rcT!MFF6$Jb>9*|R_~c!f z?BMEAhFfz}U2;=xP~H$lm(6$+D;7RL#8xL@F^>9$qiQVnwpNN^@@}5uONAPUeetJ{ ziq|Vipnm@Zt_vJRAny#@S@a88yvQ9kXO{ripswiaWA7|_`=XU!Ezqm{8Y~l35Rg8g zBo^hr7_Hx(g&J_K%G0&FbZ1;~abV;zAOU=&NP~v4AR@k>Sj3d$!I_|gf?cKLWBmr7 zC8vNWzRjJYy-+O4)$>v-DpM7g4pA&EJ29{-@mdnFJUO~p)>`ne@mO%T(AsOiOi6kF z43YA3W8;wDqoQ?Y{^0ba)@Aw2bt9S>Te!mZ1mdmF%@=V2qQRXC+^-Bt_wqysn>k86 zM|u-Qp&A?b8IEQ;JUE9lAG>u^X4o#x($o5RcJ`Dzg5+=bL^fi0Fizj{jqdpKJ>6v8 zWYydt%|QHwO%ye4#uqg?S20OWc(TE|bp?L&3_VPmN2fc^OPij|WY8om;@QP1FrI(X z%d@VJ)e)8{d=oWN)~VRw(k`WD>od$i80?KQYyj;VuaZEum_n_!GhtS@!=_U9sdfgY zLv7!gqvp^VyKc5!r2MdJj(ly4R0yU;i&)`VFRZLn({ljkStIW3zT-P4?LJ_(9V%6B z1wi7RX`vMNO98B1Pm+r0WpUh>>5>Po`B4Y#*3rkbD2?;|7Gfu|o{QA&v*w;f@@mi< zPTIt+7wciZ=b*SRw>Kz1&O&Bry1hB)xN)sk-?7iA|AfJl)-v5ck_+=?Jh!^HOu#yB z&^a>TS&vaEba0ue&Ok(ODfVQtO2(-k`66}{WVe-5%xig8^FA`g$a-eEa#q8cFx&UA z{r;z`@^on-G%LCpZPvV#4YJ(}-7z})9`?03ks9ND4LJ2|h{Ef=g((Mmw6@rYtQgZ! zhRh*#CKhk3%wau>tRl4(J=hBD0?lf0xdpK!d-0m zbpTUC(cydp!`L0(k&YJ38Sl(5<}pfe>)57d7+0#AoR8+WlGvDT)T~)uQdM+L_1@B& z*J?DEsHWMOV(1RA(HhV-m+}r8D&sn}euPO~?95p~L;h{EUleH=G50V$1 zVlZVn;A(N3cBvR^rWrU0Lnl4iyvu}vxJm;0HgzUqp3*WEfik3wf*#R> zlQgo)+Xvw_N*5am1J z8OCP_Ce~>XT3_H0~$ijnyU%D6Sjpj2~Bgmf@dKA=EqoG&>1y)x=jEK*7rD}S^DB}hQ zF=|0<%7!ooW4^G}szMs(7Fje;Bh1a21vL>*8NS+3ylGvu4rhsROT|r8i79UY&wdj$ zAe1gju+KGMWan*<%|^x=A7r12TAu|7@l#h$DXK+ud&isIb31v|!?p-`xm2n3KGo8wS zYrS)AU6?{20&2~(k&p&e8X}etS5Jb%hl~tmGhE2yx)-MkM|YKJ_W=&o7~yhhybhF; z=dn4$+2{~LqsJ*=bUVXC4nfuS&&Okp-U+F1Qh2|AQB035&@J5i$_8ckNJPXY!cja; zu^Z-f6i!d>3v6shtR<^4;ik!K#xX0%C1DqqNQKY3(-xU9#J8iupG zThNHyp9@@pAVYDu=HOWLQ`)Wb?oz|Kn6)gdTDMJP2k$W#tmnKA5I&6Q!+mM|iExC|`#Q_7`G7qfgzQ1FMXa{E&iOQRbdKs}<1omQaX8905cd6_jA4Xzdi< zZ5eB;wTi?30Vx24YG1qt`B0~J%B+3_Z~ykpMHA4e?uD{MW!q6a%Cke+^iGA(N;q0Y zkrE@;+$?O~xPBarNOuvU@A;w)>G%lu3Zi*QJo4H|r2^ zl`6gBGH3KS=w&VF2cSb4_5z@x$0l?Z{Yi-}Yn8(=8ADUr%|6wWSd(`DC0W9Eft>*L$-HSn14w%>bZD^7d-fm3l-4` zi&L`8juks7H{%F^y$}kS7M`}S_6`uJ4u48hrCe<+u|)-0dgK}TlJgot(MV*lAm4+- zNmm6AbfpzfsWprtZCD1uI}W8qDJX(M8*!8%)^uPe07A5iYe}}tc75q4!_Vxpuw4=X zDoo)_g4xB@mS=a+py4L{t8FLxHCs~t+N#&~8_Ao!J%SgEUt9KG_m;gDMuNGtYq8BP z{lN29MMKbijKL?MY1)s_P~_LO4b%84=<0CW#%V;qH3{F;mPc@((iXJFhC|pYNirLha=m ziWUV2_($N^6X{6+NVBcR&PvrC*pfYu4&tdIZV)+e3KCit%B+nuW5D7r3e@|_p1`zU zPg#WJo(g~Axr^)#FDDSVq#Nvj6LyD&e{!(LNQ0Kn;z2yeSC&(bU4wgMB!{2Z9kJAN z*Ws^_ZvlADn@gr$Ub4>u2v*fR%{p~?gQLg9pj2EN-BI1^#3Qh%l(BogoA?PJgXr&x+lH>C92l?8SlWFcWC)kZ+?5RUbt!(Sq zryv_5Qk0rOC!m!jZ(tlVQJMMxvB<=&&ATKabCO7tNz5h|8E@X&4-Z964iMsAD2J7) z?bXvps#u4qJmnXOGPsAntvae$eds>NZVW6sAU^*9hUX%<#d)D5tn{&ZbN`J_iE?47R1)`oW+`S8I#;$P{Uad@unh>s2eaY;C;b%KV z-nyF1qtxJOT!UT-Ut1^SIY5qt%3lFnr{QO-?K`--9AiU1eA4MC{(SFhlkqsGx}=rE z7=;=DUA8^@<$9}4q>Q067q0THG6Rq7coRR&i^>a+7Mi9($)ZCh48JD)sbHFlEYMHN zz2WMhxwsXU3nxc!hVaGSW3O$=Nh!~dH^VHmr{+$f#^2H27QsdUFh}=uK8o-)2am=$ zn@4^)ImqD-emiy|YmHSr_5>$$VYO(KVF)8mMNsVQ9o?5$uaURotQz|;iSA)ri$TCR zsLiQiNmClfL1{HkW}mZ>+}ECb)w#jjP~@4~w3)A8fUHEaz2+EK?r~+% zk;fXx)Ra|=4)s|uqjOSX)sbUxMAMLZrz)m_$1i(yjta5YTodUHS$st;M)U$IBbO;E z8#*dqK2wUfAvsrD#x7G*XHkmRjqGUMYHB3Ik>Vu3}g3& z)=B~1HCR)Oj{@fz(Vpr(-BKUX|vI^z;|Im8utLdU7P7>7q=#mOqAbxsYt{Rm3BqNETPDs6;sC1)9QN< z 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 literal 0 HcmV?d00001 diff --git a/tests/ReactTests/android/gradle/wrapper/gradle-wrapper.properties b/tests/ReactTests/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..b9fbfaba0e --- /dev/null +++ b/tests/ReactTests/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip diff --git a/tests/ReactTests/android/gradlew b/tests/ReactTests/android/gradlew new file mode 100755 index 0000000000..91a7e269e1 --- /dev/null +++ b/tests/ReactTests/android/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/tests/ReactTests/android/gradlew.bat b/tests/ReactTests/android/gradlew.bat new file mode 100644 index 0000000000..aec99730b4 --- /dev/null +++ b/tests/ReactTests/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/tests/ReactTests/android/settings.gradle b/tests/ReactTests/android/settings.gradle new file mode 100644 index 0000000000..96e526a0e9 --- /dev/null +++ b/tests/ReactTests/android/settings.gradle @@ -0,0 +1,3 @@ +rootProject.name = 'ReactTests' + +include ':app' diff --git a/tests/ReactTests/index.android.js b/tests/ReactTests/index.android.js new file mode 100644 index 0000000000..e5a52d27d5 --- /dev/null +++ b/tests/ReactTests/index.android.js @@ -0,0 +1,52 @@ +/** + * Sample React Native App + * https://github.com/facebook/react-native + */ +'use strict'; + +var React = require('react-native'); +var { + AppRegistry, + StyleSheet, + Text, + View, +} = React; + +var ReactTests = React.createClass({ + render: function() { + return ( + + + Welcome to React Native! + + + To get started, edit index.android.js + + + Shake or press menu button for dev menu + + + ); + } +}); + +var styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + welcome: { + fontSize: 20, + textAlign: 'center', + margin: 10, + }, + instructions: { + textAlign: 'center', + color: '#333333', + marginBottom: 5, + }, +}); + +AppRegistry.registerComponent('ReactTests', () => ReactTests); diff --git a/tests/ReactTests/index.ios.js b/tests/ReactTests/index.ios.js new file mode 100644 index 0000000000..f34574907f --- /dev/null +++ b/tests/ReactTests/index.ios.js @@ -0,0 +1,56 @@ +/** + * Sample React Native App + * https://github.com/facebook/react-native + */ +'use strict'; + +var React = require('react-native'); +var Realm = require('realm'); +var RealmTestSuite = require('RealmTestSuite'); + +var { + AppRegistry, + StyleSheet, + Text, + View, +} = React; + +var ReactTests = React.createClass({ + render: function() { + return ( + + + Welcome to React Native! + + + To get started, edit index.ios.js + + + Press Cmd+R to reload,{'\n'} + Cmd+D or shake for dev menu + + + ); + } +}); + +var styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + welcome: { + fontSize: 20, + textAlign: 'center', + margin: 10, + }, + instructions: { + textAlign: 'center', + color: '#333333', + marginBottom: 5, + }, +}); + +AppRegistry.registerComponent('ReactTests', () => ReactTests); diff --git a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..b872f486f0 --- /dev/null +++ b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj @@ -0,0 +1,745 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 008F07F31AC5B25A0029DE68 /* main.jsbundle in Resources */ = {isa = PBXBuildFile; fileRef = 008F07F21AC5B25A0029DE68 /* main.jsbundle */; }; + 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; + 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; + 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; }; + 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; + 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; + 00E356F31AD99517003FC87E /* ReactTestsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ReactTestsTests.m */; }; + 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; + 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; + 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; + 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTActionSheet; + }; + 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTGeolocation; + }; + 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5115D1A9E6B3D00147676; + remoteInfo = RCTImage; + }; + 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B511DB1A9E6C8500147676; + remoteInfo = RCTNetwork; + }; + 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 832C81801AAF6DEF007FA2F7; + remoteInfo = RCTVibration; + }; + 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 13B07F861A680F5B00A75B9A; + remoteInfo = ReactTests; + }; + 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTSettings; + }; + 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3C86DF461ADF2C930047B81A; + remoteInfo = RCTWebSocket; + }; + 146834031AC3E56700842450 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; + remoteInfo = React; + }; + 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTLinking; + }; + 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5119B1A9E6C1200147676; + remoteInfo = RCTText; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = main.jsbundle; path = main.jsbundle; sourceTree = ""; }; + 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = ""; }; + 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = ""; }; + 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; + 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; + 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = ""; }; + 00E356EE1AD99517003FC87E /* ReactTestsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactTestsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* ReactTestsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReactTestsTests.m; sourceTree = ""; }; + 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj; sourceTree = ""; }; + 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* ReactTests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReactTests.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ReactTests/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = ReactTests/AppDelegate.m; sourceTree = ""; }; + 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ReactTests/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ReactTests/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ReactTests/main.m; sourceTree = ""; }; + 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../node_modules/react-native/React/React.xcodeproj; sourceTree = ""; }; + 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = ""; }; + 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../node_modules/react-native/Libraries/Text/RCTText.xcodeproj; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 00E356EB1AD99517003FC87E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 146834051AC3E58100842450 /* libReact.a in Frameworks */, + 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, + 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, + 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */, + 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */, + 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */, + 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */, + 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, + 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, + 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 00C302A81ABCB8CE00DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302B61ABCB90400DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302BC1ABCB91800DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302D41ABCB9D200DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302E01ABCB9EE00DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */, + ); + name = Products; + sourceTree = ""; + }; + 00E356EF1AD99517003FC87E /* ReactTestsTests */ = { + isa = PBXGroup; + children = ( + 00E356F21AD99517003FC87E /* ReactTestsTests.m */, + 00E356F01AD99517003FC87E /* Supporting Files */, + ); + path = ReactTestsTests; + sourceTree = ""; + }; + 00E356F01AD99517003FC87E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 00E356F11AD99517003FC87E /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 139105B71AF99BAD00B5F7CC /* Products */ = { + isa = PBXGroup; + children = ( + 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */, + ); + name = Products; + sourceTree = ""; + }; + 139FDEE71B06529A00C62182 /* Products */ = { + isa = PBXGroup; + children = ( + 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */, + ); + name = Products; + sourceTree = ""; + }; + 13B07FAE1A68108700A75B9A /* ReactTests */ = { + isa = PBXGroup; + children = ( + 008F07F21AC5B25A0029DE68 /* main.jsbundle */, + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.m */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = ReactTests; + sourceTree = ""; + }; + 146834001AC3E56700842450 /* Products */ = { + isa = PBXGroup; + children = ( + 146834041AC3E56700842450 /* libReact.a */, + ); + name = Products; + sourceTree = ""; + }; + 78C398B11ACF4ADC00677621 /* Products */ = { + isa = PBXGroup; + children = ( + 78C398B91ACF4ADC00677621 /* libRCTLinking.a */, + ); + name = Products; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + 146833FF1AC3E56700842450 /* React.xcodeproj */, + 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, + 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, + 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */, + 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */, + 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */, + 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */, + 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, + 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */, + 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, + ); + name = Libraries; + sourceTree = ""; + }; + 832341B11AAA6A8300B99B32 /* Products */ = { + isa = PBXGroup; + children = ( + 832341B51AAA6A8300B99B32 /* libRCTText.a */, + ); + name = Products; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* ReactTests */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 00E356EF1AD99517003FC87E /* ReactTestsTests */, + 83CBBA001A601CBA00E9B192 /* Products */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* ReactTests.app */, + 00E356EE1AD99517003FC87E /* ReactTestsTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 00E356ED1AD99517003FC87E /* ReactTestsTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactTestsTests" */; + buildPhases = ( + 00E356EA1AD99517003FC87E /* Sources */, + 00E356EB1AD99517003FC87E /* Frameworks */, + 00E356EC1AD99517003FC87E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 00E356F51AD99517003FC87E /* PBXTargetDependency */, + ); + name = ReactTestsTests; + productName = ReactTestsTests; + productReference = 00E356EE1AD99517003FC87E /* ReactTestsTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 13B07F861A680F5B00A75B9A /* ReactTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactTests" */; + buildPhases = ( + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ReactTests; + productName = "Hello World"; + productReference = 13B07F961A680F5B00A75B9A /* ReactTests.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0610; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 00E356ED1AD99517003FC87E = { + CreatedOnToolsVersion = 6.2; + TestTargetID = 13B07F861A680F5B00A75B9A; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactTests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */; + ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; + }, + { + ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */; + ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; + }, + { + ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */; + ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; + }, + { + ProductGroup = 78C398B11ACF4ADC00677621 /* Products */; + ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; + }, + { + ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */; + ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; + }, + { + ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */; + ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; + }, + { + ProductGroup = 832341B11AAA6A8300B99B32 /* Products */; + ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; + }, + { + ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */; + ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; + }, + { + ProductGroup = 139FDEE71B06529A00C62182 /* Products */; + ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; + }, + { + ProductGroup = 146834001AC3E56700842450 /* Products */; + ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* ReactTests */, + 00E356ED1AD99517003FC87E /* ReactTestsTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTActionSheet.a; + remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTGeolocation.a; + remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTImage.a; + remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTNetwork.a; + remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTVibration.a; + remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTSettings.a; + remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTWebSocket.a; + remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 146834041AC3E56700842450 /* libReact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libReact.a; + remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTLinking.a; + remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 832341B51AAA6A8300B99B32 /* libRCTText.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTText.a; + remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 00E356EC1AD99517003FC87E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 008F07F31AC5B25A0029DE68 /* main.jsbundle in Resources */, + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 00E356EA1AD99517003FC87E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 00E356F31AD99517003FC87E /* ReactTestsTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 13B07F861A680F5B00A75B9A /* ReactTests */; + targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 13B07FB21A68108700A75B9A /* Base */, + ); + name = LaunchScreen.xib; + path = ReactTests; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 00E356F61AD99517003FC87E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = ReactTestsTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactTests.app/ReactTests"; + }; + name = Debug; + }; + 00E356F71AD99517003FC87E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = ReactTestsTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactTests.app/ReactTests"; + }; + name = Release; + }; + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + ); + INFOPLIST_FILE = "ReactTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ReactTests; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + ); + INFOPLIST_FILE = "ReactTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ReactTests; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactTestsTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 00E356F61AD99517003FC87E /* Debug */, + 00E356F71AD99517003FC87E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme b/tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme new file mode 100644 index 0000000000..a0d2883bd3 --- /dev/null +++ b/tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/ReactTests/ios/ReactTests/AppDelegate.h b/tests/ReactTests/ios/ReactTests/AppDelegate.h new file mode 100644 index 0000000000..a9654d5e01 --- /dev/null +++ b/tests/ReactTests/ios/ReactTests/AppDelegate.h @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +@interface AppDelegate : UIResponder + +@property (nonatomic, strong) UIWindow *window; + +@end diff --git a/tests/ReactTests/ios/ReactTests/AppDelegate.m b/tests/ReactTests/ios/ReactTests/AppDelegate.m new file mode 100644 index 0000000000..309637c4ca --- /dev/null +++ b/tests/ReactTests/ios/ReactTests/AppDelegate.m @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "AppDelegate.h" + +#import "RCTRootView.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + NSURL *jsCodeLocation; + + /** + * Loading JavaScript code - uncomment the one you want. + * + * OPTION 1 + * Load from development server. Start the server from the repository root: + * + * $ npm start + * + * To run on device, change `localhost` to the IP address of your computer + * (you can get this by typing `ifconfig` into the terminal and selecting the + * `inet` value under `en0:`) and make sure your computer and iOS device are + * on the same Wi-Fi network. + */ + + jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle"]; + + /** + * OPTION 2 + * Load from pre-bundled file on disk. To re-generate the static bundle + * from the root of your project directory, run + * + * $ react-native bundle --minify + * + * see http://facebook.github.io/react-native/docs/runningondevice.html + */ + +// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + + RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation + moduleName:@"ReactTests" + initialProperties:nil + launchOptions:launchOptions]; + + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + UIViewController *rootViewController = [[UIViewController alloc] init]; + rootViewController.view = rootView; + self.window.rootViewController = rootViewController; + [self.window makeKeyAndVisible]; + return YES; +} + +@end diff --git a/tests/ReactTests/ios/ReactTests/Base.lproj/LaunchScreen.xib b/tests/ReactTests/ios/ReactTests/Base.lproj/LaunchScreen.xib new file mode 100644 index 0000000000..fff23b24c5 --- /dev/null +++ b/tests/ReactTests/ios/ReactTests/Base.lproj/LaunchScreen.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/ReactTests/ios/ReactTests/Images.xcassets/AppIcon.appiconset/Contents.json b/tests/ReactTests/ios/ReactTests/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..118c98f746 --- /dev/null +++ b/tests/ReactTests/ios/ReactTests/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/tests/ReactTests/ios/ReactTests/Info.plist b/tests/ReactTests/ios/ReactTests/Info.plist new file mode 100644 index 0000000000..cddf0766c9 --- /dev/null +++ b/tests/ReactTests/ios/ReactTests/Info.plist @@ -0,0 +1,48 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + NSLocationWhenInUseUsageDescription + + NSAppTransportSecurity + + + NSAllowsArbitraryLoads + + + + diff --git a/tests/ReactTests/ios/ReactTests/main.m b/tests/ReactTests/ios/ReactTests/main.m new file mode 100644 index 0000000000..3d767fcbb9 --- /dev/null +++ b/tests/ReactTests/ios/ReactTests/main.m @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/tests/ReactTests/ios/ReactTestsTests/Info.plist b/tests/ReactTests/ios/ReactTestsTests/Info.plist new file mode 100644 index 0000000000..886825ccc9 --- /dev/null +++ b/tests/ReactTests/ios/ReactTestsTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/tests/ReactTests/ios/ReactTestsTests/ReactTestsTests.m b/tests/ReactTests/ios/ReactTestsTests/ReactTestsTests.m new file mode 100644 index 0000000000..c9770887b8 --- /dev/null +++ b/tests/ReactTests/ios/ReactTestsTests/ReactTestsTests.m @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import +#import + +#import "RCTLog.h" +#import "RCTRootView.h" + +#define TIMEOUT_SECONDS 240 +#define TEXT_TO_LOOK_FOR @"Welcome to React Native!" + +@interface ReactTestsTests : XCTestCase + +@end + +@implementation ReactTestsTests + +- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test +{ + if (test(view)) { + return YES; + } + for (UIView *subview in [view subviews]) { + if ([self findSubviewInView:subview matching:test]) { + return YES; + } + } + return NO; +} + +- (void)testRendersWelcomeScreen +{ + UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; + BOOL foundElement = NO; + + __block NSString *redboxError = nil; + RCTSetLogFunction(^(RCTLogLevel level, NSString *fileName, NSNumber *lineNumber, NSString *message) { + if (level >= RCTLogLevelError) { + redboxError = message; + } + }); + + while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + + foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; + } + + RCTSetLogFunction(RCTDefaultLogFunction); + + XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); + XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); +} + + +@end diff --git a/tests/ReactTests/ios/main.jsbundle b/tests/ReactTests/ios/main.jsbundle new file mode 100644 index 0000000000..b702b30c66 --- /dev/null +++ b/tests/ReactTests/ios/main.jsbundle @@ -0,0 +1,8 @@ +// Offline JS +// To re-generate the offline bundle, run this from the root of your project: +// +// $ react-native bundle --minify +// +// See http://facebook.github.io/react-native/docs/runningondevice.html for more details. + +throw new Error('Offline JS file is empty. See iOS/main.jsbundle for instructions'); diff --git a/tests/ReactTests/package.json b/tests/ReactTests/package.json new file mode 100644 index 0000000000..bd41b47cf5 --- /dev/null +++ b/tests/ReactTests/package.json @@ -0,0 +1,13 @@ +{ + "name": "ReactTests", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node_modules/react-native/packager/packager.sh" + }, + "dependencies": { + "react-native": "^0.11.4", + "realm": "file:../../lib", + "RealmTestSuite": "file:.." + } +} diff --git a/tests/RealmTests.js b/tests/RealmTests.js index 760ea37b46..d173620ffa 100644 --- a/tests/RealmTests.js +++ b/tests/RealmTests.js @@ -18,6 +18,16 @@ 'use strict'; +var TestCase = require('./TestCase'); +var { + LinkTypesObjectSchema, + TestObjectSchema, + IntPrimaryObjectSchema, + AllTypesObjectSchema, + DefaultValuesObjectSchema, + PersonObject, +} = require('./TestObjects'); + var RealmTests = { testRealmConstructorPath: function() { TestCase.assertThrows(function() { new Realm('/invalidpath'); }); @@ -266,4 +276,5 @@ var RealmTests = { TestCase.assertEqual(notificationCount, 1); }, }; +exports.RealmTests = RealmTests; diff --git a/tests/ResultsTests.js b/tests/ResultsTests.js index 7c953bb5df..9da420fa14 100644 --- a/tests/ResultsTests.js +++ b/tests/ResultsTests.js @@ -18,6 +18,12 @@ 'use strict'; +var TestCase = require('./TestCase'); +var { + LinkTypesObjectSchema, + TestObjectSchema, +} = require('./TestObjects'); + var ResultsTests = { testResultsLength: function() { var realm = new Realm({schema: [TestObjectSchema]}); @@ -100,3 +106,4 @@ var ResultsTests = { TestCase.assertEqual(objects[4].doubleCol, 0); }, } +exports.ResultsTests = ResultsTests; diff --git a/tests/TestCase.js b/tests/TestCase.js index 48761f9241..7a45d2f5f2 100644 --- a/tests/TestCase.js +++ b/tests/TestCase.js @@ -24,6 +24,7 @@ var TestUtil = { return path.substring(0, path.lastIndexOf("/") + 1) + str; }, }; +exports.TestUtil = TestUtil; var TestCase = { assertEqual: function(val1, val2, errorMessage) { @@ -76,6 +77,7 @@ var TestCase = { }; }, } +exports.TestCase = TestCase; function TestFailureError(message) { var error; @@ -101,3 +103,5 @@ function TestFailureError(message) { this.__proto__ = error; } +exports.TestFailureError = TestFailureError; + diff --git a/tests/TestObjects.js b/tests/TestObjects.js index b905a2060f..cd71e07519 100644 --- a/tests/TestObjects.js +++ b/tests/TestObjects.js @@ -24,6 +24,7 @@ var TestObjectSchema = { {name: 'doubleCol', type: Realm.Types.DOUBLE}, ] }; +exports.TestObjectSchema = TestObjectSchema; function PersonObject() {} PersonObject.prototype.schema = { @@ -36,6 +37,7 @@ PersonObject.prototype.schema = { PersonObject.prototype.description = function() { return this.name + ' ' + this.age; }; +exports.PersonObject = PersonObject; var BasicTypesObjectSchema = { name: 'BasicTypesObject', @@ -49,6 +51,7 @@ var BasicTypesObjectSchema = { {name: 'dataCol', type: Realm.Types.DATA}, ] }; +exports.BasicTypesObjectSchema = BasicTypesObjectSchema; var LinkTypesObjectSchema = { name: 'LinkTypesObject', @@ -58,6 +61,7 @@ var LinkTypesObjectSchema = { {name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject'}, ] }; +exports.LinkTypesObjectSchema = LinkTypesObjectSchema; var IntPrimaryObjectSchema = { name: 'IntPrimaryObject', @@ -67,6 +71,7 @@ var IntPrimaryObjectSchema = { {name: 'valueCol', type: Realm.Types.STRING}, ] }; +exports.IntPrimaryObjectSchema = IntPrimaryObjectSchema; var AllTypesObjectSchema = { name: 'AllTypesObject', @@ -84,6 +89,7 @@ var AllTypesObjectSchema = { {name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject'}, ] }; +exports.AllTypesObjectSchema = AllTypesObjectSchema; var DefaultValuesObjectSchema = { name: 'DefaultValuesObject', @@ -100,4 +106,5 @@ var DefaultValuesObjectSchema = { {name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject', default: [[2]]}, ] }; +exports.DefaultValuesObjectSchema = DefaultValuesObjectSchema; diff --git a/tests/index.js b/tests/index.js new file mode 100644 index 0000000000..e2150f134b --- /dev/null +++ b/tests/index.js @@ -0,0 +1,11 @@ +'use strict'; + +var RealmTestSuite = { + tests: [ + require('./ArrayTests.js'), + require('./ObjectTests.js'), + require('./RealmTests.js'), + require('./ResultsTests.js'), + ], +} +module.exports = RealmTestSuite; // eslint-disable-line no-undef diff --git a/tests/package.json b/tests/package.json new file mode 100644 index 0000000000..1516389641 --- /dev/null +++ b/tests/package.json @@ -0,0 +1,5 @@ +{ + "name": "RealmTestSuite", + "version": "0.0.1", + "private": true +} From 08fada74d644a41dc2f038027d5357ad39c2d186 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 2 Oct 2015 15:15:25 -0700 Subject: [PATCH 02/32] fix so that RealmJS tests work again --- tests/ArrayTests.js | 6 ------ tests/ObjectTests.js | 7 ------- tests/RealmJSTests.mm | 2 ++ tests/RealmTests.js | 10 ---------- tests/ResultsTests.js | 6 ------ tests/index.js | 10 ++++++++++ 6 files changed, 12 insertions(+), 29 deletions(-) diff --git a/tests/ArrayTests.js b/tests/ArrayTests.js index 7772853307..16729fbef4 100644 --- a/tests/ArrayTests.js +++ b/tests/ArrayTests.js @@ -18,12 +18,6 @@ 'use strict'; -var TestCase = require('./TestCase'); -var { - LinkTypesObjectSchema, - TestObjectSchema, -} = require('./TestObjects'); - var ArrayTests = { testLinkTypesPropertySetters: function() { var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); diff --git a/tests/ObjectTests.js b/tests/ObjectTests.js index d898f076f1..f5dbe48d3c 100644 --- a/tests/ObjectTests.js +++ b/tests/ObjectTests.js @@ -18,13 +18,6 @@ 'use strict'; -var TestCase = require('./TestCase'); -var { - LinkTypesObjectSchema, - TestObjectSchema, - BasicTypesObjectSchema, -} = require('./TestObjects'); - var ObjectTests = { testBasicTypesPropertyGetters: function() { var basicTypesValues = [true, 1, 1.1, 1.11, 'string', new Date(1), 'DATA']; diff --git a/tests/RealmJSTests.mm b/tests/RealmJSTests.mm index bd7445bcff..71bde080cd 100644 --- a/tests/RealmJSTests.mm +++ b/tests/RealmJSTests.mm @@ -82,6 +82,7 @@ - (void)setUp { [RealmJS initializeContext:ctx]; + [self evaluateScript:@"var exports = {};" fromURL:nil]; [self evaluateScriptWithName:@"TestCase"]; [self evaluateScriptWithName:@"TestObjects"]; [self evaluateScriptWithName:self.class.jsSuiteName]; @@ -183,6 +184,7 @@ + (XCTestSuite *)defaultTestSuite { JSContext *context = [[JSContext alloc] init]; JSValue *exception; + [self evaluateScript:@"var exports = {};" fromURL:nil inContext:context exception:&exception]; [self evaluateScript:script fromURL:scriptURL inContext:context exception:&exception]; if (exception) { NSLog(@"%@.js - %@", suiteName, exception); diff --git a/tests/RealmTests.js b/tests/RealmTests.js index d173620ffa..bb69cca48c 100644 --- a/tests/RealmTests.js +++ b/tests/RealmTests.js @@ -18,16 +18,6 @@ 'use strict'; -var TestCase = require('./TestCase'); -var { - LinkTypesObjectSchema, - TestObjectSchema, - IntPrimaryObjectSchema, - AllTypesObjectSchema, - DefaultValuesObjectSchema, - PersonObject, -} = require('./TestObjects'); - var RealmTests = { testRealmConstructorPath: function() { TestCase.assertThrows(function() { new Realm('/invalidpath'); }); diff --git a/tests/ResultsTests.js b/tests/ResultsTests.js index 9da420fa14..e85173fda1 100644 --- a/tests/ResultsTests.js +++ b/tests/ResultsTests.js @@ -18,12 +18,6 @@ 'use strict'; -var TestCase = require('./TestCase'); -var { - LinkTypesObjectSchema, - TestObjectSchema, -} = require('./TestObjects'); - var ResultsTests = { testResultsLength: function() { var realm = new Realm({schema: [TestObjectSchema]}); diff --git a/tests/index.js b/tests/index.js index e2150f134b..ebe9576020 100644 --- a/tests/index.js +++ b/tests/index.js @@ -1,5 +1,15 @@ 'use strict'; +var TestCase = require('./TestCase'); +var { + LinkTypesObjectSchema, + TestObjectSchema, + IntPrimaryObjectSchema, + AllTypesObjectSchema, + DefaultValuesObjectSchema, + PersonObject, +} = require('./TestObjects'); + var RealmTestSuite = { tests: [ require('./ArrayTests.js'), From d9618a0e0617ca480e66d527d1984628607ee5b2 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 2 Oct 2015 15:26:35 -0700 Subject: [PATCH 03/32] remove const, link test app with libRealmReact --- lib/objects.js | 4 +- .../ios/ReactTests.xcodeproj/project.pbxproj | 86 ++++++++++++++++--- 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/lib/objects.js b/lib/objects.js index fa4a5ac2ba..734d4090fb 100644 --- a/lib/objects.js +++ b/lib/objects.js @@ -33,8 +33,8 @@ function create(realmId, info) { return object; } -function registerConstructors(realmId, constructors) { - registeredConstructors[realmId] = constructors; +function registerletructors(realmId, letructors) { + registeredletructors[realmId] = letructors; } function getterForProperty(name) { diff --git a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj index b872f486f0..50795fa792 100644 --- a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj +++ b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; 00E356F31AD99517003FC87E /* ReactTestsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ReactTestsTests.m */; }; + 0277991C1BBF3BC600C96559 /* libRealmReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0277991B1BBF3BB700C96559 /* libRealmReact.a */; }; 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; @@ -68,6 +69,27 @@ remoteGlobalIDString = 13B07F861A680F5B00A75B9A; remoteInfo = ReactTests; }; + 027799161BBF3BB700C96559 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 027799061BBF3BB700C96559 /* RealmJS.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 02B58CB11AE99CEC009B348C; + remoteInfo = RealmJS; + }; + 027799181BBF3BB700C96559 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 027799061BBF3BB700C96559 /* RealmJS.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 02B58CBC1AE99CEC009B348C; + remoteInfo = RealmJSTests; + }; + 0277991A1BBF3BB700C96559 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 027799061BBF3BB700C96559 /* RealmJS.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 02B29A161B7CF7C9008A7E6B; + remoteInfo = RealmReact; + }; 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; @@ -106,17 +128,18 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = main.jsbundle; path = main.jsbundle; sourceTree = ""; }; - 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = ""; }; - 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = ""; }; - 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; - 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; - 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = ""; }; + 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; + 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; }; + 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; }; + 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; + 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; }; + 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; 00E356EE1AD99517003FC87E /* ReactTestsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactTestsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 00E356F21AD99517003FC87E /* ReactTestsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReactTestsTests.m; sourceTree = ""; }; - 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj; sourceTree = ""; }; - 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; + 027799061BBF3BB700C96559 /* RealmJS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RealmJS.xcodeproj; path = ../../../RealmJS.xcodeproj; sourceTree = ""; }; + 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; + 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* ReactTests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReactTests.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ReactTests/AppDelegate.h; sourceTree = ""; }; 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = ReactTests/AppDelegate.m; sourceTree = ""; }; @@ -124,9 +147,9 @@ 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ReactTests/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ReactTests/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ReactTests/main.m; sourceTree = ""; }; - 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../node_modules/react-native/React/React.xcodeproj; sourceTree = ""; }; - 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = ""; }; - 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../node_modules/react-native/Libraries/Text/RCTText.xcodeproj; sourceTree = ""; }; + 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; + 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; + 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -141,6 +164,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0277991C1BBF3BC600C96559 /* libRealmReact.a in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */, 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, @@ -214,6 +238,16 @@ name = "Supporting Files"; sourceTree = ""; }; + 027799071BBF3BB700C96559 /* Products */ = { + isa = PBXGroup; + children = ( + 027799171BBF3BB700C96559 /* RealmJS.framework */, + 027799191BBF3BB700C96559 /* RealmJSTests.xctest */, + 0277991B1BBF3BB700C96559 /* libRealmReact.a */, + ); + name = Products; + sourceTree = ""; + }; 139105B71AF99BAD00B5F7CC /* Products */ = { isa = PBXGroup; children = ( @@ -263,6 +297,7 @@ 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( + 027799061BBF3BB700C96559 /* RealmJS.xcodeproj */, 146833FF1AC3E56700842450 /* React.xcodeproj */, 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, @@ -411,6 +446,10 @@ ProductGroup = 146834001AC3E56700842450 /* Products */; ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; }, + { + ProductGroup = 027799071BBF3BB700C96559 /* Products */; + ProjectRef = 027799061BBF3BB700C96559 /* RealmJS.xcodeproj */; + }, ); projectRoot = ""; targets = ( @@ -456,6 +495,27 @@ remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 027799171BBF3BB700C96559 /* RealmJS.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = RealmJS.framework; + remoteRef = 027799161BBF3BB700C96559 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 027799191BBF3BB700C96559 /* RealmJSTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = RealmJSTests.xctest; + remoteRef = 027799181BBF3BB700C96559 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 0277991B1BBF3BB700C96559 /* libRealmReact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRealmReact.a; + remoteRef = 0277991A1BBF3BB700C96559 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -600,7 +660,7 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", ); - INFOPLIST_FILE = "ReactTests/Info.plist"; + INFOPLIST_FILE = ReactTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = ReactTests; @@ -616,7 +676,7 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", ); - INFOPLIST_FILE = "ReactTests/Info.plist"; + INFOPLIST_FILE = ReactTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = ReactTests; From 68603c2620fff376ef4a03e9c67f20097a997856 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 2 Oct 2015 15:50:23 -0700 Subject: [PATCH 04/32] fix exports --- tests/ArrayTests.js | 2 +- tests/ObjectTests.js | 2 +- tests/ReactTests/index.ios.js | 6 ++++++ tests/RealmTests.js | 2 +- tests/ResultsTests.js | 2 +- tests/index.js | 1 + 6 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/ArrayTests.js b/tests/ArrayTests.js index 16729fbef4..db3bd18ab9 100644 --- a/tests/ArrayTests.js +++ b/tests/ArrayTests.js @@ -250,5 +250,5 @@ var ArrayTests = { }); }, }; -exports.ArrayTests = ArrayTests; +module.exports = ArrayTests; diff --git a/tests/ObjectTests.js b/tests/ObjectTests.js index f5dbe48d3c..ad719b357e 100644 --- a/tests/ObjectTests.js +++ b/tests/ObjectTests.js @@ -122,4 +122,4 @@ var ObjectTests = { TestCase.assertEqual(obj.arrayCol[2].doubleCol, 2); }, }; -exports.ObjectTests = ObjectTests; +module.exports = ObjectTests; diff --git a/tests/ReactTests/index.ios.js b/tests/ReactTests/index.ios.js index f34574907f..71e065cf6e 100644 --- a/tests/ReactTests/index.ios.js +++ b/tests/ReactTests/index.ios.js @@ -8,6 +8,12 @@ var React = require('react-native'); var Realm = require('realm'); var RealmTestSuite = require('RealmTestSuite'); +RealmTestSuite.tests.forEach(function(suite, name) { + for (var name in suite) { + suite[name](); + } +}); + var { AppRegistry, StyleSheet, diff --git a/tests/RealmTests.js b/tests/RealmTests.js index bb69cca48c..1d4fd286cc 100644 --- a/tests/RealmTests.js +++ b/tests/RealmTests.js @@ -266,5 +266,5 @@ var RealmTests = { TestCase.assertEqual(notificationCount, 1); }, }; -exports.RealmTests = RealmTests; +module.exports = RealmTests; diff --git a/tests/ResultsTests.js b/tests/ResultsTests.js index e85173fda1..8d81635a75 100644 --- a/tests/ResultsTests.js +++ b/tests/ResultsTests.js @@ -100,4 +100,4 @@ var ResultsTests = { TestCase.assertEqual(objects[4].doubleCol, 0); }, } -exports.ResultsTests = ResultsTests; +module.exports = ResultsTests; diff --git a/tests/index.js b/tests/index.js index ebe9576020..3e07192e0a 100644 --- a/tests/index.js +++ b/tests/index.js @@ -17,5 +17,6 @@ var RealmTestSuite = { require('./RealmTests.js'), require('./ResultsTests.js'), ], + testObjects: require('./TestObjects'), } module.exports = RealmTestSuite; // eslint-disable-line no-undef From 22076933adbf6a17cdd664ac18c612a35a1df234 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Tue, 6 Oct 2015 00:52:15 -0700 Subject: [PATCH 05/32] Fix "const" search and replace --- lib/objects.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/objects.js b/lib/objects.js index 734d4090fb..fa4a5ac2ba 100644 --- a/lib/objects.js +++ b/lib/objects.js @@ -33,8 +33,8 @@ function create(realmId, info) { return object; } -function registerletructors(realmId, letructors) { - registeredletructors[realmId] = letructors; +function registerConstructors(realmId, constructors) { + registeredConstructors[realmId] = constructors; } function getterForProperty(name) { From db80c3a89a7a3a4042f2cb1f85200ef0775b9eca Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Tue, 6 Oct 2015 00:57:35 -0700 Subject: [PATCH 06/32] Refactor tests to run again inside Xcode Added a CommonJS module loader that is used by XCTestCase subclass to load and run the tests. --- RealmJS.xcodeproj/project.pbxproj | 36 +++-- tests/ArrayTests.js | 27 ++-- tests/ObjectTests.js | 18 +-- tests/RJSModuleLoader.h | 30 ++++ tests/RJSModuleLoader.m | 183 +++++++++++++++++++++++++ tests/ReactTests/index.ios.js | 12 +- tests/ReactTests/package.json | 2 +- tests/RealmJSTests.h | 4 - tests/RealmJSTests.mm | 196 +++++++-------------------- tests/RealmTests.js | 48 +++---- tests/ResultsTests.js | 22 +-- tests/{TestCase.js => asserts.js} | 15 +- tests/index.js | 42 +++--- tests/package.json | 2 +- tests/{TestObjects.js => schemas.js} | 12 +- tests/util.js | 24 ++++ 16 files changed, 412 insertions(+), 261 deletions(-) create mode 100644 tests/RJSModuleLoader.h create mode 100644 tests/RJSModuleLoader.m rename tests/{TestCase.js => asserts.js} (91%) rename tests/{TestObjects.js => schemas.js} (91%) create mode 100644 tests/util.js diff --git a/RealmJS.xcodeproj/project.pbxproj b/RealmJS.xcodeproj/project.pbxproj index fdcaea6aaa..ad712f1ba0 100644 --- a/RealmJS.xcodeproj/project.pbxproj +++ b/RealmJS.xcodeproj/project.pbxproj @@ -47,8 +47,8 @@ 0270BC821B7D020100010E03 /* RealmJSTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC7B1B7D020100010E03 /* RealmJSTests.mm */; }; 0270BC831B7D020100010E03 /* RealmTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 0270BC7C1B7D020100010E03 /* RealmTests.js */; }; 0270BC841B7D020100010E03 /* ResultsTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 0270BC7D1B7D020100010E03 /* ResultsTests.js */; }; - 0270BC851B7D020100010E03 /* TestCase.js in Resources */ = {isa = PBXBuildFile; fileRef = 0270BC7E1B7D020100010E03 /* TestCase.js */; }; - 0270BC861B7D020100010E03 /* TestObjects.js in Resources */ = {isa = PBXBuildFile; fileRef = 0270BC7F1B7D020100010E03 /* TestObjects.js */; }; + 0270BC851B7D020100010E03 /* asserts.js in Resources */ = {isa = PBXBuildFile; fileRef = 0270BC7E1B7D020100010E03 /* asserts.js */; }; + 0270BC861B7D020100010E03 /* schemas.js in Resources */ = {isa = PBXBuildFile; fileRef = 0270BC7F1B7D020100010E03 /* schemas.js */; }; 0270BC871B7D023200010E03 /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; }; 0270BCD11B7D067300010E03 /* RealmReactModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0270BCD01B7D067300010E03 /* RealmReactModule.m */; }; 02A3C7971BC4318600B1A7BE /* GCDWebServers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02A3C7941BC4317A00B1A7BE /* GCDWebServers.framework */; }; @@ -56,6 +56,9 @@ 02B58CCE1AE99D4D009B348C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; }; 02D456DA1B7E59A500EE1299 /* ArrayTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02D456D91B7E59A500EE1299 /* ArrayTests.js */; }; 02D8D1F71B601984006DB49D /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; }; + F64E1EF11BC3510E00E0E150 /* util.js in Resources */ = {isa = PBXBuildFile; fileRef = F64E1EF01BC3510E00E0E150 /* util.js */; settings = {ASSET_TAGS = (); }; }; + F68A278C1BC2722A0063D40A /* RJSModuleLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */; settings = {ASSET_TAGS = (); }; }; + F68A278E1BC30F0A0063D40A /* index.js in Resources */ = {isa = PBXBuildFile; fileRef = F68A278D1BC30F0A0063D40A /* index.js */; settings = {ASSET_TAGS = (); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -166,8 +169,8 @@ 0270BC7B1B7D020100010E03 /* RealmJSTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmJSTests.mm; path = tests/RealmJSTests.mm; sourceTree = SOURCE_ROOT; }; 0270BC7C1B7D020100010E03 /* RealmTests.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = RealmTests.js; path = tests/RealmTests.js; sourceTree = SOURCE_ROOT; }; 0270BC7D1B7D020100010E03 /* ResultsTests.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ResultsTests.js; path = tests/ResultsTests.js; sourceTree = SOURCE_ROOT; }; - 0270BC7E1B7D020100010E03 /* TestCase.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TestCase.js; path = tests/TestCase.js; sourceTree = SOURCE_ROOT; }; - 0270BC7F1B7D020100010E03 /* TestObjects.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TestObjects.js; path = tests/TestObjects.js; sourceTree = SOURCE_ROOT; }; + 0270BC7E1B7D020100010E03 /* asserts.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = asserts.js; path = tests/asserts.js; sourceTree = SOURCE_ROOT; }; + 0270BC7F1B7D020100010E03 /* schemas.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = schemas.js; path = tests/schemas.js; sourceTree = SOURCE_ROOT; }; 0270BCCF1B7D067300010E03 /* RealmReactModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmReactModule.h; path = ReactNative/RealmReactModule.h; sourceTree = ""; }; 0270BCD01B7D067300010E03 /* RealmReactModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RealmReactModule.m; path = ReactNative/RealmReactModule.m; sourceTree = ""; }; 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GCDWebServer.xcodeproj; path = vendor/GCDWebServer/GCDWebServer.xcodeproj; sourceTree = ""; }; @@ -177,6 +180,10 @@ 02B58CBC1AE99CEC009B348C /* RealmJSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RealmJSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; 02D456D91B7E59A500EE1299 /* ArrayTests.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ArrayTests.js; path = tests/ArrayTests.js; sourceTree = SOURCE_ROOT; }; + F64E1EF01BC3510E00E0E150 /* util.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = util.js; path = tests/util.js; sourceTree = SOURCE_ROOT; }; + F68A278A1BC2722A0063D40A /* RJSModuleLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RJSModuleLoader.h; path = tests/RJSModuleLoader.h; sourceTree = SOURCE_ROOT; }; + F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RJSModuleLoader.m; path = tests/RJSModuleLoader.m; sourceTree = SOURCE_ROOT; }; + F68A278D1BC30F0A0063D40A /* index.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = index.js; path = tests/index.js; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -299,15 +306,19 @@ 02B58CC01AE99CEC009B348C /* RealmJSTests */ = { isa = PBXGroup; children = ( - 02D456D91B7E59A500EE1299 /* ArrayTests.js */, 0270BC781B7D020100010E03 /* Info.plist */, + F68A278D1BC30F0A0063D40A /* index.js */, + 0270BC7E1B7D020100010E03 /* asserts.js */, + 0270BC7F1B7D020100010E03 /* schemas.js */, + F64E1EF01BC3510E00E0E150 /* util.js */, + 02D456D91B7E59A500EE1299 /* ArrayTests.js */, 0270BC791B7D020100010E03 /* ObjectTests.js */, - 0270BC7A1B7D020100010E03 /* RealmJSTests.h */, - 0270BC7B1B7D020100010E03 /* RealmJSTests.mm */, 0270BC7C1B7D020100010E03 /* RealmTests.js */, 0270BC7D1B7D020100010E03 /* ResultsTests.js */, - 0270BC7F1B7D020100010E03 /* TestObjects.js */, - 0270BC7E1B7D020100010E03 /* TestCase.js */, + 0270BC7A1B7D020100010E03 /* RealmJSTests.h */, + 0270BC7B1B7D020100010E03 /* RealmJSTests.mm */, + F68A278A1BC2722A0063D40A /* RJSModuleLoader.h */, + F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */, ); path = RealmJSTests; sourceTree = ""; @@ -503,10 +514,12 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0270BC851B7D020100010E03 /* TestCase.js in Resources */, + F64E1EF11BC3510E00E0E150 /* util.js in Resources */, + 0270BC851B7D020100010E03 /* asserts.js in Resources */, 0270BC811B7D020100010E03 /* ObjectTests.js in Resources */, 02D456DA1B7E59A500EE1299 /* ArrayTests.js in Resources */, - 0270BC861B7D020100010E03 /* TestObjects.js in Resources */, + 0270BC861B7D020100010E03 /* schemas.js in Resources */, + F68A278E1BC30F0A0063D40A /* index.js in Resources */, 0270BC831B7D020100010E03 /* RealmTests.js in Resources */, 0270BC841B7D020100010E03 /* ResultsTests.js in Resources */, ); @@ -568,6 +581,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F68A278C1BC2722A0063D40A /* RJSModuleLoader.m in Sources */, 0270BC821B7D020100010E03 /* RealmJSTests.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/tests/ArrayTests.js b/tests/ArrayTests.js index db3bd18ab9..3348b2b9c6 100644 --- a/tests/ArrayTests.js +++ b/tests/ArrayTests.js @@ -18,9 +18,12 @@ 'use strict'; -var ArrayTests = { +var TestCase = require('./asserts'); +var schemas = require('./schemas'); + +module.exports = { testLinkTypesPropertySetters: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); var obj = null; realm.write(function() { obj = realm.create('LinkTypesObject', [[1], undefined, [[3]]]); @@ -51,7 +54,7 @@ var ArrayTests = { }, testArrayLength: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); realm.write(function() { var obj = realm.create('LinkTypesObject', [[1], [2], [[3]]]); TestCase.assertEqual(obj.arrayCol.length, 1); @@ -65,7 +68,7 @@ var ArrayTests = { }, testArraySubscript: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); realm.write(function() { realm.create('LinkTypesObject', [[1], [2], [[3], [4]]]); }); var array = realm.objects('LinkTypesObject')[0].arrayCol; @@ -76,7 +79,7 @@ var ArrayTests = { }, testArrayInvalidProperty: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); realm.write(function() { realm.create('LinkTypesObject', [[1], [2], [[3], [4]]]); }); var array = realm.objects('LinkTypesObject')[0].arrayCol; @@ -84,7 +87,7 @@ var ArrayTests = { }, testArrayEnumerate: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); realm.write(function() { realm.create('LinkTypesObject', [[1], [2], []]); }); var obj = realm.objects('LinkTypesObject')[0]; @@ -106,7 +109,7 @@ var ArrayTests = { }, testPush: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); var array; realm.write(function() { var obj = realm.create('LinkTypesObject', [[1], [2], [[3]]]); @@ -134,7 +137,7 @@ var ArrayTests = { }, testPop: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); var array; realm.write(function() { var obj = realm.create('LinkTypesObject', [[1], [2], [[3], [4]]]); @@ -157,7 +160,7 @@ var ArrayTests = { }, testUnshift: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); var array; realm.write(function() { var obj = realm.create('LinkTypesObject', [[1], [2], [[3]]]); @@ -181,7 +184,7 @@ var ArrayTests = { }, testShift: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); var array; realm.write(function() { var obj = realm.create('LinkTypesObject', [[1], [2], [[3], [4]]]); @@ -204,7 +207,7 @@ var ArrayTests = { }, testSplice: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); realm.write(function() { var obj = realm.create('LinkTypesObject', [[1], [2], [[3], [4]]]); @@ -250,5 +253,3 @@ var ArrayTests = { }); }, }; -module.exports = ArrayTests; - diff --git a/tests/ObjectTests.js b/tests/ObjectTests.js index ad719b357e..126ea4f279 100644 --- a/tests/ObjectTests.js +++ b/tests/ObjectTests.js @@ -18,17 +18,20 @@ 'use strict'; -var ObjectTests = { +var TestCase = require('./asserts'); +var schemas = require('./schemas'); + +module.exports = { testBasicTypesPropertyGetters: function() { var basicTypesValues = [true, 1, 1.1, 1.11, 'string', new Date(1), 'DATA']; - var realm = new Realm({schema: [BasicTypesObjectSchema]}); + var realm = new Realm({schema: [schemas.BasicTypes]}); var object = null; realm.write(function() { object = realm.create('BasicTypesObject', basicTypesValues); }); - for (var i = 0; i < BasicTypesObjectSchema.properties.length; i++) { - var prop = BasicTypesObjectSchema.properties[i]; + for (var i = 0; i < schemas.BasicTypes.properties.length; i++) { + var prop = schemas.BasicTypes.properties[i]; if (prop.type == Realm.Types.FLOAT) { TestCase.assertEqualWithTolerance(object[prop.name], basicTypesValues[i], 0.000001); } @@ -42,7 +45,7 @@ var ObjectTests = { }, testBasicTypesPropertySetters: function() { var basicTypesValues = [true, 1, 1.1, 1.11, 'string', new Date(1), 'DATA']; - var realm = new Realm({schema: [BasicTypesObjectSchema]}); + var realm = new Realm({schema: [schemas.BasicTypes]}); var obj = null; realm.write(function() { obj = realm.create('BasicTypesObject', basicTypesValues); @@ -63,7 +66,7 @@ var ObjectTests = { TestCase.assertEqual(obj.dataCol, 'b', 'wrong data value'); }, testLinkTypesPropertyGetters: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); var obj = null; realm.write(function() { obj = realm.create('LinkTypesObject', [[1], null, [[3]]]); @@ -83,7 +86,7 @@ var ObjectTests = { TestCase.assertEqual(arrayVal[0].doubleCol, 3); }, testLinkTypesPropertySetters: function() { - var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); var obj = null; realm.write(function() { obj = realm.create('LinkTypesObject', [[1], null, [[3]]]); @@ -122,4 +125,3 @@ var ObjectTests = { TestCase.assertEqual(obj.arrayCol[2].doubleCol, 2); }, }; -module.exports = ObjectTests; diff --git a/tests/RJSModuleLoader.h b/tests/RJSModuleLoader.h new file mode 100644 index 0000000000..5bdac486ff --- /dev/null +++ b/tests/RJSModuleLoader.h @@ -0,0 +1,30 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import +#import + +@interface RJSModuleLoader : NSObject + +- (instancetype)initWithContext:(JSContext *)context; + +- (void)addGlobalModuleObject:(id)object forName:(NSString *)name; + +- (JSValue *)loadModuleFromURL:(NSURL *)url error:(NSError **)error; + +@end diff --git a/tests/RJSModuleLoader.m b/tests/RJSModuleLoader.m new file mode 100644 index 0000000000..e155fa808e --- /dev/null +++ b/tests/RJSModuleLoader.m @@ -0,0 +1,183 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RJSModuleLoader.h" + +static NSString * const RJSModuleLoaderErrorDomain = @"RJSModuleLoaderErrorDomain"; + +@interface RJSModuleLoader () + +@property (nonatomic, strong) JSContext *context; +@property (nonatomic, strong) NSMutableDictionary *modules; +@property (nonatomic, strong) NSMutableDictionary *globalModules; + +@end + +@implementation RJSModuleLoader + +- (instancetype)initWithContext:(JSContext *)context { + self = [super init]; + if (!self) { + return nil; + } + + _context = context; + _modules = [[NSMutableDictionary alloc] init]; + _globalModules = [[NSMutableDictionary alloc] init]; + + return self; +} + +- (void)addGlobalModuleObject:(id)object forName:(NSString *)name { + self.globalModules[name] = [JSValue valueWithObject:object inContext:self.context]; +} + +- (JSValue *)loadModule:(NSString *)name relativeToURL:(NSURL *)baseURL error:(NSError **)error +{ + if (![name hasPrefix:@"./"] && ![name hasPrefix:@"../"]) { + return [self loadGlobalModule:name relativeToURL:baseURL error:error]; + } + + NSURL *url = [[NSURL URLWithString:name relativeToURL:baseURL] absoluteURL]; + BOOL isDirectory; + + if ([[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDirectory]) { + if (!isDirectory) { + return nil; + } + + url = [url URLByAppendingPathComponent:@"index.js"]; + } else { + url = [url URLByAppendingPathExtension:@"js"]; + } + + return [self loadModuleFromURL:url error:error]; +} + +- (JSValue *)loadModuleFromURL:(NSURL *)url error:(NSError **)error { + url = url.absoluteURL; + url = url.standardizedURL ?: url; + + NSString *path = url.path; + JSValue *exports = self.modules[path]; + if (exports) { + return exports; + } + + NSString *source = [NSString stringWithContentsOfURL:url usedEncoding:NULL error:error]; + if (!source) { + return nil; + } + + JSContext *context = self.context; + JSValue *module = [JSValue valueWithNewObjectInContext:context]; + + exports = [JSValue valueWithNewObjectInContext:context]; + module[@"exports"] = exports; + + __weak __typeof__(self) weakSelf = self; + + JSValue *require = [JSValue valueWithObject:^JSValue *(NSString *name) { + NSError *error; + JSValue *result = [weakSelf loadModule:name relativeToURL:url error:&error]; + + if (!result) { + NSString *message = [NSString stringWithFormat:@"Error requiring module '%@': %@", name, error ?: @"Not found"]; + JSContext *context = [JSContext currentContext]; + + context.exception = [JSValue valueWithNewErrorFromMessage:message inContext:context]; + return nil; + } + + return result; + } inContext:context]; + + JSStringRef jsParameterNames[] = {JSStringCreateWithUTF8CString("module"), JSStringCreateWithUTF8CString("exports"), JSStringCreateWithUTF8CString("require")}; + JSStringRef jsSource = JSStringCreateWithCFString((__bridge CFStringRef)source); + JSStringRef jsSourceURL = JSStringCreateWithCFString((__bridge CFStringRef)path); + + JSValueRef jsException; + JSObjectRef jsModuleFunction = JSObjectMakeFunction(context.JSGlobalContextRef, NULL, 3, jsParameterNames, jsSource, jsSourceURL, 1, &jsException); + + JSStringRelease(jsParameterNames[0]); + JSStringRelease(jsParameterNames[1]); + JSStringRelease(jsParameterNames[2]); + JSStringRelease(jsSource); + JSStringRelease(jsSourceURL); + + // Start with the original exports for circular dependendies and in case of an error. + self.modules[path] = exports; + + JSValue *exception; + + if (jsModuleFunction) { + JSValue *moduleFunction = [JSValue valueWithJSValueRef:jsModuleFunction inContext:context]; + [moduleFunction callWithArguments:@[module, exports, require]]; + + exception = context.exception; + } else { + exception = [JSValue valueWithJSValueRef:jsException inContext:context]; + } + + exports = module[@"exports"]; + self.modules[path] = exports; + + if (exception) { + *error = [NSError errorWithDomain:RJSModuleLoaderErrorDomain code:1 userInfo:@{ + NSLocalizedDescriptionKey: exception.description, + NSURLErrorKey: url, + @"JSException": exception, + }]; + + return nil; + } + + return exports; +} + +- (JSValue *)loadGlobalModule:(NSString *)name relativeToURL:(NSURL *)baseURL error:(NSError **)error { + JSValue *exports = self.globalModules[name]; + if (exports || !baseURL) { + return exports; + } + + NSURL *bundleResourcesURL = [[NSBundle bundleForClass:self.class] resourceURL]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + + while (YES) { + NSURL *moduleURL = [NSURL URLWithString:[@"node_modules" stringByAppendingPathComponent:name] relativeToURL:baseURL]; + BOOL isDirectory; + + if ([fileManager fileExistsAtPath:moduleURL.path isDirectory:&isDirectory] && isDirectory) { + return [self loadModuleFromURL:moduleURL error:error]; + } + + // Remove last two path components (node_modules/name) and make absolute. + baseURL = moduleURL.URLByDeletingLastPathComponent.URLByDeletingLastPathComponent.absoluteURL; + if ([baseURL isEqual:bundleResourcesURL] || !baseURL.path.length) { + break; + } + + // Retry with parent directory. + baseURL = baseURL.URLByDeletingLastPathComponent; + } + + return nil; +} + +@end diff --git a/tests/ReactTests/index.ios.js b/tests/ReactTests/index.ios.js index 71e065cf6e..3a1e1702f0 100644 --- a/tests/ReactTests/index.ios.js +++ b/tests/ReactTests/index.ios.js @@ -6,13 +6,13 @@ var React = require('react-native'); var Realm = require('realm'); -var RealmTestSuite = require('RealmTestSuite'); +var RealmTests = require('realm-tests'); -RealmTestSuite.tests.forEach(function(suite, name) { - for (var name in suite) { - suite[name](); - } -}); +for (var suiteName in RealmTests) { + for (var testName in RealmTests[suiteName]) { + RealmTests[suiteName][testName](); + } +} var { AppRegistry, diff --git a/tests/ReactTests/package.json b/tests/ReactTests/package.json index bd41b47cf5..33231d5628 100644 --- a/tests/ReactTests/package.json +++ b/tests/ReactTests/package.json @@ -8,6 +8,6 @@ "dependencies": { "react-native": "^0.11.4", "realm": "file:../../lib", - "RealmTestSuite": "file:.." + "realm-tests": "file:.." } } diff --git a/tests/RealmJSTests.h b/tests/RealmJSTests.h index 907a9aea3b..4ff55c4fc5 100644 --- a/tests/RealmJSTests.h +++ b/tests/RealmJSTests.h @@ -24,8 +24,4 @@ extern NSString *TestRealmPath(); @interface RealmJSTests : XCTestCase -+ (NSString *)jsSuiteName; - -@property (nonatomic, readonly) JSContext *context; - @end diff --git a/tests/RealmJSTests.mm b/tests/RealmJSTests.mm index 71bde080cd..c7f8b9cbcd 100644 --- a/tests/RealmJSTests.mm +++ b/tests/RealmJSTests.mm @@ -16,9 +16,12 @@ // //////////////////////////////////////////////////////////////////////////// +#import + #import "RealmJSTests.h" #import "RJSUtil.hpp" #import "RJSRealm.hpp" +#import "RJSModuleLoader.h" NSString *RealmPathForFile(NSString *fileName) { #if TARGET_OS_IPHONE @@ -53,20 +56,27 @@ static void DeleteRealmFilesAtPath(NSString *path) { DeleteOrThrow([path stringByAppendingString:@".note"]); } -static JSClassRef s_globalClass; - @interface RealmJSTests () -@property (nonatomic, strong) JSContext *context; +@property (nonatomic, strong) JSValue *testObject; @end @implementation RealmJSTests -+ (void)initialize { - JSClassDefinition globalDefinition = kJSClassDefinitionEmpty; - globalDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; - s_globalClass = JSClassCreate(&globalDefinition); +- (instancetype)initWithJSTestObject:(JSValue *)testObject methodName:(NSString *)methodName { + self = [super initWithSelector:NSSelectorFromString(methodName)]; + if (!self) { + return nil; + } + + _testObject = testObject; + + return self; +} + +- (JSContext *)context { + return self.testObject.context; } - (void)setUp { @@ -77,20 +87,10 @@ - (void)setUp { [[NSFileManager defaultManager] createDirectoryAtPath:defaultDir withIntermediateDirectories:YES attributes:nil error:nil]; RJSSetDefaultPath([defaultDir stringByAppendingPathComponent:@"default.realm"].UTF8String); - JSGlobalContextRef ctx = JSGlobalContextCreateInGroup(NULL, s_globalClass); - self.context = [JSContext contextWithJSGlobalContextRef:ctx]; - - [RealmJS initializeContext:ctx]; - - [self evaluateScript:@"var exports = {};" fromURL:nil]; - [self evaluateScriptWithName:@"TestCase"]; - [self evaluateScriptWithName:@"TestObjects"]; - [self evaluateScriptWithName:self.class.jsSuiteName]; + self.context.exception = nil; } - (void)tearDown { - self.context = nil; - DeleteRealmFilesAtPath(TestRealmPath()); DeleteRealmFilesAtPath(@(RJSDefaultPath().c_str())); @@ -103,107 +103,33 @@ - (void)invokeTest { } } -- (void)evaluateScriptWithName:(NSString *)name { - NSURL *url = [self.class scriptURLWithName:name]; - NSString *script = [self.class loadScriptWithURL:url]; - - [self evaluateScript:script fromURL:url]; -} - -- (void)evaluateScript:(NSString *)script fromURL:(NSURL *)url { - JSValue *exception; - [self.class evaluateScript:script fromURL:url inContext:self.context exception:&exception]; - - if (exception) { - JSValue *message = [exception hasProperty:@"message"] ? exception[@"message"] : exception; - NSString *source = [exception hasProperty:@"sourceURL"] ? [exception[@"sourceURL"] toString] : nil; - NSUInteger line = [exception hasProperty:@"line"] ? [exception[@"line"] toUInt32] : 0; - NSURL *sourceURL = source ? [NSURL URLWithString:source.lastPathComponent relativeToURL:[NSURL URLWithString:@(__FILE__)]] : nil; - const char *sourcePath = sourceURL.absoluteString.UTF8String; - - _XCTFailureHandler(self, YES, sourcePath ?: __FILE__, sourcePath ? line : __LINE__, @"JS", @"%@", message); - } -} - -+ (JSValue *)evaluateScript:(NSString *)script fromURL:(NSURL *)url inContext:(JSContext *)context exception:(JSValue **)exception { - JSStringRef jsScript = JSStringCreateWithUTF8CString(script.UTF8String); - JSStringRef jsURL = url ? JSStringCreateWithUTF8CString(url.absoluteString.UTF8String) : NULL; - JSValueRef jsException = NULL; - JSValueRef jsResult = JSEvaluateScript(context.JSGlobalContextRef, jsScript, NULL, jsURL, 1, &jsException); - - JSStringRelease(jsScript); - if (jsURL) { - JSStringRelease(jsURL); - } - - if (jsException) { - *exception = [JSValue valueWithJSValueRef:jsException inContext:context]; - return NULL; - } - - return [JSValue valueWithJSValueRef:jsResult inContext:context]; -} - -+ (NSURL *)scriptURLWithName:(NSString *)name { - NSURL *url = [[NSBundle bundleForClass:self] URLForResource:name withExtension:@"js"]; - if (!url) { - NSLog(@"JS file does not exist: %@", url); - exit(1); - } - return url; -} - -+ (NSString *)loadScriptWithURL:(NSURL *)url { - NSError *error; - NSString *script = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error]; - if (!script) { - NSLog(@"Error reading JS file (%@): %@", url, error); - exit(1); - } - return script; -} - -+ (NSString *)jsSuiteName { - return nil; -} - -+ (NSString *)jsSuiteScript { - NSString *name = [self jsSuiteName]; - return name ? [self loadScriptWithURL:[self scriptURLWithName:name]] : nil; -} - + (XCTestSuite *)defaultTestSuite { XCTestSuite *suite = [super defaultTestSuite]; - NSString *suiteName = [self jsSuiteName]; - NSURL *scriptURL = suiteName ? [self scriptURLWithName:suiteName] : nil; - NSString *script = scriptURL ? [self loadScriptWithURL:scriptURL] : nil; - if (!script) { - return suite; - } - JSContext *context = [[JSContext alloc] init]; - JSValue *exception; + RJSModuleLoader *moduleLoader = [[RJSModuleLoader alloc] initWithContext:context]; + NSURL *scriptURL = [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js"]; - [self evaluateScript:@"var exports = {};" fromURL:nil inContext:context exception:&exception]; - [self evaluateScript:script fromURL:scriptURL inContext:context exception:&exception]; - if (exception) { - NSLog(@"%@.js - %@", suiteName, exception); - exit(1); - } + [RealmJS initializeContext:context.JSGlobalContextRef]; - JSValue *suiteObject = [self evaluateScript:suiteName fromURL:nil inContext:context exception:&exception]; - if (exception) { - NSLog(@"%@.js - %@", suiteName, exception); - exit(1); - } + NSError *error; + JSValue *testObjects = [moduleLoader loadModuleFromURL:scriptURL error:&error]; - if (![suiteObject isObject]) { - NSLog(@"%@.js - JS test suite is not an object: %@", suiteName, suiteObject); + if (!testObjects) { + NSLog(@"index.js - %@", error); exit(1); } - for (NSString *testName in [suiteObject toDictionary]) { - [suite addTest:[self testCaseWithSelector:NSSelectorFromString(testName)]]; + for (NSString *testName in [testObjects toDictionary]) { + JSValue *testObject = testObjects[testName]; + XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:testName]; + Class testClass = objc_allocateClassPair(self, testName.UTF8String, 0); + + for (NSString *methodName in [testObject toDictionary]) { + XCTestCase *testCase = [[testClass alloc] initWithJSTestObject:testObject methodName:methodName]; + [testSuite addTest:testCase]; + } + + [suite addTest:testSuite]; } return suite; @@ -211,48 +137,28 @@ + (XCTestSuite *)defaultTestSuite { - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *sig = [super methodSignatureForSelector:aSelector]; - if (sig) { - return sig; - } - return [NSMethodSignature signatureWithObjCTypes:"v@:"]; + return sig ?: [NSMethodSignature signatureWithObjCTypes:"v@:"]; } - (void)forwardInvocation:(NSInvocation *)anInvocation { - NSString *script = [NSString stringWithFormat:@"%@.%@();", [self.class jsSuiteName], NSStringFromSelector(anInvocation.selector)]; - [self evaluateScript:script fromURL:nil]; -} + JSValue *testObject = self.testObject; + JSContext *context = testObject.context; -@end + [testObject invokeMethod:NSStringFromSelector(anInvocation.selector) withArguments:nil]; -@interface RJSResultsTests : RealmJSTests -@end -@implementation RJSResultsTests -+ (NSString *)jsSuiteName { - return @"ResultsTests"; -} -@end + JSValue *exception = context.exception; -@interface RJSObjectTests : RealmJSTests -@end -@implementation RJSObjectTests -+ (NSString *)jsSuiteName { - return @"ObjectTests"; -} -@end + if (exception) { + JSValue *message = [exception hasProperty:@"message"] ? exception[@"message"] : exception; + NSString *source = [exception hasProperty:@"sourceURL"] ? [exception[@"sourceURL"] toString] : nil; + NSUInteger line = [exception hasProperty:@"line"] ? [exception[@"line"] toUInt32] - 1 : 0; + NSURL *sourceURL = source ? [NSURL URLWithString:source.lastPathComponent relativeToURL:[NSURL URLWithString:@(__FILE__)]] : nil; -@interface RJSArrayTests : RealmJSTests -@end -@implementation RJSArrayTests -+ (NSString *)jsSuiteName { - return @"ArrayTests"; + [self recordFailureWithDescription:message.description + inFile:sourceURL ? sourceURL.absoluteString : @(__FILE__) + atLine:sourceURL ? line : __LINE__ + expected:YES]; + } } -@end -@interface RJSRealmTests : RealmJSTests -@end -@implementation RJSRealmTests -+ (NSString *)jsSuiteName { - return @"RealmTests"; -} @end - diff --git a/tests/RealmTests.js b/tests/RealmTests.js index 1d4fd286cc..d94a085215 100644 --- a/tests/RealmTests.js +++ b/tests/RealmTests.js @@ -18,10 +18,14 @@ 'use strict'; -var RealmTests = { +var TestCase = require('./asserts'); +var schemas = require('./schemas'); +var util = require('./util'); + +module.exports = { testRealmConstructorPath: function() { TestCase.assertThrows(function() { new Realm('/invalidpath'); }); - TestCase.assertThrows(function() { new Realm(TestUtil.realmPathForFile('test1.realm'), 'invalidArgument'); }); + TestCase.assertThrows(function() { new Realm(util.realmPathForFile('test1.realm'), 'invalidArgument'); }); var defaultRealm = new Realm({schema: []}); TestCase.assertEqual(defaultRealm.path, Realm.defaultPath); @@ -29,12 +33,12 @@ var RealmTests = { var defaultRealm2 = new Realm(); TestCase.assertEqual(defaultRealm2.path, Realm.defaultPath); - var testPath = TestUtil.realmPathForFile('test1.realm'); + var testPath = util.realmPathForFile('test1.realm'); var realm = new Realm({schema: [], path: testPath}); //TestCase.assertTrue(realm instanceof Realm); TestCase.assertEqual(realm.path, testPath); - var testPath2 = TestUtil.realmPathForFile('test2.realm'); + var testPath2 = util.realmPathForFile('test2.realm'); var realm2 = new Realm({schema: [], path: testPath2}); //TestCase.assertTrue(realm2 instanceof Realm); TestCase.assertEqual(realm2.path, testPath2); @@ -51,7 +55,7 @@ var RealmTests = { TestCase.assertEqual(new Realm().schemaVersion, 0); TestCase.assertEqual(new Realm({schemaVersion: 0}).schemaVersion, 0); - var testPath = TestUtil.realmPathForFile('test1.realm'); + var testPath = util.realmPathForFile('test1.realm'); var realm = new Realm({path: testPath, schema: [], schemaVersion: 1}); TestCase.assertEqual(realm.schemaVersion, 1); @@ -63,7 +67,7 @@ var RealmTests = { var defaultRealm = new Realm({schema: []}); TestCase.assertEqual(defaultRealm.path, Realm.defaultPath); - var newPath = TestUtil.realmPathForFile('default2.realm'); + var newPath = util.realmPathForFile('default2.realm'); Realm.defaultPath = newPath; defaultRealm = new Realm({schema: []}); TestCase.assertEqual(defaultRealm.path, newPath); @@ -72,7 +76,7 @@ var RealmTests = { }, testRealmCreate: function() { - var realm = new Realm({schema: [IntPrimaryObjectSchema, AllTypesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.IntPrimary, schemas.AllTypes, schemas.TestObject]}); realm.write(function() { realm.create('TestObject', [1]); realm.create('TestObject', {'doubleCol': 2}); @@ -143,25 +147,25 @@ var RealmTests = { }, testRealmCreateWithDefaults: function() { - var realm = new Realm({schema: [DefaultValuesObjectSchema, TestObjectSchema]}); + var realm = new Realm({schema: [schemas.DefaultValues, schemas.TestObject]}); realm.write(function() { var obj = realm.create('DefaultValuesObject', {}); - TestCase.assertEqual(obj.boolCol, DefaultValuesObjectSchema.properties[0].default); - TestCase.assertEqual(obj.intCol, DefaultValuesObjectSchema.properties[1].default); - TestCase.assertEqualWithTolerance(obj.floatCol, DefaultValuesObjectSchema.properties[2].default, 0.000001); - TestCase.assertEqual(obj.doubleCol, DefaultValuesObjectSchema.properties[3].default); - TestCase.assertEqual(obj.stringCol, DefaultValuesObjectSchema.properties[4].default); - TestCase.assertEqual(obj.dateCol.getTime(), DefaultValuesObjectSchema.properties[5].default.getTime()); - TestCase.assertEqual(obj.dataCol, DefaultValuesObjectSchema.properties[6].default); - TestCase.assertEqual(obj.objectCol.doubleCol, DefaultValuesObjectSchema.properties[7].default[0]); + TestCase.assertEqual(obj.boolCol, schemas.DefaultValues.properties[0].default); + TestCase.assertEqual(obj.intCol, schemas.DefaultValues.properties[1].default); + TestCase.assertEqualWithTolerance(obj.floatCol, schemas.DefaultValues.properties[2].default, 0.000001); + TestCase.assertEqual(obj.doubleCol, schemas.DefaultValues.properties[3].default); + TestCase.assertEqual(obj.stringCol, schemas.DefaultValues.properties[4].default); + TestCase.assertEqual(obj.dateCol.getTime(), schemas.DefaultValues.properties[5].default.getTime()); + TestCase.assertEqual(obj.dataCol, schemas.DefaultValues.properties[6].default); + TestCase.assertEqual(obj.objectCol.doubleCol, schemas.DefaultValues.properties[7].default[0]); TestCase.assertEqual(obj.nullObjectCol, null); - TestCase.assertEqual(obj.arrayCol.length, DefaultValuesObjectSchema.properties[9].default.length); - TestCase.assertEqual(obj.arrayCol[0].doubleCol, DefaultValuesObjectSchema.properties[9].default[0][0]); + TestCase.assertEqual(obj.arrayCol.length, schemas.DefaultValues.properties[9].default.length); + TestCase.assertEqual(obj.arrayCol[0].doubleCol, schemas.DefaultValues.properties[9].default[0][0]); }); }, testRealmDelete: function() { - var realm = new Realm({schema: [TestObjectSchema]}); + var realm = new Realm({schema: [schemas.TestObject]}); realm.write(function() { for (var i = 0; i < 10; i++) { realm.create('TestObject', [i]); @@ -197,7 +201,7 @@ var RealmTests = { }, testDeleteAll: function() { - var realm = new Realm({schema: [TestObjectSchema, IntPrimaryObjectSchema]}); + var realm = new Realm({schema: [schemas.TestObject, schemas.IntPrimary]}); realm.write(function() { realm.create('TestObject', [1]); realm.create('TestObject', [2]); @@ -219,7 +223,7 @@ var RealmTests = { }, testRealmObjects: function() { - var realm = new Realm({schema: [PersonObject]}); + var realm = new Realm({schema: [schemas.PersonObject]}); realm.write(function() { realm.create('PersonObject', ['Ari', 10]); realm.create('PersonObject', ['Tim', 11]); @@ -266,5 +270,3 @@ var RealmTests = { TestCase.assertEqual(notificationCount, 1); }, }; -module.exports = RealmTests; - diff --git a/tests/ResultsTests.js b/tests/ResultsTests.js index 8d81635a75..098692e694 100644 --- a/tests/ResultsTests.js +++ b/tests/ResultsTests.js @@ -18,9 +18,12 @@ 'use strict'; -var ResultsTests = { +var TestCase = require('./asserts'); +var schemas = require('./schemas'); + +module.exports = { testResultsLength: function() { - var realm = new Realm({schema: [TestObjectSchema]}); + var realm = new Realm({schema: [schemas.TestObject]}); var objects = realm.objects('TestObject'); TestCase.assertEqual(objects.length, 0); @@ -31,7 +34,7 @@ var ResultsTests = { TestCase.assertEqual(objects.length, 1); }, testResultsSubscript: function() { - var realm = new Realm({schema: [PersonObject]}); + var realm = new Realm({schema: [schemas.PersonObject]}); realm.write(function() { realm.create('PersonObject', ['name1', 1]); realm.create('PersonObject', ['name2', 2]); @@ -42,21 +45,21 @@ var ResultsTests = { TestCase.assertEqual(people[1].age, 2); TestCase.assertThrows(function() { people[2]; }, 'Invalid index'); TestCase.assertThrows(function() { people[-1]; }, 'Invalid index'); - TestCase.assertTrue(Object.getPrototypeOf(people[0]) === PersonObject.prototype); + TestCase.assertTrue(Object.getPrototypeOf(people[0]) === schemas.PersonObject.prototype); }, testResultsInvalidProperty: function() { - var realm = new Realm({schema: [TestObjectSchema]}); + var realm = new Realm({schema: [schemas.TestObject]}); var objects = realm.objects('TestObject'); TestCase.assertEqual(undefined, objects.ablasdf); }, testResultsInvalidObjectType: function() { - var realm = new Realm({schema: [TestObjectSchema]}); + var realm = new Realm({schema: [schemas.TestObject]}); TestCase.assertThrows(function() { var objects = realm.objects('NotTestObject'); }); }, testResultsEnumerate: function() { - var realm = new Realm({schema: [TestObjectSchema]}); + var realm = new Realm({schema: [schemas.TestObject]}); var objects = realm.objects('TestObject'); for (var object in objects) { TestCase.assertTrue(false, "No objects should have been enumerated"); @@ -75,7 +78,7 @@ var ResultsTests = { TestCase.assertEqual(1, count); }, testSort: function() { - var realm = new Realm({schema: [TestObjectSchema]}); + var realm = new Realm({schema: [schemas.TestObject]}); var objects = realm.objects('TestObject'); realm.write(function() { realm.create('TestObject', [2]); @@ -99,5 +102,4 @@ var ResultsTests = { TestCase.assertEqual(objects[3].doubleCol, 1); TestCase.assertEqual(objects[4].doubleCol, 0); }, -} -module.exports = ResultsTests; +}; diff --git a/tests/TestCase.js b/tests/asserts.js similarity index 91% rename from tests/TestCase.js rename to tests/asserts.js index 7a45d2f5f2..f58f9d4180 100644 --- a/tests/TestCase.js +++ b/tests/asserts.js @@ -18,15 +18,7 @@ 'use strict'; -var TestUtil = { - realmPathForFile: function(str) { - var path = Realm.defaultPath; - return path.substring(0, path.lastIndexOf("/") + 1) + str; - }, -}; -exports.TestUtil = TestUtil; - -var TestCase = { +module.exports = { assertEqual: function(val1, val2, errorMessage) { if (val1 !== val2) { var message = "'" + val1 + "' does not equal expected value '" + val2 + "'"; @@ -76,8 +68,7 @@ var TestCase = { throw new TestFailureError(errorMessage || 'Condition expected to be true'); }; }, -} -exports.TestCase = TestCase; +}; function TestFailureError(message) { var error; @@ -103,5 +94,3 @@ function TestFailureError(message) { this.__proto__ = error; } -exports.TestFailureError = TestFailureError; - diff --git a/tests/index.js b/tests/index.js index 3e07192e0a..0888ad6bf5 100644 --- a/tests/index.js +++ b/tests/index.js @@ -1,22 +1,24 @@ -'use strict'; +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// -var TestCase = require('./TestCase'); -var { - LinkTypesObjectSchema, - TestObjectSchema, - IntPrimaryObjectSchema, - AllTypesObjectSchema, - DefaultValuesObjectSchema, - PersonObject, -} = require('./TestObjects'); +'use strict'; -var RealmTestSuite = { - tests: [ - require('./ArrayTests.js'), - require('./ObjectTests.js'), - require('./RealmTests.js'), - require('./ResultsTests.js'), - ], - testObjects: require('./TestObjects'), -} -module.exports = RealmTestSuite; // eslint-disable-line no-undef +exports.ArrayTests = require('./ArrayTests'); +exports.ObjectTests = require('./ObjectTests'); +exports.RealmTests = require('./RealmTests'); +exports.ResultsTests = require('./ResultsTests'); diff --git a/tests/package.json b/tests/package.json index 1516389641..07bbe26a86 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,5 +1,5 @@ { - "name": "RealmTestSuite", + "name": "realm-tests", "version": "0.0.1", "private": true } diff --git a/tests/TestObjects.js b/tests/schemas.js similarity index 91% rename from tests/TestObjects.js rename to tests/schemas.js index cd71e07519..6ecd5f6da2 100644 --- a/tests/TestObjects.js +++ b/tests/schemas.js @@ -24,7 +24,7 @@ var TestObjectSchema = { {name: 'doubleCol', type: Realm.Types.DOUBLE}, ] }; -exports.TestObjectSchema = TestObjectSchema; +exports.TestObject = TestObjectSchema; function PersonObject() {} PersonObject.prototype.schema = { @@ -51,7 +51,7 @@ var BasicTypesObjectSchema = { {name: 'dataCol', type: Realm.Types.DATA}, ] }; -exports.BasicTypesObjectSchema = BasicTypesObjectSchema; +exports.BasicTypes = BasicTypesObjectSchema; var LinkTypesObjectSchema = { name: 'LinkTypesObject', @@ -61,7 +61,7 @@ var LinkTypesObjectSchema = { {name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject'}, ] }; -exports.LinkTypesObjectSchema = LinkTypesObjectSchema; +exports.LinkTypes = LinkTypesObjectSchema; var IntPrimaryObjectSchema = { name: 'IntPrimaryObject', @@ -71,7 +71,7 @@ var IntPrimaryObjectSchema = { {name: 'valueCol', type: Realm.Types.STRING}, ] }; -exports.IntPrimaryObjectSchema = IntPrimaryObjectSchema; +exports.IntPrimary = IntPrimaryObjectSchema; var AllTypesObjectSchema = { name: 'AllTypesObject', @@ -89,7 +89,7 @@ var AllTypesObjectSchema = { {name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject'}, ] }; -exports.AllTypesObjectSchema = AllTypesObjectSchema; +exports.AllTypes = AllTypesObjectSchema; var DefaultValuesObjectSchema = { name: 'DefaultValuesObject', @@ -106,5 +106,5 @@ var DefaultValuesObjectSchema = { {name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject', default: [[2]]}, ] }; -exports.DefaultValuesObjectSchema = DefaultValuesObjectSchema; +exports.DefaultValues = DefaultValuesObjectSchema; diff --git a/tests/util.js b/tests/util.js new file mode 100644 index 0000000000..0e49fa17e6 --- /dev/null +++ b/tests/util.js @@ -0,0 +1,24 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +'use strict'; + +exports.realmPathForFile = function(str) { + var path = Realm.defaultPath; + return path.substring(0, path.lastIndexOf("/") + 1) + str; +}; From c1fa6351833adace458818afc63e95d32fb22c1b Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Thu, 8 Oct 2015 16:02:36 -0700 Subject: [PATCH 07/32] Update ReactTests for iOS 8.0 deployment target Needs this to link to GCDWebServer. --- tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj index 50795fa792..85ca031bc6 100644 --- a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj +++ b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj @@ -722,7 +722,7 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", ); - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -762,7 +762,7 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", ); - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; From 3f3710339f60fefbb08433281db19c3fed4ade2b Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Thu, 8 Oct 2015 16:02:54 -0700 Subject: [PATCH 08/32] Update ReactTests to re-install local NPM modules --- .../ios/ReactTests.xcodeproj/project.pbxproj | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj index 85ca031bc6..676b58f250 100644 --- a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj +++ b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj @@ -366,6 +366,7 @@ isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactTests" */; buildPhases = ( + F65C4BCA1BC72C5A000A1793 /* ShellScript */, 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, @@ -573,6 +574,22 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + F65C4BCA1BC72C5A000A1793 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "rm -rf ./node_modules/realm ./node_modules/realm-tests\nnpm install realm realm-tests"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 00E356EA1AD99517003FC87E /* Sources */ = { isa = PBXSourcesBuildPhase; From 88352721f7b98484eec9a0d6686e088742f310ad Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Thu, 8 Oct 2015 16:19:19 -0700 Subject: [PATCH 09/32] Make all tests explicitly require realm module --- tests/ArrayTests.js | 1 + tests/ObjectTests.js | 1 + tests/RealmJSTests.mm | 3 +++ tests/RealmTests.js | 1 + tests/ResultsTests.js | 1 + tests/package.json | 5 ++++- tests/schemas.js | 3 ++- tests/util.js | 2 ++ 8 files changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/ArrayTests.js b/tests/ArrayTests.js index 3348b2b9c6..15b02e8ce0 100644 --- a/tests/ArrayTests.js +++ b/tests/ArrayTests.js @@ -18,6 +18,7 @@ 'use strict'; +var Realm = require('realm'); var TestCase = require('./asserts'); var schemas = require('./schemas'); diff --git a/tests/ObjectTests.js b/tests/ObjectTests.js index 126ea4f279..33160c15f2 100644 --- a/tests/ObjectTests.js +++ b/tests/ObjectTests.js @@ -18,6 +18,7 @@ 'use strict'; +var Realm = require('realm'); var TestCase = require('./asserts'); var schemas = require('./schemas'); diff --git a/tests/RealmJSTests.mm b/tests/RealmJSTests.mm index c7f8b9cbcd..a12b72e77b 100644 --- a/tests/RealmJSTests.mm +++ b/tests/RealmJSTests.mm @@ -111,6 +111,9 @@ + (XCTestSuite *)defaultTestSuite { [RealmJS initializeContext:context.JSGlobalContextRef]; + // Expose the global Realm object as a global 'realm' CommonJS module. + [moduleLoader addGlobalModuleObject:context[@"Realm"] forName:@"realm"]; + NSError *error; JSValue *testObjects = [moduleLoader loadModuleFromURL:scriptURL error:&error]; diff --git a/tests/RealmTests.js b/tests/RealmTests.js index d94a085215..23fc8354dd 100644 --- a/tests/RealmTests.js +++ b/tests/RealmTests.js @@ -18,6 +18,7 @@ 'use strict'; +var Realm = require('realm'); var TestCase = require('./asserts'); var schemas = require('./schemas'); var util = require('./util'); diff --git a/tests/ResultsTests.js b/tests/ResultsTests.js index 098692e694..140c4fa695 100644 --- a/tests/ResultsTests.js +++ b/tests/ResultsTests.js @@ -18,6 +18,7 @@ 'use strict'; +var Realm = require('realm'); var TestCase = require('./asserts'); var schemas = require('./schemas'); diff --git a/tests/package.json b/tests/package.json index 07bbe26a86..36ce6dfb35 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,5 +1,8 @@ { "name": "realm-tests", "version": "0.0.1", - "private": true + "private": true, + "dependencies": { + "realm": "file:../lib" + } } diff --git a/tests/schemas.js b/tests/schemas.js index 6ecd5f6da2..af8280d54f 100644 --- a/tests/schemas.js +++ b/tests/schemas.js @@ -18,6 +18,8 @@ 'use strict'; +var Realm = require('realm'); + var TestObjectSchema = { name: 'TestObject', properties: [ @@ -107,4 +109,3 @@ var DefaultValuesObjectSchema = { ] }; exports.DefaultValues = DefaultValuesObjectSchema; - diff --git a/tests/util.js b/tests/util.js index 0e49fa17e6..6b1b1bb72d 100644 --- a/tests/util.js +++ b/tests/util.js @@ -18,6 +18,8 @@ 'use strict'; +var Realm = require('realm'); + exports.realmPathForFile = function(str) { var path = Realm.defaultPath; return path.substring(0, path.lastIndexOf("/") + 1) + str; From 39b262b2792cdd15bfb7bca8c4f337f7c47b5768 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Wed, 14 Oct 2015 14:58:42 -0700 Subject: [PATCH 10/32] Each test can now have a beforeEach and afterEach --- tests/ReactTests/index.ios.js | 73 +++++++++++++------ .../ios/ReactTests.xcodeproj/project.pbxproj | 41 +++++++++-- tests/RealmJSTests.mm | 31 ++++++-- tests/schemas.js | 18 ++--- 4 files changed, 118 insertions(+), 45 deletions(-) diff --git a/tests/ReactTests/index.ios.js b/tests/ReactTests/index.ios.js index 3a1e1702f0..96beddf121 100644 --- a/tests/ReactTests/index.ios.js +++ b/tests/ReactTests/index.ios.js @@ -8,12 +8,6 @@ var React = require('react-native'); var Realm = require('realm'); var RealmTests = require('realm-tests'); -for (var suiteName in RealmTests) { - for (var testName in RealmTests[suiteName]) { - RealmTests[suiteName][testName](); - } -} - var { AppRegistry, StyleSheet, @@ -21,23 +15,58 @@ var { View, } = React; +function runTests() { + let specialMethodNames = {'beforeEach': true, 'afterEach': true}; + + for (let suiteName in RealmTests) { + let testSuite = RealmTests[suiteName]; + + console.log('Starting suite:', suiteName); + + for (let testName in testSuite) { + if (testName in specialMethodNames || typeof testSuite[testName] != 'function') { + continue; + } + + console.log('-', testName); + + if (testSuite.beforeEach) { + testSuite.beforeEach(); + } + + try { + testSuite[testName](); + } + finally { + if (testSuite.afterEach) { + testSuite.afterEach(); + } + } + } + } +} + var ReactTests = React.createClass({ - render: function() { - return ( - - - Welcome to React Native! - - - To get started, edit index.ios.js - - - Press Cmd+R to reload,{'\n'} - Cmd+D or shake for dev menu - - - ); - } + componentDidMount() { + runTests(); + }, + + render() { + return ( + + + Welcome to React Native! + + + To get started, edit index.ios.js + + + Press Cmd+R to reload,{'\n'} + Cmd+D or shake for dev menu + + + ); + } }); var styles = StyleSheet.create({ diff --git a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj index 676b58f250..4df22ab00b 100644 --- a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj +++ b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj @@ -14,7 +14,7 @@ 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; 00E356F31AD99517003FC87E /* ReactTestsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ReactTestsTests.m */; }; - 0277991C1BBF3BC600C96559 /* libRealmReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0277991B1BBF3BB700C96559 /* libRealmReact.a */; }; + 0277991C1BBF3BC600C96559 /* RealmReact.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0277991B1BBF3BB700C96559 /* RealmReact.framework */; }; 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; @@ -24,6 +24,7 @@ 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; + F6F405C71BCE566300A1E24F /* RealmReact.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0277991B1BBF3BB700C96559 /* RealmReact.framework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -125,8 +126,29 @@ remoteGlobalIDString = 58B5119B1A9E6C1200147676; remoteInfo = RCTText; }; + F6F405B71BCE55FB00A1E24F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 027799061BBF3BB700C96559 /* RealmJS.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 02B29A151B7CF7C9008A7E6B; + remoteInfo = RealmReact; + }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + F6F405C61BCE565100A1E24F /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + F6F405C71BCE566300A1E24F /* RealmReact.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; }; @@ -164,7 +186,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 0277991C1BBF3BC600C96559 /* libRealmReact.a in Frameworks */, + 0277991C1BBF3BC600C96559 /* RealmReact.framework in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */, 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, @@ -243,7 +265,7 @@ children = ( 027799171BBF3BB700C96559 /* RealmJS.framework */, 027799191BBF3BB700C96559 /* RealmJSTests.xctest */, - 0277991B1BBF3BB700C96559 /* libRealmReact.a */, + 0277991B1BBF3BB700C96559 /* RealmReact.framework */, ); name = Products; sourceTree = ""; @@ -370,10 +392,12 @@ 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, + F6F405C61BCE565100A1E24F /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( + F6F405B81BCE55FB00A1E24F /* PBXTargetDependency */, ); name = ReactTests; productName = "Hello World"; @@ -510,10 +534,10 @@ remoteRef = 027799181BBF3BB700C96559 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 0277991B1BBF3BB700C96559 /* libRealmReact.a */ = { + 0277991B1BBF3BB700C96559 /* RealmReact.framework */ = { isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRealmReact.a; + fileType = wrapper.framework; + path = RealmReact.framework; remoteRef = 0277991A1BBF3BB700C96559 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -616,6 +640,11 @@ target = 13B07F861A680F5B00A75B9A /* ReactTests */; targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; }; + F6F405B81BCE55FB00A1E24F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RealmReact; + targetProxy = F6F405B71BCE55FB00A1E24F /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ diff --git a/tests/RealmJSTests.mm b/tests/RealmJSTests.mm index 9cec80893f..55eae49126 100644 --- a/tests/RealmJSTests.mm +++ b/tests/RealmJSTests.mm @@ -86,10 +86,12 @@ - (void)setUp { NSString *defaultDir = [[NSString stringWithUTF8String:RJSDefaultPath().c_str()] stringByDeletingLastPathComponent]; [[NSFileManager defaultManager] createDirectoryAtPath:defaultDir withIntermediateDirectories:YES attributes:nil error:nil]; - self.context.exception = nil; + [self invokeMethod:@"beforeEach"]; } - (void)tearDown { + [self invokeMethod:@"afterEach"]; + realm::Realm::s_global_cache.invalidate_all(); realm::Realm::s_global_cache.clear(); @@ -127,14 +129,24 @@ + (XCTestSuite *)defaultTestSuite { exit(1); } + NSSet *specialMethodNames = [NSSet setWithObjects:@"beforeEach", @"afterEach", nil]; + for (NSString *testName in [testObjects toDictionary]) { JSValue *testObject = testObjects[testName]; XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:testName]; Class testClass = objc_allocateClassPair(self, testName.UTF8String, 0); for (NSString *methodName in [testObject toDictionary]) { - XCTestCase *testCase = [[testClass alloc] initWithJSTestObject:testObject methodName:methodName]; - [testSuite addTest:testCase]; + if ([specialMethodNames containsObject:methodName]) { + continue; + } + + JSObjectRef jsMethod = JSValueToObject(context.JSGlobalContextRef, [testObject[methodName] JSValueRef], NULL); + + if (jsMethod && JSObjectIsFunction(context.JSGlobalContextRef, jsMethod)) { + XCTestCase *testCase = [[testClass alloc] initWithJSTestObject:testObject methodName:methodName]; + [testSuite addTest:testCase]; + } } [suite addTest:testSuite]; @@ -149,13 +161,22 @@ - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { } - (void)forwardInvocation:(NSInvocation *)anInvocation { + [self invokeMethod:NSStringFromSelector(anInvocation.selector)]; +} + +- (void)invokeMethod:(NSString *)method { JSValue *testObject = self.testObject; + + if (![testObject hasProperty:method]) { + return; + } + JSContext *context = testObject.context; + context.exception = nil; - [testObject invokeMethod:NSStringFromSelector(anInvocation.selector) withArguments:nil]; + [testObject invokeMethod:method withArguments:nil]; JSValue *exception = context.exception; - if (exception) { JSValue *message = [exception hasProperty:@"message"] ? exception[@"message"] : exception; NSString *source = [exception hasProperty:@"sourceURL"] ? [exception[@"sourceURL"] toString] : nil; diff --git a/tests/schemas.js b/tests/schemas.js index af8280d54f..407bf17160 100644 --- a/tests/schemas.js +++ b/tests/schemas.js @@ -20,13 +20,12 @@ var Realm = require('realm'); -var TestObjectSchema = { +exports.TestObject = { name: 'TestObject', properties: [ {name: 'doubleCol', type: Realm.Types.DOUBLE}, ] }; -exports.TestObject = TestObjectSchema; function PersonObject() {} PersonObject.prototype.schema = { @@ -41,7 +40,7 @@ PersonObject.prototype.description = function() { }; exports.PersonObject = PersonObject; -var BasicTypesObjectSchema = { +exports.BasicTypes = { name: 'BasicTypesObject', properties: [ {name: 'boolCol', type: Realm.Types.BOOL}, @@ -53,9 +52,8 @@ var BasicTypesObjectSchema = { {name: 'dataCol', type: Realm.Types.DATA}, ] }; -exports.BasicTypes = BasicTypesObjectSchema; -var LinkTypesObjectSchema = { +exports.LinkTypes = { name: 'LinkTypesObject', properties: [ {name: 'objectCol', type: 'TestObject'}, @@ -63,9 +61,8 @@ var LinkTypesObjectSchema = { {name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject'}, ] }; -exports.LinkTypes = LinkTypesObjectSchema; -var IntPrimaryObjectSchema = { +exports.IntPrimary = { name: 'IntPrimaryObject', primaryKey: 'primaryCol', properties: [ @@ -73,9 +70,8 @@ var IntPrimaryObjectSchema = { {name: 'valueCol', type: Realm.Types.STRING}, ] }; -exports.IntPrimary = IntPrimaryObjectSchema; -var AllTypesObjectSchema = { +exports.AllTypes = { name: 'AllTypesObject', primaryKey: 'primaryCol', properties: [ @@ -91,9 +87,8 @@ var AllTypesObjectSchema = { {name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject'}, ] }; -exports.AllTypes = AllTypesObjectSchema; -var DefaultValuesObjectSchema = { +exports.DefaultValues = { name: 'DefaultValuesObject', properties: [ {name: 'boolCol', type: Realm.Types.BOOL, default: true}, @@ -108,4 +103,3 @@ var DefaultValuesObjectSchema = { {name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject', default: [[2]]}, ] }; -exports.DefaultValues = DefaultValuesObjectSchema; From 2384f2cf9bda00060f53cf053fea2d45a765694b Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Wed, 14 Oct 2015 15:15:44 -0700 Subject: [PATCH 11/32] catch errors thrown from tests and display error information --- tests/ReactTests/index.ios.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/ReactTests/index.ios.js b/tests/ReactTests/index.ios.js index 96beddf121..f24797f52b 100644 --- a/tests/ReactTests/index.ios.js +++ b/tests/ReactTests/index.ios.js @@ -28,7 +28,6 @@ function runTests() { continue; } - console.log('-', testName); if (testSuite.beforeEach) { testSuite.beforeEach(); @@ -36,6 +35,11 @@ function runTests() { try { testSuite[testName](); + console.log('+ ' + testName); + } + catch (e) { + console.log('- ' + testName); + console.warn(e); } finally { if (testSuite.afterEach) { From d0787e36bbb5b0ec4e44d09795f66733451030fe Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Wed, 14 Oct 2015 15:19:44 -0700 Subject: [PATCH 12/32] remove android project --- tests/ReactTests/android/app/build.gradle | 29 ---- .../ReactTests/android/app/proguard-rules.pro | 17 -- .../android/app/src/main/AndroidManifest.xml | 22 --- .../java/com/reacttests/MainActivity.java | 69 -------- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 3418 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2206 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4842 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 7718 -> 0 bytes .../app/src/main/res/values/strings.xml | 3 - .../app/src/main/res/values/styles.xml | 8 - tests/ReactTests/android/build.gradle | 20 --- tests/ReactTests/android/gradle.properties | 20 --- .../android/gradle/wrapper/gradle-wrapper.jar | Bin 52266 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - tests/ReactTests/android/gradlew | 164 ------------------ tests/ReactTests/android/gradlew.bat | 90 ---------- tests/ReactTests/android/settings.gradle | 3 - tests/ReactTests/index.android.js | 52 ------ 18 files changed, 502 deletions(-) delete mode 100644 tests/ReactTests/android/app/build.gradle delete mode 100644 tests/ReactTests/android/app/proguard-rules.pro delete mode 100644 tests/ReactTests/android/app/src/main/AndroidManifest.xml delete mode 100644 tests/ReactTests/android/app/src/main/java/com/reacttests/MainActivity.java delete mode 100644 tests/ReactTests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 tests/ReactTests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 tests/ReactTests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 tests/ReactTests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 tests/ReactTests/android/app/src/main/res/values/strings.xml delete mode 100644 tests/ReactTests/android/app/src/main/res/values/styles.xml delete mode 100644 tests/ReactTests/android/build.gradle delete mode 100644 tests/ReactTests/android/gradle.properties delete mode 100644 tests/ReactTests/android/gradle/wrapper/gradle-wrapper.jar delete mode 100644 tests/ReactTests/android/gradle/wrapper/gradle-wrapper.properties delete mode 100755 tests/ReactTests/android/gradlew delete mode 100644 tests/ReactTests/android/gradlew.bat delete mode 100644 tests/ReactTests/android/settings.gradle delete mode 100644 tests/ReactTests/index.android.js diff --git a/tests/ReactTests/android/app/build.gradle b/tests/ReactTests/android/app/build.gradle deleted file mode 100644 index eb2d457b52..0000000000 --- a/tests/ReactTests/android/app/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion 23 - buildToolsVersion "23.0.1" - - defaultConfig { - applicationId "com.reacttests" - minSdkVersion 16 - targetSdkVersion 22 - versionCode 1 - versionName "1.0" - ndk { - abiFilters "armeabi-v7a", "x86" - } - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } -} - -dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:23.0.0' - compile 'com.facebook.react:react-native:0.11.+' -} diff --git a/tests/ReactTests/android/app/proguard-rules.pro b/tests/ReactTests/android/app/proguard-rules.pro deleted file mode 100644 index a92fa177ee..0000000000 --- a/tests/ReactTests/android/app/proguard-rules.pro +++ /dev/null @@ -1,17 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/tests/ReactTests/android/app/src/main/AndroidManifest.xml b/tests/ReactTests/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 6e884d8314..0000000000 --- a/tests/ReactTests/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/tests/ReactTests/android/app/src/main/java/com/reacttests/MainActivity.java b/tests/ReactTests/android/app/src/main/java/com/reacttests/MainActivity.java deleted file mode 100644 index 562cd0e38f..0000000000 --- a/tests/ReactTests/android/app/src/main/java/com/reacttests/MainActivity.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.reacttests; - -import android.app.Activity; -import android.os.Bundle; -import android.view.KeyEvent; - -import com.facebook.react.LifecycleState; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.ReactRootView; -import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; -import com.facebook.react.shell.MainReactPackage; -import com.facebook.soloader.SoLoader; - -public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { - - private ReactInstanceManager mReactInstanceManager; - private ReactRootView mReactRootView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mReactRootView = new ReactRootView(this); - - mReactInstanceManager = ReactInstanceManager.builder() - .setApplication(getApplication()) - .setBundleAssetName("index.android.bundle") - .setJSMainModuleName("index.android") - .addPackage(new MainReactPackage()) - .setUseDeveloperSupport(BuildConfig.DEBUG) - .setInitialLifecycleState(LifecycleState.RESUMED) - .build(); - - mReactRootView.startReactApplication(mReactInstanceManager, "ReactTests", null); - - setContentView(mReactRootView); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { - mReactInstanceManager.showDevOptionsDialog(); - return true; - } - return super.onKeyUp(keyCode, event); - } - - @Override - public void invokeDefaultOnBackPressed() { - super.onBackPressed(); - } - - @Override - protected void onPause() { - super.onPause(); - - if (mReactInstanceManager != null) { - mReactInstanceManager.onPause(); - } - } - - @Override - protected void onResume() { - super.onResume(); - - if (mReactInstanceManager != null) { - mReactInstanceManager.onResume(this); - } - } -} diff --git a/tests/ReactTests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/tests/ReactTests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index cde69bcccec65160d92116f20ffce4fce0b5245c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3418 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 diff --git a/tests/ReactTests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/tests/ReactTests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index bfa42f0e7b91d006d22352c9ff2f134e504e3c1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4842 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 diff --git a/tests/ReactTests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/tests/ReactTests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 324e72cdd7480cb983fa1bcc7ce686e51ef87fe7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7718 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 diff --git a/tests/ReactTests/android/app/src/main/res/values/strings.xml b/tests/ReactTests/android/app/src/main/res/values/strings.xml deleted file mode 100644 index a351b3d5d6..0000000000 --- a/tests/ReactTests/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - ReactTests - diff --git a/tests/ReactTests/android/app/src/main/res/values/styles.xml b/tests/ReactTests/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 319eb0ca10..0000000000 --- a/tests/ReactTests/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/tests/ReactTests/android/build.gradle b/tests/ReactTests/android/build.gradle deleted file mode 100644 index 32bc6f5dfa..0000000000 --- a/tests/ReactTests/android/build.gradle +++ /dev/null @@ -1,20 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - repositories { - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:1.3.0' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - mavenLocal() - jcenter() - } -} diff --git a/tests/ReactTests/android/gradle.properties b/tests/ReactTests/android/gradle.properties deleted file mode 100644 index 1fd964e90b..0000000000 --- a/tests/ReactTests/android/gradle.properties +++ /dev/null @@ -1,20 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true - -android.useDeprecatedNdk=true diff --git a/tests/ReactTests/android/gradle/wrapper/gradle-wrapper.jar b/tests/ReactTests/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index b5166dad4d90021f6a0b45268c0755719f1d5cd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52266 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 z 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 diff --git a/tests/ReactTests/android/gradle/wrapper/gradle-wrapper.properties b/tests/ReactTests/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index b9fbfaba0e..0000000000 --- a/tests/ReactTests/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip diff --git a/tests/ReactTests/android/gradlew b/tests/ReactTests/android/gradlew deleted file mode 100755 index 91a7e269e1..0000000000 --- a/tests/ReactTests/android/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/tests/ReactTests/android/gradlew.bat b/tests/ReactTests/android/gradlew.bat deleted file mode 100644 index aec99730b4..0000000000 --- a/tests/ReactTests/android/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/tests/ReactTests/android/settings.gradle b/tests/ReactTests/android/settings.gradle deleted file mode 100644 index 96e526a0e9..0000000000 --- a/tests/ReactTests/android/settings.gradle +++ /dev/null @@ -1,3 +0,0 @@ -rootProject.name = 'ReactTests' - -include ':app' diff --git a/tests/ReactTests/index.android.js b/tests/ReactTests/index.android.js deleted file mode 100644 index e5a52d27d5..0000000000 --- a/tests/ReactTests/index.android.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Sample React Native App - * https://github.com/facebook/react-native - */ -'use strict'; - -var React = require('react-native'); -var { - AppRegistry, - StyleSheet, - Text, - View, -} = React; - -var ReactTests = React.createClass({ - render: function() { - return ( - - - Welcome to React Native! - - - To get started, edit index.android.js - - - Shake or press menu button for dev menu - - - ); - } -}); - -var styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: '#F5FCFF', - }, - welcome: { - fontSize: 20, - textAlign: 'center', - margin: 10, - }, - instructions: { - textAlign: 'center', - color: '#333333', - marginBottom: 5, - }, -}); - -AppRegistry.registerComponent('ReactTests', () => ReactTests); From c8c19109108a75a35a841bb92c915a802aead609 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Wed, 14 Oct 2015 15:25:58 -0700 Subject: [PATCH 13/32] Expose global cleanupTestRealms function This handles clearing out all of the test files between each test case. --- RealmJS.xcodeproj/project.pbxproj | 4 ++++ tests/ArrayTests.js | 5 +++-- tests/ObjectTests.js | 5 +++-- tests/RealmJSTests.mm | 24 +++++++++++++-------- tests/RealmTests.js | 5 +++-- tests/ResultsTests.js | 5 +++-- tests/base-test.js | 36 +++++++++++++++++++++++++++++++ tests/util.js | 6 ++++++ 8 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 tests/base-test.js diff --git a/RealmJS.xcodeproj/project.pbxproj b/RealmJS.xcodeproj/project.pbxproj index aa78e2fa08..a9c15f967e 100644 --- a/RealmJS.xcodeproj/project.pbxproj +++ b/RealmJS.xcodeproj/project.pbxproj @@ -63,6 +63,7 @@ F64E1EF11BC3510E00E0E150 /* util.js in Resources */ = {isa = PBXBuildFile; fileRef = F64E1EF01BC3510E00E0E150 /* util.js */; settings = {ASSET_TAGS = (); }; }; F68A278C1BC2722A0063D40A /* RJSModuleLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */; settings = {ASSET_TAGS = (); }; }; F68A278E1BC30F0A0063D40A /* index.js in Resources */ = {isa = PBXBuildFile; fileRef = F68A278D1BC30F0A0063D40A /* index.js */; settings = {ASSET_TAGS = (); }; }; + F6F405F81BCF0C1A00A1E24F /* base-test.js in Resources */ = {isa = PBXBuildFile; fileRef = F6F405F71BCF0C1A00A1E24F /* base-test.js */; settings = {ASSET_TAGS = (); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -199,6 +200,7 @@ F68A278A1BC2722A0063D40A /* RJSModuleLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RJSModuleLoader.h; path = tests/RJSModuleLoader.h; sourceTree = SOURCE_ROOT; }; F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RJSModuleLoader.m; path = tests/RJSModuleLoader.m; sourceTree = SOURCE_ROOT; }; F68A278D1BC30F0A0063D40A /* index.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = index.js; path = tests/index.js; sourceTree = SOURCE_ROOT; }; + F6F405F71BCF0C1A00A1E24F /* base-test.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = "base-test.js"; path = "tests/base-test.js"; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -325,6 +327,7 @@ 0270BC781B7D020100010E03 /* Info.plist */, F68A278D1BC30F0A0063D40A /* index.js */, 0270BC7E1B7D020100010E03 /* asserts.js */, + F6F405F71BCF0C1A00A1E24F /* base-test.js */, 0270BC7F1B7D020100010E03 /* schemas.js */, F64E1EF01BC3510E00E0E150 /* util.js */, 02D456D91B7E59A500EE1299 /* ArrayTests.js */, @@ -546,6 +549,7 @@ 0270BC811B7D020100010E03 /* ObjectTests.js in Resources */, 02D456DA1B7E59A500EE1299 /* ArrayTests.js in Resources */, 0270BC861B7D020100010E03 /* schemas.js in Resources */, + F6F405F81BCF0C1A00A1E24F /* base-test.js in Resources */, F68A278E1BC30F0A0063D40A /* index.js in Resources */, 0270BC831B7D020100010E03 /* RealmTests.js in Resources */, 0270BC841B7D020100010E03 /* ResultsTests.js in Resources */, diff --git a/tests/ArrayTests.js b/tests/ArrayTests.js index 24590821fb..4fb02a6c27 100644 --- a/tests/ArrayTests.js +++ b/tests/ArrayTests.js @@ -19,10 +19,11 @@ 'use strict'; var Realm = require('realm'); +var BaseTest = require('./base-test'); var TestCase = require('./asserts'); var schemas = require('./schemas'); -module.exports = { +module.exports = BaseTest.extend({ testArrayLength: function() { var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]}); realm.write(function() { @@ -282,4 +283,4 @@ module.exports = { obj.arrayCol.splice(0, 0, obj.objectCol); }, 'can only splice in a write transaction'); }, -}; +}); diff --git a/tests/ObjectTests.js b/tests/ObjectTests.js index b8aa97c9fb..5d045e443d 100644 --- a/tests/ObjectTests.js +++ b/tests/ObjectTests.js @@ -19,10 +19,11 @@ 'use strict'; var Realm = require('realm'); +var BaseTest = require('./base-test'); var TestCase = require('./asserts'); var schemas = require('./schemas'); -module.exports = { +module.exports = BaseTest.extend({ testBasicTypesPropertyGetters: function() { var basicTypesValues = [true, 1, 1.1, 1.11, 'string', new Date(1), 'DATA']; var realm = new Realm({schema: [schemas.BasicTypes]}); @@ -147,4 +148,4 @@ module.exports = { TestCase.assertEqual(obj.arrayCol[1].doubleCol, 1); TestCase.assertEqual(obj.arrayCol[2].doubleCol, 2); }, -}; +}); diff --git a/tests/RealmJSTests.mm b/tests/RealmJSTests.mm index 55eae49126..345bd54dca 100644 --- a/tests/RealmJSTests.mm +++ b/tests/RealmJSTests.mm @@ -92,15 +92,6 @@ - (void)setUp { - (void)tearDown { [self invokeMethod:@"afterEach"]; - realm::Realm::s_global_cache.invalidate_all(); - realm::Realm::s_global_cache.clear(); - - // FIXME - find all realm files in the docs dir and delete them rather than hardcoding these - DeleteRealmFilesAtPath(RealmPathForFile(@"test.realm")); - DeleteRealmFilesAtPath(RealmPathForFile(@"test1.realm")); - DeleteRealmFilesAtPath(RealmPathForFile(@"test2.realm")); - DeleteRealmFilesAtPath(@(RJSDefaultPath().c_str())); - [super tearDown]; } @@ -116,6 +107,10 @@ + (XCTestSuite *)defaultTestSuite { RJSModuleLoader *moduleLoader = [[RJSModuleLoader alloc] initWithContext:context]; NSURL *scriptURL = [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js"]; + context[@"cleanupTestRealms"] = ^{ + [self cleanupTestRealms]; + }; + [RealmJS initializeContext:context.JSGlobalContextRef]; // Expose the global Realm object as a global 'realm' CommonJS module. @@ -155,6 +150,17 @@ + (XCTestSuite *)defaultTestSuite { return suite; } ++ (void)cleanupTestRealms { + realm::Realm::s_global_cache.invalidate_all(); + realm::Realm::s_global_cache.clear(); + + // FIXME - find all realm files in the docs dir and delete them rather than hardcoding these + DeleteRealmFilesAtPath(RealmPathForFile(@"test.realm")); + DeleteRealmFilesAtPath(RealmPathForFile(@"test1.realm")); + DeleteRealmFilesAtPath(RealmPathForFile(@"test2.realm")); + DeleteRealmFilesAtPath(@(RJSDefaultPath().c_str())); +} + - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *sig = [super methodSignatureForSelector:aSelector]; return sig ?: [NSMethodSignature signatureWithObjCTypes:"v@:"]; diff --git a/tests/RealmTests.js b/tests/RealmTests.js index 22c5662d93..b75360f2a7 100644 --- a/tests/RealmTests.js +++ b/tests/RealmTests.js @@ -19,11 +19,12 @@ 'use strict'; var Realm = require('realm'); +var BaseTest = require('./base-test'); var TestCase = require('./asserts'); var schemas = require('./schemas'); var util = require('./util'); -module.exports = { +module.exports = BaseTest.extend({ testRealmConstructorPath: function() { TestCase.assertThrows(function() { new Realm('/invalidpath'); }); TestCase.assertThrows(function() { new Realm(util.realmPathForFile('test1.realm'), 'invalidArgument'); }); @@ -291,4 +292,4 @@ module.exports = { TestCase.assertEqual(notificationCount, 1); TestCase.assertEqual(notificationName, 'DidChangeNotification'); }, -}; +}); diff --git a/tests/ResultsTests.js b/tests/ResultsTests.js index 82033fb3a3..c3180c24ce 100644 --- a/tests/ResultsTests.js +++ b/tests/ResultsTests.js @@ -19,10 +19,11 @@ 'use strict'; var Realm = require('realm'); +var BaseTest = require('./base-test'); var TestCase = require('./asserts'); var schemas = require('./schemas'); -module.exports = { +module.exports = BaseTest.extend({ testResultsLength: function() { var realm = new Realm({schema: [schemas.TestObject]}); var objects = realm.objects('TestObject'); @@ -103,4 +104,4 @@ module.exports = { TestCase.assertEqual(objects[3].doubleCol, 1); TestCase.assertEqual(objects[4].doubleCol, 0); }, -}; +}); diff --git a/tests/base-test.js b/tests/base-test.js new file mode 100644 index 0000000000..a7ad8aaaae --- /dev/null +++ b/tests/base-test.js @@ -0,0 +1,36 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +'use strict'; + +var util = require('./util'); + +var prototype = exports.prototype = {}; + +exports.extend = function(object) { + object.__proto__ = prototype; + return object; +}; + +Object.defineProperties(prototype, { + afterEach: { + value: function() { + util.cleanupTestRealms(); + } + } +}); diff --git a/tests/util.js b/tests/util.js index 6b1b1bb72d..3008d62a83 100644 --- a/tests/util.js +++ b/tests/util.js @@ -20,7 +20,13 @@ var Realm = require('realm'); +var global = (typeof global != 'undefined') ? global : this; + exports.realmPathForFile = function(str) { var path = Realm.defaultPath; return path.substring(0, path.lastIndexOf("/") + 1) + str; }; + +exports.cleanupTestRealms = function() { + global.cleanupTestRealms(); +}; From e470c5d1891a4a18bcea0b43f76ffea18f9ea6b9 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Wed, 14 Oct 2015 15:46:46 -0700 Subject: [PATCH 14/32] run tests from subclass --- RealmJS.xcodeproj/project.pbxproj | 10 ++++++++-- src/RealmJSCoreTests.h | 23 +++++++++++++++++++++++ src/RealmJSCoreTests.m | 28 ++++++++++++++++++++++++++++ tests/RealmJSTests.mm | 12 ++++++++++-- 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 src/RealmJSCoreTests.h create mode 100644 src/RealmJSCoreTests.m diff --git a/RealmJS.xcodeproj/project.pbxproj b/RealmJS.xcodeproj/project.pbxproj index a9c15f967e..277a01a5ef 100644 --- a/RealmJS.xcodeproj/project.pbxproj +++ b/RealmJS.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 02258FB31BC6E2D00075F13A /* RealmRPC.h in Headers */ = {isa = PBXBuildFile; fileRef = 02258FB11BC6E2D00075F13A /* RealmRPC.h */; settings = {ATTRIBUTES = (Public, ); }; }; 02258FB41BC6E2D00075F13A /* RealmRPC.mm in Sources */ = {isa = PBXBuildFile; fileRef = 02258FB21BC6E2D00075F13A /* RealmRPC.mm */; }; + 02409DC21BCF11D6005F3B3E /* RealmJSCoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 02409DC11BCF11D6005F3B3E /* RealmJSCoreTests.m */; settings = {ASSET_TAGS = (); }; }; 02601F031BA0F0C4007C91FF /* external_commit_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02601F011BA0F0C4007C91FF /* external_commit_helper.cpp */; }; 02601F041BA0F0C4007C91FF /* external_commit_helper.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02601F021BA0F0C4007C91FF /* external_commit_helper.hpp */; }; 02601F081BA0F0CD007C91FF /* index_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02601F051BA0F0CD007C91FF /* index_set.cpp */; }; @@ -58,11 +59,11 @@ 02D8D1F71B601984006DB49D /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; }; F636F6C81BCDB3570023F35C /* RealmReact.h in Headers */ = {isa = PBXBuildFile; fileRef = 0270BCCF1B7D067300010E03 /* RealmReact.h */; settings = {ATTRIBUTES = (Public, ); }; }; F64426C51BCDB1E200A81210 /* RealmJS.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - F67191381BCE231100AD0939 /* GCDWebServers.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 02A3C7941BC4317A00B1A7BE /* GCDWebServers.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - F6B3963D1BCE2430008BDC39 /* GCDWebServers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02A3C7941BC4317A00B1A7BE /* GCDWebServers.framework */; }; F64E1EF11BC3510E00E0E150 /* util.js in Resources */ = {isa = PBXBuildFile; fileRef = F64E1EF01BC3510E00E0E150 /* util.js */; settings = {ASSET_TAGS = (); }; }; + F67191381BCE231100AD0939 /* GCDWebServers.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 02A3C7941BC4317A00B1A7BE /* GCDWebServers.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; F68A278C1BC2722A0063D40A /* RJSModuleLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */; settings = {ASSET_TAGS = (); }; }; F68A278E1BC30F0A0063D40A /* index.js in Resources */ = {isa = PBXBuildFile; fileRef = F68A278D1BC30F0A0063D40A /* index.js */; settings = {ASSET_TAGS = (); }; }; + F6B3963D1BCE2430008BDC39 /* GCDWebServers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02A3C7941BC4317A00B1A7BE /* GCDWebServers.framework */; }; F6F405F81BCF0C1A00A1E24F /* base-test.js in Resources */ = {isa = PBXBuildFile; fileRef = F6F405F71BCF0C1A00A1E24F /* base-test.js */; settings = {ASSET_TAGS = (); }; }; /* End PBXBuildFile section */ @@ -143,6 +144,8 @@ /* Begin PBXFileReference section */ 02258FB11BC6E2D00075F13A /* RealmRPC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmRPC.h; path = src/RealmRPC.h; sourceTree = ""; }; 02258FB21BC6E2D00075F13A /* RealmRPC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmRPC.mm; path = src/RealmRPC.mm; sourceTree = ""; }; + 02409DC01BCF11D6005F3B3E /* RealmJSCoreTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmJSCoreTests.h; path = src/RealmJSCoreTests.h; sourceTree = SOURCE_ROOT; }; + 02409DC11BCF11D6005F3B3E /* RealmJSCoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RealmJSCoreTests.m; path = src/RealmJSCoreTests.m; sourceTree = SOURCE_ROOT; }; 02601F011BA0F0C4007C91FF /* external_commit_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = external_commit_helper.cpp; path = "src/object-store/apple/external_commit_helper.cpp"; sourceTree = ""; }; 02601F021BA0F0C4007C91FF /* external_commit_helper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = external_commit_helper.hpp; path = "src/object-store/apple/external_commit_helper.hpp"; sourceTree = ""; }; 02601F051BA0F0CD007C91FF /* index_set.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = index_set.cpp; path = "src/object-store/index_set.cpp"; sourceTree = ""; }; @@ -336,6 +339,8 @@ 0270BC7D1B7D020100010E03 /* ResultsTests.js */, 0270BC7A1B7D020100010E03 /* RealmJSTests.h */, 0270BC7B1B7D020100010E03 /* RealmJSTests.mm */, + 02409DC01BCF11D6005F3B3E /* RealmJSCoreTests.h */, + 02409DC11BCF11D6005F3B3E /* RealmJSCoreTests.m */, F68A278A1BC2722A0063D40A /* RJSModuleLoader.h */, F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */, ); @@ -614,6 +619,7 @@ files = ( F68A278C1BC2722A0063D40A /* RJSModuleLoader.m in Sources */, 0270BC821B7D020100010E03 /* RealmJSTests.mm in Sources */, + 02409DC21BCF11D6005F3B3E /* RealmJSCoreTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/RealmJSCoreTests.h b/src/RealmJSCoreTests.h new file mode 100644 index 0000000000..3645f0ccc0 --- /dev/null +++ b/src/RealmJSCoreTests.h @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RealmJSTests.h" + +@interface RealmJSCoreTests : RealmJSTests + +@end diff --git a/src/RealmJSCoreTests.m b/src/RealmJSCoreTests.m new file mode 100644 index 0000000000..50666d5b6c --- /dev/null +++ b/src/RealmJSCoreTests.m @@ -0,0 +1,28 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + + +#import "RealmJSCoreTests.h" + +@implementation RealmJSCoreTests + ++ (NSURL *)scriptURL { + return [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js"]; +} + +@end diff --git a/tests/RealmJSTests.mm b/tests/RealmJSTests.mm index 345bd54dca..f075bdd31d 100644 --- a/tests/RealmJSTests.mm +++ b/tests/RealmJSTests.mm @@ -101,11 +101,14 @@ - (void)invokeTest { } } ++ (NSURL *)scriptURL { + return nil; +} + + (XCTestSuite *)defaultTestSuite { XCTestSuite *suite = [super defaultTestSuite]; JSContext *context = [[JSContext alloc] init]; RJSModuleLoader *moduleLoader = [[RJSModuleLoader alloc] initWithContext:context]; - NSURL *scriptURL = [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js"]; context[@"cleanupTestRealms"] = ^{ [self cleanupTestRealms]; @@ -117,8 +120,13 @@ + (XCTestSuite *)defaultTestSuite { [moduleLoader addGlobalModuleObject:context[@"Realm"] forName:@"realm"]; NSError *error; - JSValue *testObjects = [moduleLoader loadModuleFromURL:scriptURL error:&error]; + NSURL *scriptURL = [self scriptURL]; + if (!scriptURL) { + return suite; + } + + JSValue *testObjects = [moduleLoader loadModuleFromURL:scriptURL error:&error]; if (!testObjects) { NSLog(@"index.js - %@", error); exit(1); From 7b5be78df26d8f97fe4a812a316d7db5e9e60152 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Wed, 14 Oct 2015 18:52:55 -0700 Subject: [PATCH 15/32] close to working test harness --- ReactNative/RealmReact.h | 5 ++ ReactNative/RealmReact.m | 17 ++-- .../xcschemes/RealmReact.xcscheme | 24 ++++++ src/RealmJS.h | 2 + src/RealmJS.mm | 46 +++++++++++ tests/ReactTests/index.ios.js | 4 + .../ios/ReactTests.xcodeproj/project.pbxproj | 77 +++++++++++++++---- .../xcschemes/ReactTests.xcscheme | 19 +++-- .../ios/ReactTestsTests/ReactTestsTests.m | 70 ----------------- .../ios/ReactTestsTests/RealmReactTests.m | 49 ++++++++++++ tests/RealmJSTests.mm | 54 ------------- tests/index.js | 5 ++ 12 files changed, 221 insertions(+), 151 deletions(-) delete mode 100644 tests/ReactTests/ios/ReactTestsTests/ReactTestsTests.m create mode 100644 tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m diff --git a/ReactNative/RealmReact.h b/ReactNative/RealmReact.h index fa334b79fa..91874a16a2 100644 --- a/ReactNative/RealmReact.h +++ b/ReactNative/RealmReact.h @@ -19,4 +19,9 @@ @import Foundation; @interface RealmReact : NSObject + +@property (nonatomic) id executor; + ++ (id)executor; + @end diff --git a/ReactNative/RealmReact.m b/ReactNative/RealmReact.m index 57992ea802..3a9a2b01d3 100644 --- a/ReactNative/RealmReact.m +++ b/ReactNative/RealmReact.m @@ -33,8 +33,11 @@ - (JSGlobalContextRef)ctx; @interface RealmReact () @end +static id s_executor; + @implementation RealmReact +@dynamic executor; @synthesize bridge = _bridge; + (void)load { @@ -52,12 +55,16 @@ + (NSString *)moduleName { return @"Realm"; } ++ (id)executor { + return s_executor; +} + - (void)setBridge:(RCTBridge *)bridge { _bridge = bridge; Ivar executorIvar = class_getInstanceVariable([bridge class], "_javaScriptExecutor"); - id contextExecutor = object_getIvar(bridge, executorIvar); - Ivar contextIvar = class_getInstanceVariable([contextExecutor class], "_context"); + s_executor = object_getIvar(bridge, executorIvar); + Ivar contextIvar = class_getInstanceVariable([s_executor class], "_context"); // The executor could be a RCTWebSocketExecutor, in which case it won't have a JS context. if (!contextIvar) { @@ -86,8 +93,8 @@ - (void)setBridge:(RCTBridge *)bridge { return; } - [contextExecutor executeBlockOnJavaScriptQueue:^{ - id rctJSContext = object_getIvar(contextExecutor, contextIvar); + [s_executor executeBlockOnJavaScriptQueue:^{ + id rctJSContext = object_getIvar(s_executor, contextIvar); JSGlobalContextRef ctx; if (rctJSContext) { @@ -98,7 +105,7 @@ - (void)setBridge:(RCTBridge *)bridge { if (RCTJavaScriptContext) { ctx = JSGlobalContextCreate(NULL); - object_setIvar(contextExecutor, contextIvar, [[RCTJavaScriptContext alloc] initWithJSContext:ctx]); + object_setIvar(s_executor, contextIvar, [[RCTJavaScriptContext alloc] initWithJSContext:ctx]); } else { NSLog(@"Failed to load RCTJavaScriptContext class"); diff --git a/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmReact.xcscheme b/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmReact.xcscheme index 2699e2b9bc..0ba909fd01 100644 --- a/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmReact.xcscheme +++ b/RealmJS.xcodeproj/xcshareddata/xcschemes/RealmReact.xcscheme @@ -28,7 +28,31 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + + + + + + + + + diff --git a/src/RealmJS.h b/src/RealmJS.h index ecee3d7da3..54e1476eb7 100644 --- a/src/RealmJS.h +++ b/src/RealmJS.h @@ -25,4 +25,6 @@ // add realm apis to the given js context + (void)initializeContext:(JSContextRef)ctx; ++ (void)cleanupTestRealms; + @end diff --git a/src/RealmJS.mm b/src/RealmJS.mm index fe89b02a72..6bbf9366d2 100644 --- a/src/RealmJS.mm +++ b/src/RealmJS.mm @@ -21,6 +21,8 @@ #import "RJSObject.hpp" #import "RJSUtil.hpp" +#include "shared_realm.hpp" + JSValueRef RJSTypeGet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) { return RJSValueForString(ctx, RJSTypeGet(RJSStringForJSString(propertyName))); } @@ -44,6 +46,34 @@ JSClassRef RJSRealmTypeClass() { return JSClassCreate(&realmTypesDefinition); } + +NSString *RealmPathForFile(NSString *fileName) { +#if TARGET_OS_IPHONE + NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; +#else + NSString *path = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)[0]; + path = [path stringByAppendingPathComponent:[[[NSBundle mainBundle] executablePath] lastPathComponent]]; +#endif + return [path stringByAppendingPathComponent:fileName]; +} + +static void DeleteOrThrow(NSString *path) { + NSError *error; + if (![[NSFileManager defaultManager] removeItemAtPath:path error:&error]) { + if (error.code != NSFileNoSuchFileError) { + @throw [NSException exceptionWithName:@"RLMTestException" + reason:[@"Unable to delete realm: " stringByAppendingString:error.description] + userInfo:nil]; + } + } +} + +static void DeleteRealmFilesAtPath(NSString *path) { + DeleteOrThrow(path); + DeleteOrThrow([path stringByAppendingString:@".lock"]); + DeleteOrThrow([path stringByAppendingString:@".note"]); +} + @implementation RealmJS + (void)initializeContext:(JSContextRef)ctx { @@ -56,7 +86,23 @@ + (void)initializeContext:(JSContextRef)ctx { JSObjectSetProperty(ctx, globalRealmObject, typeString, typesObject, kJSPropertyAttributeNone, &exception); JSStringRelease(typeString); + [JSContext contextWithJSGlobalContextRef:JSContextGetGlobalContext(ctx)][@"cleanupTestRealms"] = ^{ + [RealmJS cleanupTestRealms]; + }; + assert(!exception); } ++ (void)cleanupTestRealms { + realm::Realm::s_global_cache.invalidate_all(); + realm::Realm::s_global_cache.clear(); + + // FIXME - find all realm files in the docs dir and delete them rather than hardcoding these + + DeleteRealmFilesAtPath(RealmPathForFile(@"test.realm")); + DeleteRealmFilesAtPath(RealmPathForFile(@"test1.realm")); + DeleteRealmFilesAtPath(RealmPathForFile(@"test2.realm")); + DeleteRealmFilesAtPath(@(RJSDefaultPath().c_str())); +} + @end diff --git a/tests/ReactTests/index.ios.js b/tests/ReactTests/index.ios.js index f24797f52b..1396ab3224 100644 --- a/tests/ReactTests/index.ios.js +++ b/tests/ReactTests/index.ios.js @@ -21,6 +21,10 @@ function runTests() { for (let suiteName in RealmTests) { let testSuite = RealmTests[suiteName]; + if (typeof testSuite != 'object') { + continue; + } + console.log('Starting suite:', suiteName); for (let testName in testSuite) { diff --git a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj index 4df22ab00b..7cb351fc61 100644 --- a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj +++ b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj @@ -13,7 +13,18 @@ 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; }; 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; - 00E356F31AD99517003FC87E /* ReactTestsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ReactTestsTests.m */; }; + 00E356F31AD99517003FC87E /* RealmReactTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* RealmReactTests.m */; }; + 02409E1E1BCF1F2E005F3B3E /* RealmJSTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 02409E1B1BCF1F2E005F3B3E /* RealmJSTests.mm */; settings = {ASSET_TAGS = (); }; }; + 02409E1F1BCF1F2E005F3B3E /* RJSModuleLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 02409E1D1BCF1F2E005F3B3E /* RJSModuleLoader.m */; settings = {ASSET_TAGS = (); }; }; + 02409E291BCF1F45005F3B3E /* ArrayTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E201BCF1F45005F3B3E /* ArrayTests.js */; }; + 02409E2A1BCF1F45005F3B3E /* asserts.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E211BCF1F45005F3B3E /* asserts.js */; }; + 02409E2B1BCF1F45005F3B3E /* base-test.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E221BCF1F45005F3B3E /* base-test.js */; }; + 02409E2C1BCF1F45005F3B3E /* index.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E231BCF1F45005F3B3E /* index.js */; }; + 02409E2D1BCF1F45005F3B3E /* ObjectTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E241BCF1F45005F3B3E /* ObjectTests.js */; }; + 02409E2E1BCF1F45005F3B3E /* RealmTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E251BCF1F45005F3B3E /* RealmTests.js */; }; + 02409E2F1BCF1F45005F3B3E /* ResultsTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E261BCF1F45005F3B3E /* ResultsTests.js */; }; + 02409E301BCF1F45005F3B3E /* schemas.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E271BCF1F45005F3B3E /* schemas.js */; }; + 02409E311BCF1F45005F3B3E /* util.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E281BCF1F45005F3B3E /* util.js */; }; 0277991C1BBF3BC600C96559 /* RealmReact.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0277991B1BBF3BB700C96559 /* RealmReact.framework */; }; 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; @@ -156,9 +167,22 @@ 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; }; 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; - 00E356EE1AD99517003FC87E /* ReactTestsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactTestsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356EE1AD99517003FC87E /* RealmReactTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RealmReactTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 00E356F21AD99517003FC87E /* ReactTestsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReactTestsTests.m; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* RealmReactTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RealmReactTests.m; sourceTree = ""; }; + 02409E1A1BCF1F2E005F3B3E /* RealmJSTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmJSTests.h; path = ../../../RealmJSTests.h; sourceTree = ""; }; + 02409E1B1BCF1F2E005F3B3E /* RealmJSTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmJSTests.mm; path = ../../../RealmJSTests.mm; sourceTree = ""; }; + 02409E1C1BCF1F2E005F3B3E /* RJSModuleLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RJSModuleLoader.h; path = ../../../RJSModuleLoader.h; sourceTree = ""; }; + 02409E1D1BCF1F2E005F3B3E /* RJSModuleLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RJSModuleLoader.m; path = ../../../RJSModuleLoader.m; sourceTree = ""; }; + 02409E201BCF1F45005F3B3E /* ArrayTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ArrayTests.js; path = ../../ArrayTests.js; sourceTree = ""; }; + 02409E211BCF1F45005F3B3E /* asserts.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = asserts.js; path = ../../asserts.js; sourceTree = ""; }; + 02409E221BCF1F45005F3B3E /* base-test.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = "base-test.js"; path = "../../base-test.js"; sourceTree = ""; }; + 02409E231BCF1F45005F3B3E /* index.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = index.js; path = ../../index.js; sourceTree = ""; }; + 02409E241BCF1F45005F3B3E /* ObjectTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ObjectTests.js; path = ../../ObjectTests.js; sourceTree = ""; }; + 02409E251BCF1F45005F3B3E /* RealmTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = RealmTests.js; path = ../../RealmTests.js; sourceTree = ""; }; + 02409E261BCF1F45005F3B3E /* ResultsTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ResultsTests.js; path = ../../ResultsTests.js; sourceTree = ""; }; + 02409E271BCF1F45005F3B3E /* schemas.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = schemas.js; path = ../../schemas.js; sourceTree = ""; }; + 02409E281BCF1F45005F3B3E /* util.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = util.js; path = ../../util.js; sourceTree = ""; }; 027799061BBF3BB700C96559 /* RealmJS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RealmJS.xcodeproj; path = ../../../RealmJS.xcodeproj; sourceTree = ""; }; 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; @@ -243,12 +267,17 @@ name = Products; sourceTree = ""; }; - 00E356EF1AD99517003FC87E /* ReactTestsTests */ = { + 00E356EF1AD99517003FC87E /* RealmReactTests */ = { isa = PBXGroup; children = ( - 00E356F21AD99517003FC87E /* ReactTestsTests.m */, + 00E356F21AD99517003FC87E /* RealmReactTests.m */, + 02409E1A1BCF1F2E005F3B3E /* RealmJSTests.h */, + 02409E1B1BCF1F2E005F3B3E /* RealmJSTests.mm */, + 02409E1C1BCF1F2E005F3B3E /* RJSModuleLoader.h */, + 02409E1D1BCF1F2E005F3B3E /* RJSModuleLoader.m */, 00E356F01AD99517003FC87E /* Supporting Files */, ); + name = RealmReactTests; path = ReactTestsTests; sourceTree = ""; }; @@ -345,9 +374,18 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( + 02409E201BCF1F45005F3B3E /* ArrayTests.js */, + 02409E211BCF1F45005F3B3E /* asserts.js */, + 02409E221BCF1F45005F3B3E /* base-test.js */, + 02409E231BCF1F45005F3B3E /* index.js */, + 02409E241BCF1F45005F3B3E /* ObjectTests.js */, + 02409E251BCF1F45005F3B3E /* RealmTests.js */, + 02409E261BCF1F45005F3B3E /* ResultsTests.js */, + 02409E271BCF1F45005F3B3E /* schemas.js */, + 02409E281BCF1F45005F3B3E /* util.js */, 13B07FAE1A68108700A75B9A /* ReactTests */, 832341AE1AAA6A7D00B99B32 /* Libraries */, - 00E356EF1AD99517003FC87E /* ReactTestsTests */, + 00E356EF1AD99517003FC87E /* RealmReactTests */, 83CBBA001A601CBA00E9B192 /* Products */, ); indentWidth = 2; @@ -358,7 +396,7 @@ isa = PBXGroup; children = ( 13B07F961A680F5B00A75B9A /* ReactTests.app */, - 00E356EE1AD99517003FC87E /* ReactTestsTests.xctest */, + 00E356EE1AD99517003FC87E /* RealmReactTests.xctest */, ); name = Products; sourceTree = ""; @@ -366,9 +404,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 00E356ED1AD99517003FC87E /* ReactTestsTests */ = { + 00E356ED1AD99517003FC87E /* RealmReactTests */ = { isa = PBXNativeTarget; - buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactTestsTests" */; + buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "RealmReactTests" */; buildPhases = ( 00E356EA1AD99517003FC87E /* Sources */, 00E356EB1AD99517003FC87E /* Frameworks */, @@ -379,9 +417,9 @@ dependencies = ( 00E356F51AD99517003FC87E /* PBXTargetDependency */, ); - name = ReactTestsTests; + name = RealmReactTests; productName = ReactTestsTests; - productReference = 00E356EE1AD99517003FC87E /* ReactTestsTests.xctest */; + productReference = 00E356EE1AD99517003FC87E /* RealmReactTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 13B07F861A680F5B00A75B9A /* ReactTests */ = { @@ -479,7 +517,7 @@ projectRoot = ""; targets = ( 13B07F861A680F5B00A75B9A /* ReactTests */, - 00E356ED1AD99517003FC87E /* ReactTestsTests */, + 00E356ED1AD99517003FC87E /* RealmReactTests */, ); }; /* End PBXProject section */ @@ -583,6 +621,15 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 02409E291BCF1F45005F3B3E /* ArrayTests.js in Resources */, + 02409E2A1BCF1F45005F3B3E /* asserts.js in Resources */, + 02409E2B1BCF1F45005F3B3E /* base-test.js in Resources */, + 02409E2C1BCF1F45005F3B3E /* index.js in Resources */, + 02409E2D1BCF1F45005F3B3E /* ObjectTests.js in Resources */, + 02409E2E1BCF1F45005F3B3E /* RealmTests.js in Resources */, + 02409E2F1BCF1F45005F3B3E /* ResultsTests.js in Resources */, + 02409E301BCF1F45005F3B3E /* schemas.js in Resources */, + 02409E311BCF1F45005F3B3E /* util.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -619,7 +666,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 00E356F31AD99517003FC87E /* ReactTestsTests.m in Sources */, + 02409E1F1BCF1F2E005F3B3E /* RJSModuleLoader.m in Sources */, + 02409E1E1BCF1F2E005F3B3E /* RealmJSTests.mm in Sources */, + 00E356F31AD99517003FC87E /* RealmReactTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -818,7 +867,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactTestsTests" */ = { + 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "RealmReactTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 00E356F61AD99517003FC87E /* Debug */, diff --git a/tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme b/tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme index a0d2883bd3..74ba8c85c8 100644 --- a/tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme +++ b/tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme @@ -29,26 +29,26 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -62,15 +62,18 @@ ReferencedContainer = "container:ReactTests.xcodeproj"> + + @@ -86,10 +89,10 @@ diff --git a/tests/ReactTests/ios/ReactTestsTests/ReactTestsTests.m b/tests/ReactTests/ios/ReactTestsTests/ReactTestsTests.m deleted file mode 100644 index c9770887b8..0000000000 --- a/tests/ReactTests/ios/ReactTestsTests/ReactTestsTests.m +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import -#import - -#import "RCTLog.h" -#import "RCTRootView.h" - -#define TIMEOUT_SECONDS 240 -#define TEXT_TO_LOOK_FOR @"Welcome to React Native!" - -@interface ReactTestsTests : XCTestCase - -@end - -@implementation ReactTestsTests - -- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test -{ - if (test(view)) { - return YES; - } - for (UIView *subview in [view subviews]) { - if ([self findSubviewInView:subview matching:test]) { - return YES; - } - } - return NO; -} - -- (void)testRendersWelcomeScreen -{ - UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; - BOOL foundElement = NO; - - __block NSString *redboxError = nil; - RCTSetLogFunction(^(RCTLogLevel level, NSString *fileName, NSNumber *lineNumber, NSString *message) { - if (level >= RCTLogLevelError) { - redboxError = message; - } - }); - - while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - - foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { - if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { - return YES; - } - return NO; - }]; - } - - RCTSetLogFunction(RCTDefaultLogFunction); - - XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); - XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); -} - - -@end diff --git a/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m new file mode 100644 index 0000000000..01899f696d --- /dev/null +++ b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RealmJSTests.h" +#import "../../node_modules/react-native/React/Base/RCTJavaScriptExecutor.h" +#import "../../node_modules/react-native/React/Base/RCTBridge.h" + +@import RealmReact; + +@interface RealmReactTests : RealmJSTests +@end + + +@implementation RealmReactTests + ++ (NSURL *)scriptURL { + return [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js"]; +} + +- (void)invokeMethod:(NSString *)method { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + [self expectationForNotification:RCTJavaScriptDidLoadNotification object:nil handler:^BOOL(NSNotification * _Nonnull notification) { + return YES; + }]; + [self waitForExpectationsWithTimeout:10000000 handler:^(NSError * _Nullable error) { + }]; + }); + + dispatch_group_t group = dispatch_group_create(); + dispatch_group_enter(group); + + id executor = [RealmReact executor]; + [executor executeBlockOnJavaScriptQueue:^{ + [executor executeJSCall:@"realm-tests" method:@"executeTest" arguments:@[NSStringFromClass(self.class), method] callback:^(id json, NSError *error) { + XCTAssertNil(error, @"%@", [error description]); + dispatch_group_leave(group); + }]; + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + }]; +} + +@end diff --git a/tests/RealmJSTests.mm b/tests/RealmJSTests.mm index f075bdd31d..dfaeec0951 100644 --- a/tests/RealmJSTests.mm +++ b/tests/RealmJSTests.mm @@ -19,44 +19,8 @@ #import #import "RealmJSTests.h" -#import "RJSUtil.hpp" -#import "RJSRealm.hpp" #import "RJSModuleLoader.h" -#import "shared_realm.hpp" - -NSString *RealmPathForFile(NSString *fileName) { -#if TARGET_OS_IPHONE - NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; -#else - NSString *path = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)[0]; - path = [path stringByAppendingPathComponent:[[[NSBundle mainBundle] executablePath] lastPathComponent]]; -#endif - return [path stringByAppendingPathComponent:fileName]; -} - - -NSString *TestRealmPath() { - return RealmPathForFile(@"test.realm"); -} - -static void DeleteOrThrow(NSString *path) { - NSError *error; - if (![[NSFileManager defaultManager] removeItemAtPath:path error:&error]) { - if (error.code != NSFileNoSuchFileError) { - @throw [NSException exceptionWithName:@"RLMTestException" - reason:[@"Unable to delete realm: " stringByAppendingString:error.description] - userInfo:nil]; - } - } -} - -static void DeleteRealmFilesAtPath(NSString *path) { - DeleteOrThrow(path); - DeleteOrThrow([path stringByAppendingString:@".lock"]); - DeleteOrThrow([path stringByAppendingString:@".note"]); -} - @interface RealmJSTests () @property (nonatomic, strong) JSValue *testObject; @@ -83,9 +47,6 @@ - (JSContext *)context { - (void)setUp { [super setUp]; - NSString *defaultDir = [[NSString stringWithUTF8String:RJSDefaultPath().c_str()] stringByDeletingLastPathComponent]; - [[NSFileManager defaultManager] createDirectoryAtPath:defaultDir withIntermediateDirectories:YES attributes:nil error:nil]; - [self invokeMethod:@"beforeEach"]; } @@ -110,10 +71,6 @@ + (XCTestSuite *)defaultTestSuite { JSContext *context = [[JSContext alloc] init]; RJSModuleLoader *moduleLoader = [[RJSModuleLoader alloc] initWithContext:context]; - context[@"cleanupTestRealms"] = ^{ - [self cleanupTestRealms]; - }; - [RealmJS initializeContext:context.JSGlobalContextRef]; // Expose the global Realm object as a global 'realm' CommonJS module. @@ -158,17 +115,6 @@ + (XCTestSuite *)defaultTestSuite { return suite; } -+ (void)cleanupTestRealms { - realm::Realm::s_global_cache.invalidate_all(); - realm::Realm::s_global_cache.clear(); - - // FIXME - find all realm files in the docs dir and delete them rather than hardcoding these - DeleteRealmFilesAtPath(RealmPathForFile(@"test.realm")); - DeleteRealmFilesAtPath(RealmPathForFile(@"test1.realm")); - DeleteRealmFilesAtPath(RealmPathForFile(@"test2.realm")); - DeleteRealmFilesAtPath(@(RJSDefaultPath().c_str())); -} - - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *sig = [super methodSignatureForSelector:aSelector]; return sig ?: [NSMethodSignature signatureWithObjCTypes:"v@:"]; diff --git a/tests/index.js b/tests/index.js index 0888ad6bf5..9ea35ae388 100644 --- a/tests/index.js +++ b/tests/index.js @@ -22,3 +22,8 @@ exports.ArrayTests = require('./ArrayTests'); exports.ObjectTests = require('./ObjectTests'); exports.RealmTests = require('./RealmTests'); exports.ResultsTests = require('./ResultsTests'); + +exports.executeTest = function(suiteName, testName) { + var suite = exports[suiteName]; + suite[textName](); +}; From 94521b73bb75d1a048a84a477a694e27916163fe Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Thu, 15 Oct 2015 03:00:13 -0700 Subject: [PATCH 16/32] Properly serialize args to create Realm through RPC An exception was thrown when parsing the JSON when only a string was passed. This is better and no longer uses the Objective-C API for converting the dictionary to a JSValue. --- lib/realm.js | 2 +- lib/rpc.js | 8 ++++++-- src/RealmRPC.mm | 47 ++++++++++++++++++++++++++++------------------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/lib/realm.js b/lib/realm.js index 45cd8de6ae..80a461b281 100644 --- a/lib/realm.js +++ b/lib/realm.js @@ -30,7 +30,7 @@ class Realm { } } - let realmId = this[realmKey] = rpc.createRealm(config); + let realmId = this[realmKey] = rpc.createRealm(Array.from(arguments)); objects.registerConstructors(realmId, constructors); } diff --git a/lib/rpc.js b/lib/rpc.js index d0fb118570..f9af56500b 100644 --- a/lib/rpc.js +++ b/lib/rpc.js @@ -41,8 +41,12 @@ function registerTypeConverter(type, handler) { typeConverters[type] = handler; } -function createRealm(config) { - return sendRequest('create_realm', config); +function createRealm(args) { + if (args) { + args = args.map((arg) => serialize(null, arg)); + } + + return sendRequest('create_realm', {arguments: args}); } function callRealmMethod(realmId, name, args) { diff --git a/src/RealmRPC.mm b/src/RealmRPC.mm index c8a2a5a605..7f2fdf9ae1 100644 --- a/src/RealmRPC.mm +++ b/src/RealmRPC.mm @@ -45,31 +45,40 @@ - (instancetype)init { self = [super init]; if (self) { _context = JSGlobalContextCreate(NULL); + _requests["/create_realm"] = [=](NSDictionary *dict) { - // We should have a method for serializing schema rather than relying on JSValue - JSValueRef value = [[JSValue valueWithObject:dict - inContext:[JSContext contextWithJSGlobalContextRef:_context]] JSValueRef]; - JSValueRef ex = NULL; - RPCObjectID realmId = [self storeObject:RealmConstructor(_context, NULL, 1, &value, &ex)]; - if (ex) { - return @{@"error": @(RJSStringForValue(_context, ex).c_str())}; + NSArray *args = dict[@"arguments"]; + NSUInteger argCount = args.count; + JSValueRef argValues[argCount]; + + for (NSUInteger i = 0; i < argCount; i++) { + argValues[i] = [self valueFromDictionary:args[i]]; + } + + JSValueRef exception = NULL; + JSObjectRef realmObject = RealmConstructor(_context, NULL, argCount, argValues, &exception); + + if (exception) { + return @{@"error": @(RJSStringForValue(_context, exception).c_str())}; } + + RPCObjectID realmId = [self storeObject:realmObject]; return @{@"result": @(realmId)}; }; _requests["/begin_transaction"] = [=](NSDictionary *dict) { RPCObjectID realmId = [dict[@"realmId"] unsignedLongValue]; RJSGetInternal(_objects[realmId])->get()->begin_transaction(); - return @{}; + return nil; }; _requests["/cancel_transaction"] = [=](NSDictionary *dict) { RPCObjectID realmId = [dict[@"realmId"] unsignedLongValue]; RJSGetInternal(_objects[realmId])->get()->cancel_transaction(); - return @{}; + return nil; }; _requests["/commit_transaction"] = [=](NSDictionary *dict) { RPCObjectID realmId = [dict[@"realmId"] unsignedLongValue]; RJSGetInternal(_objects[realmId])->get()->commit_transaction(); - return @{}; + return nil; }; _requests["/call_realm_method"] = [=](NSDictionary *dict) { NSString *name = dict[@"name"]; @@ -106,7 +115,7 @@ - (instancetype)init { RPCObjectID oid = [dict[@"id"] unsignedLongValue]; JSValueUnprotect(_context, _objects[oid]); _objects.erase(oid); - return @{}; + return nil; }; _requests["/get_results_size"] = [=](NSDictionary *dict) { RPCObjectID resultsId = [dict[@"resultsId"] unsignedLongValue]; @@ -185,26 +194,26 @@ - (NSDictionary *)performRequest:(NSString *)name args:(NSDictionary *)args { response = @{@"error": [@"exception thrown: " stringByAppendingString:@(exception.what())]}; } }); - return response; + return response ?: @{}; } - (NSDictionary *)performObjectMethod:(const char *)name classMethods:(const JSStaticFunction [])methods args:(NSArray *)args objectId:(RPCObjectID)oid { - NSUInteger count = args.count; - JSValueRef argValues[count]; - for (NSUInteger i = 0; i < count; i++) { + NSUInteger argCount = args.count; + JSValueRef argValues[argCount]; + for (NSUInteger i = 0; i < argCount; i++) { argValues[i] = [self valueFromDictionary:args[i]]; } size_t index = 0; while (methods[index].name) { if (!strcmp(methods[index].name, name)) { - JSValueRef ex = NULL; - JSValueRef ret = methods[index].callAsFunction(_context, NULL, _objects[oid], count, argValues, &ex); - if (ex) { - return @{@"error": @(RJSStringForValue(_context, ex).c_str())}; + JSValueRef exception = NULL; + JSValueRef ret = methods[index].callAsFunction(_context, NULL, _objects[oid], argCount, argValues, &exception); + if (exception) { + return @{@"error": @(RJSStringForValue(_context, exception).c_str())}; } return @{@"result": [self resultForJSValue:ret]}; } From 18f97b6ec1093f7c8554df1bdb2ca79d0e4211c7 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Thu, 15 Oct 2015 03:01:34 -0700 Subject: [PATCH 17/32] Always set Access-Control-Allow-Origin on response Error responses were not having this set, which obscured the true error from the client. --- ReactNative/RealmReact.m | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ReactNative/RealmReact.m b/ReactNative/RealmReact.m index 3a9a2b01d3..c05526a671 100644 --- a/ReactNative/RealmReact.m +++ b/ReactNative/RealmReact.m @@ -79,12 +79,16 @@ - (void)setBridge:(RCTBridge *)bridge { NSError *error; NSData *data = [(GCDWebServerDataRequest *)request data]; NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; - if (error) { - NSLog(@"%@", error); - return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_UnprocessableEntity underlyingError:error message:@"Invalid RPC request"]; + GCDWebServerResponse *response; + + if (error || ![json isKindOfClass:[NSDictionary class]]) { + NSLog(@"Invalid RPC request - %@", error ?: json); + response = [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_UnprocessableEntity underlyingError:error message:@"Invalid RPC request"]; + } + else { + response = [GCDWebServerDataResponse responseWithJSONObject:[rpcServer performRequest:request.path args:json]]; } - - GCDWebServerDataResponse *response = [GCDWebServerDataResponse responseWithJSONObject:[rpcServer performRequest:request.path args:json]]; + [response setValue:@"http://localhost:8081" forAdditionalHeader:@"Access-Control-Allow-Origin"]; return response; }]; From 7a79ac8803d4304d2804424edbbcd29b6d64a0de Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Thu, 15 Oct 2015 03:12:28 -0700 Subject: [PATCH 18/32] Make Xcode tests run in React environment The deleteTestFiles() function is now added to the Realm object, so that it's easy for the RPC module to handle this as well. We can only do this in testing environments in the future. --- ReactNative/RealmReact.h | 2 +- ReactNative/RealmReact.m | 1 - lib/realm.js | 6 +++++ lib/rpc.js | 8 ++++++- src/RJSUtil.mm | 5 ++-- src/RealmJS.h | 2 +- src/RealmJS.mm | 18 +++++++++----- src/RealmRPC.mm | 4 ++++ tests/ReactTests/index.ios.js | 5 ---- .../ios/ReactTests.xcodeproj/project.pbxproj | 17 +++++-------- .../xcschemes/ReactTests.xcscheme | 2 +- tests/ReactTests/ios/ReactTests/Info.plist | 17 +++++++------ .../ReactTests/ios/ReactTestsTests/Info.plist | 2 +- .../ios/ReactTestsTests/RealmReactTests.m | 24 +++++++++---------- tests/RealmJSTests.h | 3 --- tests/base-test.js | 9 +++++-- tests/index.js | 4 ---- tests/util.js | 6 ----- 18 files changed, 69 insertions(+), 66 deletions(-) diff --git a/ReactNative/RealmReact.h b/ReactNative/RealmReact.h index 91874a16a2..481b9fa21a 100644 --- a/ReactNative/RealmReact.h +++ b/ReactNative/RealmReact.h @@ -20,7 +20,7 @@ @interface RealmReact : NSObject -@property (nonatomic) id executor; +@property (nonatomic, readonly) id executor; + (id)executor; diff --git a/ReactNative/RealmReact.m b/ReactNative/RealmReact.m index c05526a671..286fc01793 100644 --- a/ReactNative/RealmReact.m +++ b/ReactNative/RealmReact.m @@ -37,7 +37,6 @@ @interface RealmReact () @implementation RealmReact -@dynamic executor; @synthesize bridge = _bridge; + (void)load { diff --git a/lib/realm.js b/lib/realm.js index 80a461b281..3110ec0add 100644 --- a/lib/realm.js +++ b/lib/realm.js @@ -83,4 +83,10 @@ class Realm { Object.defineProperty(Realm, 'Types', {value: types}); +Object.defineProperty(Realm, 'deleteTestFiles', { + value: function() { + rpc.deleteTestFiles(); + } +}); + module.exports = Realm; diff --git a/lib/rpc.js b/lib/rpc.js index f9af56500b..89c13ab62b 100644 --- a/lib/rpc.js +++ b/lib/rpc.js @@ -37,6 +37,8 @@ exports.beginTransaction = beginTransaction; exports.cancelTransaction = cancelTransaction; exports.commitTransaction = commitTransaction; +exports.deleteTestFiles = deleteTestFiles; + function registerTypeConverter(type, handler) { typeConverters[type] = handler; } @@ -111,6 +113,10 @@ function commitTransaction(realmId) { sendRequest('commit_transaction', {realmId}); } +function deleteTestFiles() { + sendRequest('delete_test_files'); +} + function serialize(realmId, value) { if (!value || typeof value != 'object') { return {value: value}; @@ -153,7 +159,7 @@ function deserialize(realmId, info) { } function sendRequest(command, data) { - let body = JSON.stringify(data); + let body = JSON.stringify(data || {}); let request = new XMLHttpRequest(); let url = 'http://' + DEVICE_HOST + '/' + command; diff --git a/src/RJSUtil.mm b/src/RJSUtil.mm index b8603dd80b..e64dd061f8 100644 --- a/src/RJSUtil.mm +++ b/src/RJSUtil.mm @@ -20,10 +20,11 @@ using namespace realm; -JSObjectRef RJSRegisterGlobalClass(JSContextRef ctx, JSObjectRef globalObject, JSClassRef classRef, const char * name, JSValueRef *exception) { +JSObjectRef RJSRegisterGlobalClass(JSContextRef ctx, JSObjectRef globalObject, JSClassRef classRef, const char *name, JSValueRef *exception) { JSObjectRef classObject = JSObjectMake(ctx, classRef, NULL); JSStringRef nameString = JSStringCreateWithUTF8CString(name); - JSObjectSetProperty(ctx, globalObject, nameString, classObject, kJSPropertyAttributeNone, exception); + JSPropertyAttributes attributes = kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete; + JSObjectSetProperty(ctx, globalObject, nameString, classObject, attributes, exception); JSStringRelease(nameString); return classObject; } diff --git a/src/RealmJS.h b/src/RealmJS.h index 54e1476eb7..f10133ffd6 100644 --- a/src/RealmJS.h +++ b/src/RealmJS.h @@ -25,6 +25,6 @@ // add realm apis to the given js context + (void)initializeContext:(JSContextRef)ctx; -+ (void)cleanupTestRealms; ++ (void)deleteTestFiles; @end diff --git a/src/RealmJS.mm b/src/RealmJS.mm index 6bbf9366d2..246d11d6e8 100644 --- a/src/RealmJS.mm +++ b/src/RealmJS.mm @@ -46,7 +46,6 @@ JSClassRef RJSRealmTypeClass() { return JSClassCreate(&realmTypesDefinition); } - NSString *RealmPathForFile(NSString *fileName) { #if TARGET_OS_IPHONE NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; @@ -74,6 +73,11 @@ static void DeleteRealmFilesAtPath(NSString *path) { DeleteOrThrow([path stringByAppendingString:@".note"]); } +static JSValueRef DeleteTestFiles(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { + [RealmJS deleteTestFiles]; + return NULL; +} + @implementation RealmJS + (void)initializeContext:(JSContextRef)ctx { @@ -83,17 +87,19 @@ + (void)initializeContext:(JSContextRef)ctx { JSObjectRef globalRealmObject = RJSRegisterGlobalClass(ctx, globalObject, RJSRealmConstructorClass(), "Realm", &exception); JSObjectRef typesObject = JSObjectMake(ctx, RJSRealmTypeClass(), NULL); JSStringRef typeString = JSStringCreateWithUTF8CString("Types"); - JSObjectSetProperty(ctx, globalRealmObject, typeString, typesObject, kJSPropertyAttributeNone, &exception); + JSPropertyAttributes attributes = kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete; + JSObjectSetProperty(ctx, globalRealmObject, typeString, typesObject, attributes, &exception); JSStringRelease(typeString); - [JSContext contextWithJSGlobalContextRef:JSContextGetGlobalContext(ctx)][@"cleanupTestRealms"] = ^{ - [RealmJS cleanupTestRealms]; - }; + JSStringRef deleteTestFilesString = JSStringCreateWithUTF8CString("deleteTestFiles"); + JSObjectRef deleteTestFilesFunction = JSObjectMakeFunctionWithCallback(ctx, deleteTestFilesString, DeleteTestFiles); + JSObjectSetProperty(ctx, globalRealmObject, deleteTestFilesString, deleteTestFilesFunction, attributes, &exception); + JSStringRelease(deleteTestFilesString); assert(!exception); } -+ (void)cleanupTestRealms { ++ (void)deleteTestFiles { realm::Realm::s_global_cache.invalidate_all(); realm::Realm::s_global_cache.clear(); diff --git a/src/RealmRPC.mm b/src/RealmRPC.mm index 7f2fdf9ae1..531e5f064d 100644 --- a/src/RealmRPC.mm +++ b/src/RealmRPC.mm @@ -179,6 +179,10 @@ - (instancetype)init { args:dict[@"arguments"] objectId:[dict[@"listId"] unsignedLongValue]]; }; + _requests["/delete_test_files"] = [=](NSDictionary *dict) { + [RealmJS deleteTestFiles]; + return nil; + }; } return self; } diff --git a/tests/ReactTests/index.ios.js b/tests/ReactTests/index.ios.js index 1396ab3224..39316ad2e7 100644 --- a/tests/ReactTests/index.ios.js +++ b/tests/ReactTests/index.ios.js @@ -21,10 +21,6 @@ function runTests() { for (let suiteName in RealmTests) { let testSuite = RealmTests[suiteName]; - if (typeof testSuite != 'object') { - continue; - } - console.log('Starting suite:', suiteName); for (let testName in testSuite) { @@ -32,7 +28,6 @@ function runTests() { continue; } - if (testSuite.beforeEach) { testSuite.beforeEach(); } diff --git a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj index 7cb351fc61..b979c4e1ba 100644 --- a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj +++ b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj @@ -448,7 +448,7 @@ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0610; + LastUpgradeCheck = 0700; ORGANIZATIONNAME = Facebook; TargetAttributes = { 00E356ED1AD99517003FC87E = { @@ -724,6 +724,7 @@ INFOPLIST_FILE = ReactTestsTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactTests.app/ReactTests"; }; @@ -741,6 +742,7 @@ INFOPLIST_FILE = ReactTestsTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactTests.app/ReactTests"; }; @@ -750,14 +752,10 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/../node_modules/react-native/React/**", - ); INFOPLIST_FILE = ReactTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = ReactTests; }; name = Debug; @@ -766,14 +764,10 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/../node_modules/react-native/React/**", - ); INFOPLIST_FILE = ReactTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = ReactTests; }; name = Release; @@ -798,6 +792,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; diff --git a/tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme b/tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme index 74ba8c85c8..00978f6d6d 100644 --- a/tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme +++ b/tests/ReactTests/ios/ReactTests.xcodeproj/xcshareddata/xcschemes/ReactTests.xcscheme @@ -1,6 +1,6 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -22,6 +22,13 @@ 1 LSRequiresIPhoneOS + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSLocationWhenInUseUsageDescription + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities @@ -36,13 +43,5 @@ UIViewControllerBasedStatusBarAppearance - NSLocationWhenInUseUsageDescription - - NSAppTransportSecurity - - - NSAllowsArbitraryLoads - - diff --git a/tests/ReactTests/ios/ReactTestsTests/Info.plist b/tests/ReactTests/ios/ReactTestsTests/Info.plist index 886825ccc9..ba72822e87 100644 --- a/tests/ReactTests/ios/ReactTestsTests/Info.plist +++ b/tests/ReactTests/ios/ReactTestsTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m index 01899f696d..306ee4d0f3 100644 --- a/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m +++ b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m @@ -8,8 +8,8 @@ */ #import "RealmJSTests.h" -#import "../../node_modules/react-native/React/Base/RCTJavaScriptExecutor.h" -#import "../../node_modules/react-native/React/Base/RCTBridge.h" +#import "Base/RCTJavaScriptExecutor.h" +#import "Base/RCTBridge.h" @import RealmReact; @@ -26,24 +26,24 @@ + (NSURL *)scriptURL { - (void)invokeMethod:(NSString *)method { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - [self expectationForNotification:RCTJavaScriptDidLoadNotification object:nil handler:^BOOL(NSNotification * _Nonnull notification) { - return YES; - }]; - [self waitForExpectationsWithTimeout:10000000 handler:^(NSError * _Nullable error) { + [self expectationForNotification:RCTJavaScriptDidLoadNotification object:nil handler:^(NSNotification *notification) { + return YES; }]; + [self waitForExpectationsWithTimeout:10000000 handler:NULL]; }); dispatch_group_t group = dispatch_group_create(); dispatch_group_enter(group); id executor = [RealmReact executor]; - [executor executeBlockOnJavaScriptQueue:^{ - [executor executeJSCall:@"realm-tests" method:@"executeTest" arguments:@[NSStringFromClass(self.class), method] callback:^(id json, NSError *error) { - XCTAssertNil(error, @"%@", [error description]); - dispatch_group_leave(group); - }]; - dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + NSString *module = [NSString stringWithFormat:@"realm-tests/%@.js", NSStringFromClass(self.class)]; + + [executor executeJSCall:module method:method arguments:@[] callback:^(id json, NSError *error) { + XCTAssertNil(error, @"%@", [error description]); + dispatch_group_leave(group); }]; + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); } @end diff --git a/tests/RealmJSTests.h b/tests/RealmJSTests.h index 4ff55c4fc5..6498d9b05f 100644 --- a/tests/RealmJSTests.h +++ b/tests/RealmJSTests.h @@ -19,9 +19,6 @@ #import #import -extern NSString *RealmPathForFile(NSString *fileName); -extern NSString *TestRealmPath(); - @interface RealmJSTests : XCTestCase @end diff --git a/tests/base-test.js b/tests/base-test.js index a7ad8aaaae..99e382d909 100644 --- a/tests/base-test.js +++ b/tests/base-test.js @@ -18,7 +18,7 @@ 'use strict'; -var util = require('./util'); +var Realm = require('realm'); var prototype = exports.prototype = {}; @@ -28,9 +28,14 @@ exports.extend = function(object) { }; Object.defineProperties(prototype, { + // TODO: Remove once missing undefined check is fixed inside RCTContextExecutor. + beforeEach: { + value: function() {} + }, + afterEach: { value: function() { - util.cleanupTestRealms(); + Realm.deleteTestFiles(); } } }); diff --git a/tests/index.js b/tests/index.js index 9ea35ae388..eb2c08e978 100644 --- a/tests/index.js +++ b/tests/index.js @@ -23,7 +23,3 @@ exports.ObjectTests = require('./ObjectTests'); exports.RealmTests = require('./RealmTests'); exports.ResultsTests = require('./ResultsTests'); -exports.executeTest = function(suiteName, testName) { - var suite = exports[suiteName]; - suite[textName](); -}; diff --git a/tests/util.js b/tests/util.js index 3008d62a83..6b1b1bb72d 100644 --- a/tests/util.js +++ b/tests/util.js @@ -20,13 +20,7 @@ var Realm = require('realm'); -var global = (typeof global != 'undefined') ? global : this; - exports.realmPathForFile = function(str) { var path = Realm.defaultPath; return path.substring(0, path.lastIndexOf("/") + 1) + str; }; - -exports.cleanupTestRealms = function() { - global.cleanupTestRealms(); -}; From 7f5902b0212f811903b30762f7f5fbfc8b46748b Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Thu, 15 Oct 2015 11:34:24 -0700 Subject: [PATCH 19/32] Remove dependency on JavaScriptCore for RealmReactTests The test structure is now provided by a JS API, that is used by all things that run tests. Also, the tests can be run manually by tapping a button in the ReactTests app. --- RealmJS.xcodeproj/project.pbxproj | 2 - src/RealmJSCoreTests.h | 23 ---- src/RealmJSCoreTests.m | 76 ++++++++++++- tests/ReactTests/index.ios.js | 68 ++++++------ .../ios/ReactTests.xcodeproj/project.pbxproj | 44 +------- .../ios/ReactTestsTests/RealmReactTests.m | 99 +++++++++++++---- tests/RealmJSTests.h | 4 + tests/RealmJSTests.mm | 105 +++--------------- tests/asserts.js | 2 +- tests/index.js | 20 ++++ 10 files changed, 221 insertions(+), 222 deletions(-) delete mode 100644 src/RealmJSCoreTests.h diff --git a/RealmJS.xcodeproj/project.pbxproj b/RealmJS.xcodeproj/project.pbxproj index 277a01a5ef..ddc6b7bafe 100644 --- a/RealmJS.xcodeproj/project.pbxproj +++ b/RealmJS.xcodeproj/project.pbxproj @@ -144,7 +144,6 @@ /* Begin PBXFileReference section */ 02258FB11BC6E2D00075F13A /* RealmRPC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmRPC.h; path = src/RealmRPC.h; sourceTree = ""; }; 02258FB21BC6E2D00075F13A /* RealmRPC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmRPC.mm; path = src/RealmRPC.mm; sourceTree = ""; }; - 02409DC01BCF11D6005F3B3E /* RealmJSCoreTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmJSCoreTests.h; path = src/RealmJSCoreTests.h; sourceTree = SOURCE_ROOT; }; 02409DC11BCF11D6005F3B3E /* RealmJSCoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RealmJSCoreTests.m; path = src/RealmJSCoreTests.m; sourceTree = SOURCE_ROOT; }; 02601F011BA0F0C4007C91FF /* external_commit_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = external_commit_helper.cpp; path = "src/object-store/apple/external_commit_helper.cpp"; sourceTree = ""; }; 02601F021BA0F0C4007C91FF /* external_commit_helper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = external_commit_helper.hpp; path = "src/object-store/apple/external_commit_helper.hpp"; sourceTree = ""; }; @@ -339,7 +338,6 @@ 0270BC7D1B7D020100010E03 /* ResultsTests.js */, 0270BC7A1B7D020100010E03 /* RealmJSTests.h */, 0270BC7B1B7D020100010E03 /* RealmJSTests.mm */, - 02409DC01BCF11D6005F3B3E /* RealmJSCoreTests.h */, 02409DC11BCF11D6005F3B3E /* RealmJSCoreTests.m */, F68A278A1BC2722A0063D40A /* RJSModuleLoader.h */, F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */, diff --git a/src/RealmJSCoreTests.h b/src/RealmJSCoreTests.h deleted file mode 100644 index 3645f0ccc0..0000000000 --- a/src/RealmJSCoreTests.h +++ /dev/null @@ -1,23 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// -// Copyright 2015 Realm Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -//////////////////////////////////////////////////////////////////////////// - -#import "RealmJSTests.h" - -@interface RealmJSCoreTests : RealmJSTests - -@end diff --git a/src/RealmJSCoreTests.m b/src/RealmJSCoreTests.m index 50666d5b6c..964aaf3b35 100644 --- a/src/RealmJSCoreTests.m +++ b/src/RealmJSCoreTests.m @@ -17,12 +17,82 @@ //////////////////////////////////////////////////////////////////////////// -#import "RealmJSCoreTests.h" +#import "RealmJSTests.h" +#import "RJSModuleLoader.h" + +@interface RealmJSCoreTests : RealmJSTests + +@property (nonatomic, strong) JSValue *testObject; + +@end @implementation RealmJSCoreTests -+ (NSURL *)scriptURL { - return [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js"]; ++ (XCTestSuite *)defaultTestSuite { + XCTestSuite *suite = [super defaultTestSuite]; + JSContext *context = [[JSContext alloc] init]; + RJSModuleLoader *moduleLoader = [[RJSModuleLoader alloc] initWithContext:context]; + NSURL *scriptURL = [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js"]; + + [RealmJS initializeContext:context.JSGlobalContextRef]; + + // Expose the global Realm object as a global 'realm' CommonJS module. + [moduleLoader addGlobalModuleObject:context[@"Realm"] forName:@"realm"]; + + NSError *error; + JSValue *testObjects = [moduleLoader loadModuleFromURL:scriptURL error:&error]; + + if (!testObjects) { + NSLog(@"%@", error); + exit(1); + } + + NSDictionary *testCaseNames = [[testObjects invokeMethod:@"getTestNames" withArguments:nil] toDictionary]; + + if (!testCaseNames.count) { + NSLog(@"No test case names from getTestNames() JS method!"); + exit(1); + } + + for (XCTestSuite *testSuite in [self testSuitesFromDictionary:testCaseNames]) { + for (RealmJSCoreTests *test in testSuite.tests) { + test.testObject = testObjects[testSuite.name]; + } + + [suite addTest:testSuite]; + } + + return suite; +} + +- (JSContext *)context { + return self.testObject.context; +} + +- (void)invokeMethod:(NSString *)method { + JSValue *testObject = self.testObject; + + if (![testObject hasProperty:method]) { + return; + } + + JSContext *context = testObject.context; + context.exception = nil; + + [testObject invokeMethod:method withArguments:nil]; + + JSValue *exception = context.exception; + if (exception) { + JSValue *message = [exception hasProperty:@"message"] ? exception[@"message"] : exception; + NSString *source = [exception hasProperty:@"sourceURL"] ? [exception[@"sourceURL"] toString] : nil; + NSUInteger line = [exception hasProperty:@"line"] ? [exception[@"line"] toUInt32] - 1 : 0; + NSURL *sourceURL = source ? [NSURL URLWithString:source.lastPathComponent relativeToURL:[NSURL URLWithString:@(__FILE__)]] : nil; + + [self recordFailureWithDescription:message.description + inFile:sourceURL ? sourceURL.absoluteString : @(__FILE__) + atLine:sourceURL ? line : __LINE__ + expected:YES]; + } } @end diff --git a/tests/ReactTests/index.ios.js b/tests/ReactTests/index.ios.js index 39316ad2e7..d86ea883bc 100644 --- a/tests/ReactTests/index.ios.js +++ b/tests/ReactTests/index.ios.js @@ -9,25 +9,22 @@ var Realm = require('realm'); var RealmTests = require('realm-tests'); var { - AppRegistry, - StyleSheet, - Text, - View, + AppRegistry, + StyleSheet, + Text, + TouchableHighlight, + View, } = React; function runTests() { - let specialMethodNames = {'beforeEach': true, 'afterEach': true}; + let testNames = RealmTests.getTestNames(); - for (let suiteName in RealmTests) { + for (let suiteName in testNames) { let testSuite = RealmTests[suiteName]; - console.log('Starting suite:', suiteName); - - for (let testName in testSuite) { - if (testName in specialMethodNames || typeof testSuite[testName] != 'function') { - continue; - } + console.log('Starting ' + suiteName); + for (let testName of testNames[suiteName]) { if (testSuite.beforeEach) { testSuite.beforeEach(); } @@ -50,18 +47,11 @@ function runTests() { } var ReactTests = React.createClass({ - componentDidMount() { - runTests(); - }, - render() { return ( - - Welcome to React Native! - - - To get started, edit index.ios.js + + Tap to Run Tests Press Cmd+R to reload,{'\n'} @@ -73,22 +63,26 @@ var ReactTests = React.createClass({ }); var styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: '#F5FCFF', - }, - welcome: { - fontSize: 20, - textAlign: 'center', - margin: 10, - }, - instructions: { - textAlign: 'center', - color: '#333333', - marginBottom: 5, - }, + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + button: { + borderColor: '#cccccc', + borderRadius: 4, + borderWidth: 1, + fontSize: 20, + textAlign: 'center', + margin: 20, + padding: 10, + }, + instructions: { + textAlign: 'center', + color: '#333333', + marginBottom: 5, + }, }); AppRegistry.registerComponent('ReactTests', () => ReactTests); diff --git a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj index b979c4e1ba..f1d6615652 100644 --- a/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj +++ b/tests/ReactTests/ios/ReactTests.xcodeproj/project.pbxproj @@ -15,16 +15,6 @@ 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; 00E356F31AD99517003FC87E /* RealmReactTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* RealmReactTests.m */; }; 02409E1E1BCF1F2E005F3B3E /* RealmJSTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 02409E1B1BCF1F2E005F3B3E /* RealmJSTests.mm */; settings = {ASSET_TAGS = (); }; }; - 02409E1F1BCF1F2E005F3B3E /* RJSModuleLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 02409E1D1BCF1F2E005F3B3E /* RJSModuleLoader.m */; settings = {ASSET_TAGS = (); }; }; - 02409E291BCF1F45005F3B3E /* ArrayTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E201BCF1F45005F3B3E /* ArrayTests.js */; }; - 02409E2A1BCF1F45005F3B3E /* asserts.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E211BCF1F45005F3B3E /* asserts.js */; }; - 02409E2B1BCF1F45005F3B3E /* base-test.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E221BCF1F45005F3B3E /* base-test.js */; }; - 02409E2C1BCF1F45005F3B3E /* index.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E231BCF1F45005F3B3E /* index.js */; }; - 02409E2D1BCF1F45005F3B3E /* ObjectTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E241BCF1F45005F3B3E /* ObjectTests.js */; }; - 02409E2E1BCF1F45005F3B3E /* RealmTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E251BCF1F45005F3B3E /* RealmTests.js */; }; - 02409E2F1BCF1F45005F3B3E /* ResultsTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E261BCF1F45005F3B3E /* ResultsTests.js */; }; - 02409E301BCF1F45005F3B3E /* schemas.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E271BCF1F45005F3B3E /* schemas.js */; }; - 02409E311BCF1F45005F3B3E /* util.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E281BCF1F45005F3B3E /* util.js */; }; 0277991C1BBF3BC600C96559 /* RealmReact.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0277991B1BBF3BB700C96559 /* RealmReact.framework */; }; 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; @@ -169,20 +159,9 @@ 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; 00E356EE1AD99517003FC87E /* RealmReactTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RealmReactTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 00E356F21AD99517003FC87E /* RealmReactTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RealmReactTests.m; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* RealmReactTests.m */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = RealmReactTests.m; sourceTree = ""; tabWidth = 4; }; 02409E1A1BCF1F2E005F3B3E /* RealmJSTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmJSTests.h; path = ../../../RealmJSTests.h; sourceTree = ""; }; 02409E1B1BCF1F2E005F3B3E /* RealmJSTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmJSTests.mm; path = ../../../RealmJSTests.mm; sourceTree = ""; }; - 02409E1C1BCF1F2E005F3B3E /* RJSModuleLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RJSModuleLoader.h; path = ../../../RJSModuleLoader.h; sourceTree = ""; }; - 02409E1D1BCF1F2E005F3B3E /* RJSModuleLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RJSModuleLoader.m; path = ../../../RJSModuleLoader.m; sourceTree = ""; }; - 02409E201BCF1F45005F3B3E /* ArrayTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ArrayTests.js; path = ../../ArrayTests.js; sourceTree = ""; }; - 02409E211BCF1F45005F3B3E /* asserts.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = asserts.js; path = ../../asserts.js; sourceTree = ""; }; - 02409E221BCF1F45005F3B3E /* base-test.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = "base-test.js"; path = "../../base-test.js"; sourceTree = ""; }; - 02409E231BCF1F45005F3B3E /* index.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = index.js; path = ../../index.js; sourceTree = ""; }; - 02409E241BCF1F45005F3B3E /* ObjectTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ObjectTests.js; path = ../../ObjectTests.js; sourceTree = ""; }; - 02409E251BCF1F45005F3B3E /* RealmTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = RealmTests.js; path = ../../RealmTests.js; sourceTree = ""; }; - 02409E261BCF1F45005F3B3E /* ResultsTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ResultsTests.js; path = ../../ResultsTests.js; sourceTree = ""; }; - 02409E271BCF1F45005F3B3E /* schemas.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = schemas.js; path = ../../schemas.js; sourceTree = ""; }; - 02409E281BCF1F45005F3B3E /* util.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = util.js; path = ../../util.js; sourceTree = ""; }; 027799061BBF3BB700C96559 /* RealmJS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RealmJS.xcodeproj; path = ../../../RealmJS.xcodeproj; sourceTree = ""; }; 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; @@ -273,8 +252,6 @@ 00E356F21AD99517003FC87E /* RealmReactTests.m */, 02409E1A1BCF1F2E005F3B3E /* RealmJSTests.h */, 02409E1B1BCF1F2E005F3B3E /* RealmJSTests.mm */, - 02409E1C1BCF1F2E005F3B3E /* RJSModuleLoader.h */, - 02409E1D1BCF1F2E005F3B3E /* RJSModuleLoader.m */, 00E356F01AD99517003FC87E /* Supporting Files */, ); name = RealmReactTests; @@ -374,15 +351,6 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( - 02409E201BCF1F45005F3B3E /* ArrayTests.js */, - 02409E211BCF1F45005F3B3E /* asserts.js */, - 02409E221BCF1F45005F3B3E /* base-test.js */, - 02409E231BCF1F45005F3B3E /* index.js */, - 02409E241BCF1F45005F3B3E /* ObjectTests.js */, - 02409E251BCF1F45005F3B3E /* RealmTests.js */, - 02409E261BCF1F45005F3B3E /* ResultsTests.js */, - 02409E271BCF1F45005F3B3E /* schemas.js */, - 02409E281BCF1F45005F3B3E /* util.js */, 13B07FAE1A68108700A75B9A /* ReactTests */, 832341AE1AAA6A7D00B99B32 /* Libraries */, 00E356EF1AD99517003FC87E /* RealmReactTests */, @@ -621,15 +589,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 02409E291BCF1F45005F3B3E /* ArrayTests.js in Resources */, - 02409E2A1BCF1F45005F3B3E /* asserts.js in Resources */, - 02409E2B1BCF1F45005F3B3E /* base-test.js in Resources */, - 02409E2C1BCF1F45005F3B3E /* index.js in Resources */, - 02409E2D1BCF1F45005F3B3E /* ObjectTests.js in Resources */, - 02409E2E1BCF1F45005F3B3E /* RealmTests.js in Resources */, - 02409E2F1BCF1F45005F3B3E /* ResultsTests.js in Resources */, - 02409E301BCF1F45005F3B3E /* schemas.js in Resources */, - 02409E311BCF1F45005F3B3E /* util.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -666,7 +625,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 02409E1F1BCF1F2E005F3B3E /* RJSModuleLoader.m in Sources */, 02409E1E1BCF1F2E005F3B3E /* RealmJSTests.mm in Sources */, 00E356F31AD99517003FC87E /* RealmReactTests.m in Sources */, ); diff --git a/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m index 306ee4d0f3..a4c7fcbc0c 100644 --- a/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m +++ b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m @@ -1,11 +1,20 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// #import "RealmJSTests.h" #import "Base/RCTJavaScriptExecutor.h" @@ -16,34 +25,78 @@ @interface RealmReactTests : RealmJSTests @end - @implementation RealmReactTests -+ (NSURL *)scriptURL { - return [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js"]; ++ (XCTestSuite *)defaultTestSuite { + [self waitForNotification:RCTJavaScriptDidLoadNotification]; + + NSError *error; + NSDictionary *testCaseNames = [self invokeMethod:@"getTestNames" inModule:@"index" error:&error]; + + if (error || !testCaseNames.count) { + NSLog(@"Error from calling getTestNames() - %@", error ?: @"None returned"); + exit(1); + } + + XCTestSuite *suite = [super defaultTestSuite]; + + for (XCTestSuite *testSuite in [self testSuitesFromDictionary:testCaseNames]) { + [suite addTest:testSuite]; + } + + return suite; } -- (void)invokeMethod:(NSString *)method { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - [self expectationForNotification:RCTJavaScriptDidLoadNotification object:nil handler:^(NSNotification *notification) { - return YES; - }]; - [self waitForExpectationsWithTimeout:10000000 handler:NULL]; - }); ++ (void)waitForNotification:(NSString *)notificationName { + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + __block BOOL received = NO; - dispatch_group_t group = dispatch_group_create(); - dispatch_group_enter(group); + id token = [nc addObserverForName:notificationName object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + received = YES; + }]; + + while (!received) { + @autoreleasepool { + [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + } + } + + [nc removeObserver:token]; +} + ++ (id)invokeMethod:(NSString *)method inModule:(NSString *)module error:(NSError * __strong *)outError { + module = [NSString stringWithFormat:@"realm-tests/%@.js", module]; id executor = [RealmReact executor]; - NSString *module = [NSString stringWithFormat:@"realm-tests/%@.js", NSStringFromClass(self.class)]; + dispatch_group_t group = dispatch_group_create(); + __block id result; + + dispatch_group_enter(group); [executor executeJSCall:module method:method arguments:@[] callback:^(id json, NSError *error) { - XCTAssertNil(error, @"%@", [error description]); + result = json; + + if (error && outError) { + *outError = error; + } + dispatch_group_leave(group); }]; dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + + return result; +} + +- (void)invokeMethod:(NSString *)method { + NSError *error; + [self.class invokeMethod:method inModule:NSStringFromClass(self.class) error:&error]; + + if (error) { + // TODO: Parse and use localizedFailureReason info once we can source map the failure location in JS. + [self recordFailureWithDescription:error.localizedDescription inFile:@(__FILE__) atLine:__LINE__ expected:YES]; + } } @end diff --git a/tests/RealmJSTests.h b/tests/RealmJSTests.h index 6498d9b05f..f9f8fc85f3 100644 --- a/tests/RealmJSTests.h +++ b/tests/RealmJSTests.h @@ -21,4 +21,8 @@ @interface RealmJSTests : XCTestCase ++ (NSArray *)testSuitesFromDictionary:(NSDictionary *)testCaseNames; + +- (instancetype)initWithTestName:(NSString *)name; + @end diff --git a/tests/RealmJSTests.mm b/tests/RealmJSTests.mm index dfaeec0951..9811af850f 100644 --- a/tests/RealmJSTests.mm +++ b/tests/RealmJSTests.mm @@ -19,29 +19,29 @@ #import #import "RealmJSTests.h" -#import "RJSModuleLoader.h" -@interface RealmJSTests () +@implementation RealmJSTests -@property (nonatomic, strong) JSValue *testObject; ++ (NSArray *)testSuitesFromDictionary:(NSDictionary *)testCaseNames { + NSMutableArray *testSuites = [[NSMutableArray alloc] init]; -@end + for (NSString *suiteName in testCaseNames) { + XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:suiteName]; + Class testClass = objc_allocateClassPair(self, suiteName.UTF8String, 0); -@implementation RealmJSTests + for (NSString *testName in testCaseNames[suiteName]) { + XCTestCase *testCase = [[testClass alloc] initWithTestName:testName]; + [testSuite addTest:testCase]; + } -- (instancetype)initWithJSTestObject:(JSValue *)testObject methodName:(NSString *)methodName { - self = [super initWithSelector:NSSelectorFromString(methodName)]; - if (!self) { - return nil; + [testSuites addObject:testSuite]; } - _testObject = testObject; - - return self; + return [testSuites copy]; } -- (JSContext *)context { - return self.testObject.context; +- (instancetype)initWithTestName:(NSString *)name { + return [super initWithSelector:NSSelectorFromString(name)]; } - (void)setUp { @@ -62,59 +62,6 @@ - (void)invokeTest { } } -+ (NSURL *)scriptURL { - return nil; -} - -+ (XCTestSuite *)defaultTestSuite { - XCTestSuite *suite = [super defaultTestSuite]; - JSContext *context = [[JSContext alloc] init]; - RJSModuleLoader *moduleLoader = [[RJSModuleLoader alloc] initWithContext:context]; - - [RealmJS initializeContext:context.JSGlobalContextRef]; - - // Expose the global Realm object as a global 'realm' CommonJS module. - [moduleLoader addGlobalModuleObject:context[@"Realm"] forName:@"realm"]; - - NSError *error; - - NSURL *scriptURL = [self scriptURL]; - if (!scriptURL) { - return suite; - } - - JSValue *testObjects = [moduleLoader loadModuleFromURL:scriptURL error:&error]; - if (!testObjects) { - NSLog(@"index.js - %@", error); - exit(1); - } - - NSSet *specialMethodNames = [NSSet setWithObjects:@"beforeEach", @"afterEach", nil]; - - for (NSString *testName in [testObjects toDictionary]) { - JSValue *testObject = testObjects[testName]; - XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:testName]; - Class testClass = objc_allocateClassPair(self, testName.UTF8String, 0); - - for (NSString *methodName in [testObject toDictionary]) { - if ([specialMethodNames containsObject:methodName]) { - continue; - } - - JSObjectRef jsMethod = JSValueToObject(context.JSGlobalContextRef, [testObject[methodName] JSValueRef], NULL); - - if (jsMethod && JSObjectIsFunction(context.JSGlobalContextRef, jsMethod)) { - XCTestCase *testCase = [[testClass alloc] initWithJSTestObject:testObject methodName:methodName]; - [testSuite addTest:testCase]; - } - } - - [suite addTest:testSuite]; - } - - return suite; -} - - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *sig = [super methodSignatureForSelector:aSelector]; return sig ?: [NSMethodSignature signatureWithObjCTypes:"v@:"]; @@ -125,29 +72,7 @@ - (void)forwardInvocation:(NSInvocation *)anInvocation { } - (void)invokeMethod:(NSString *)method { - JSValue *testObject = self.testObject; - - if (![testObject hasProperty:method]) { - return; - } - - JSContext *context = testObject.context; - context.exception = nil; - - [testObject invokeMethod:method withArguments:nil]; - - JSValue *exception = context.exception; - if (exception) { - JSValue *message = [exception hasProperty:@"message"] ? exception[@"message"] : exception; - NSString *source = [exception hasProperty:@"sourceURL"] ? [exception[@"sourceURL"] toString] : nil; - NSUInteger line = [exception hasProperty:@"line"] ? [exception[@"line"] toUInt32] - 1 : 0; - NSURL *sourceURL = source ? [NSURL URLWithString:source.lastPathComponent relativeToURL:[NSURL URLWithString:@(__FILE__)]] : nil; - - [self recordFailureWithDescription:message.description - inFile:sourceURL ? sourceURL.absoluteString : @(__FILE__) - atLine:sourceURL ? line : __LINE__ - expected:YES]; - } + [self doesNotRecognizeSelector:_cmd]; } @end diff --git a/tests/asserts.js b/tests/asserts.js index f58f9d4180..7f65eea871 100644 --- a/tests/asserts.js +++ b/tests/asserts.js @@ -80,7 +80,7 @@ function TestFailureError(message) { // This regular expression will match stack trace lines provided by JavaScriptCore. // Example: someMethod@file:///path/to/file.js:10:24 - var regex = /^(?:.*?@)?([^\[\(].+?):(\d+)(?::(\d+))?/; + var regex = /^(?:.*?@)?([^\[\(].+?):(\d+)(?::(\d+))?\s*$/; // Remove the top two stack frames and use information from the third, if possible. var stack = error.stack && error.stack.split('\n'); diff --git a/tests/index.js b/tests/index.js index eb2c08e978..37b7901b61 100644 --- a/tests/index.js +++ b/tests/index.js @@ -23,3 +23,23 @@ exports.ObjectTests = require('./ObjectTests'); exports.RealmTests = require('./RealmTests'); exports.ResultsTests = require('./ResultsTests'); +var SPECIAL_METHODS = { + beforeEach: true, + afterEach: true, +}; + +Object.defineProperty(exports, 'getTestNames', { + value: function() { + var testNames = {}; + + for (var suiteName in exports) { + var testSuite = exports[suiteName]; + + testNames[suiteName] = Object.keys(testSuite).filter(function(testName) { + return !(testName in SPECIAL_METHODS) && typeof testSuite[testName] == 'function'; + }); + } + + return testNames; + } +}); From 5d594318607707ac5ac6ebf60d921affdc7bbd53 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Thu, 15 Oct 2015 16:18:58 -0700 Subject: [PATCH 20/32] Fix crash when a test fails inside RealmReactTests This also appears to fix crashes when running ReactTests with Chrome debugging enabled! The crash when tests failed was due to JavaScriptCore trying to create a backtrace with the native call stack. --- ReactNative/RealmReact.h | 7 ++-- ReactNative/RealmReact.m | 24 +++++++------- .../ios/ReactTestsTests/RealmReactTests.m | 32 +++++++++++++++---- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/ReactNative/RealmReact.h b/ReactNative/RealmReact.h index 481b9fa21a..0610c6b4f3 100644 --- a/ReactNative/RealmReact.h +++ b/ReactNative/RealmReact.h @@ -17,11 +17,10 @@ //////////////////////////////////////////////////////////////////////////// @import Foundation; +@import JavaScriptCore; -@interface RealmReact : NSObject - -@property (nonatomic, readonly) id executor; +extern JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor); -+ (id)executor; +@interface RealmReact : NSObject @end diff --git a/ReactNative/RealmReact.m b/ReactNative/RealmReact.m index 286fc01793..98d23b5714 100644 --- a/ReactNative/RealmReact.m +++ b/ReactNative/RealmReact.m @@ -21,7 +21,6 @@ @import GCDWebServers; @import RealmJS; -@import JavaScriptCore; @import ObjectiveC; @import Darwin; @@ -30,11 +29,16 @@ - (instancetype)initWithJSContext:(JSGlobalContextRef)context; - (JSGlobalContextRef)ctx; @end +JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor) { + Ivar contextIvar = class_getInstanceVariable([executor class], "_context"); + id rctJSContext = contextIvar ? object_getIvar(executor, contextIvar) : nil; + + return [rctJSContext ctx]; +} + @interface RealmReact () @end -static id s_executor; - @implementation RealmReact @synthesize bridge = _bridge; @@ -54,16 +58,12 @@ + (NSString *)moduleName { return @"Realm"; } -+ (id)executor { - return s_executor; -} - - (void)setBridge:(RCTBridge *)bridge { _bridge = bridge; Ivar executorIvar = class_getInstanceVariable([bridge class], "_javaScriptExecutor"); - s_executor = object_getIvar(bridge, executorIvar); - Ivar contextIvar = class_getInstanceVariable([s_executor class], "_context"); + id executor = object_getIvar(bridge, executorIvar); + Ivar contextIvar = class_getInstanceVariable([executor class], "_context"); // The executor could be a RCTWebSocketExecutor, in which case it won't have a JS context. if (!contextIvar) { @@ -96,8 +96,8 @@ - (void)setBridge:(RCTBridge *)bridge { return; } - [s_executor executeBlockOnJavaScriptQueue:^{ - id rctJSContext = object_getIvar(s_executor, contextIvar); + [executor executeBlockOnJavaScriptQueue:^{ + id rctJSContext = object_getIvar(executor, contextIvar); JSGlobalContextRef ctx; if (rctJSContext) { @@ -108,7 +108,7 @@ - (void)setBridge:(RCTBridge *)bridge { if (RCTJavaScriptContext) { ctx = JSGlobalContextCreate(NULL); - object_setIvar(s_executor, contextIvar, [[RCTJavaScriptContext alloc] initWithJSContext:ctx]); + object_setIvar(executor, contextIvar, [[RCTJavaScriptContext alloc] initWithJSContext:ctx]); } else { NSLog(@"Failed to load RCTJavaScriptContext class"); diff --git a/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m index a4c7fcbc0c..abbf2081d4 100644 --- a/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m +++ b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m @@ -22,13 +22,31 @@ @import RealmReact; +extern void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack); + +static id s_currentJavaScriptExecutor; + @interface RealmReactTests : RealmJSTests @end @implementation RealmReactTests + (XCTestSuite *)defaultTestSuite { - [self waitForNotification:RCTJavaScriptDidLoadNotification]; + NSNotification *notification = [self waitForNotification:RCTJavaScriptDidLoadNotification]; + RCTBridge *bridge = notification.userInfo[@"bridge"]; + + if (!bridge) { + NSLog(@"No RCTBridge provided by RCTJavaScriptDidLoadNotification"); + exit(1); + } + + s_currentJavaScriptExecutor = [bridge valueForKey:@"javaScriptExecutor"]; + + // FIXME: Remove this nonsense once the crashes go away when a test fails! + JSGlobalContextRef ctx = RealmReactGetJSGlobalContextForExecutor(s_currentJavaScriptExecutor); + if (ctx) { + JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(ctx, false); + } NSError *error; NSDictionary *testCaseNames = [self invokeMethod:@"getTestNames" inModule:@"index" error:&error]; @@ -47,34 +65,34 @@ + (XCTestSuite *)defaultTestSuite { return suite; } -+ (void)waitForNotification:(NSString *)notificationName { ++ (NSNotification *)waitForNotification:(NSString *)notificationName { NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - __block BOOL received = NO; + __block NSNotification *notification; id token = [nc addObserverForName:notificationName object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - received = YES; + notification = note; }]; - while (!received) { + while (!notification) { @autoreleasepool { [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; } } [nc removeObserver:token]; + return notification; } + (id)invokeMethod:(NSString *)method inModule:(NSString *)module error:(NSError * __strong *)outError { module = [NSString stringWithFormat:@"realm-tests/%@.js", module]; - id executor = [RealmReact executor]; dispatch_group_t group = dispatch_group_create(); __block id result; dispatch_group_enter(group); - [executor executeJSCall:module method:method arguments:@[] callback:^(id json, NSError *error) { + [s_currentJavaScriptExecutor executeJSCall:module method:method arguments:@[] callback:^(id json, NSError *error) { result = json; if (error && outError) { From eb598a240889418869ae55a04a89bbc2231e5ddc Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Thu, 15 Oct 2015 17:07:10 -0700 Subject: [PATCH 21/32] fix for in chrome --- lib/rpc.js | 2 +- src/RJSList.hpp | 1 + src/RealmRPC.mm | 30 ++++++++++++++++++++++++------ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/rpc.js b/lib/rpc.js index 89c13ab62b..5b48908511 100644 --- a/lib/rpc.js +++ b/lib/rpc.js @@ -76,7 +76,7 @@ function getListItem(realmId, listId, index) { } function setListItem(realmId, listId, index, value) { - sendRequest('set_list_item', {realmId, listId, index, value}); + sendRequest('set_list_item', {realmId, listId, index, value: serialize(realmId, value)}); } function getListSize(realmId, listId) { diff --git a/src/RJSList.hpp b/src/RJSList.hpp index 6dbe9dd076..aaa0757142 100644 --- a/src/RJSList.hpp +++ b/src/RJSList.hpp @@ -25,3 +25,4 @@ JSClassRef RJSListClass(); JSObjectRef RJSListCreate(JSContextRef ctx, realm::List &list); JSValueRef ListGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* jsException); +bool ListSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* jsException); \ No newline at end of file diff --git a/src/RealmRPC.mm b/src/RealmRPC.mm index 531e5f064d..226ea19290 100644 --- a/src/RealmRPC.mm +++ b/src/RealmRPC.mm @@ -52,7 +52,7 @@ - (instancetype)init { JSValueRef argValues[argCount]; for (NSUInteger i = 0; i < argCount; i++) { - argValues[i] = [self valueFromDictionary:args[i]]; + argValues[i] = [self deserializeDictionaryValue:args[i]]; } JSValueRef exception = NULL; @@ -103,7 +103,7 @@ - (instancetype)init { _requests["/set_property"] = [=](NSDictionary *dict) { JSStringRef propString = RJSStringForString([dict[@"name"] UTF8String]); RPCObjectID realmId = [dict[@"objectId"] unsignedLongValue]; - JSValueRef value = [self valueFromDictionary:dict[@"value"]]; + JSValueRef value = [self deserializeDictionaryValue:dict[@"value"]]; JSValueRef exception = NULL; ObjectSetProperty(_context, _objects[realmId], propString, value, &exception); @@ -172,6 +172,22 @@ - (instancetype)init { return @{@"result": [self resultForJSValue:objectValue]}; }; + _requests["/set_list_item"] = [=](NSDictionary *dict) { + RPCObjectID listId = [dict[@"listId"] unsignedLongValue]; + long index = [dict[@"index"] longValue]; + + JSValueRef exception = NULL; + JSStringRef indexPropertyName = JSStringCreateWithUTF8CString(std::to_string(index).c_str()); + JSValueRef value = [self deserializeDictionaryValue:dict[@"value"]]; + ListSetProperty(_context, _objects[listId], indexPropertyName, value, &exception); + JSStringRelease(indexPropertyName); + + if (exception) { + return @{@"error": @(RJSStringForValue(_context, exception).c_str())}; + } + + return @{}; + }; _requests["/call_list_method"] = [=](NSDictionary *dict) { NSString *name = dict[@"name"]; return [self performObjectMethod:name.UTF8String @@ -190,6 +206,8 @@ - (instancetype)init { - (NSDictionary *)performRequest:(NSString *)name args:(NSDictionary *)args { // perform all realm ops on the main thread RPCRequest action = _requests[name.UTF8String]; + assert(action); + __block id response; dispatch_sync(dispatch_get_main_queue(), ^{ try { @@ -208,7 +226,7 @@ - (NSDictionary *)performObjectMethod:(const char *)name NSUInteger argCount = args.count; JSValueRef argValues[argCount]; for (NSUInteger i = 0; i < argCount; i++) { - argValues[i] = [self valueFromDictionary:args[i]]; + argValues[i] = [self deserializeDictionaryValue:args[i]]; } size_t index = 0; @@ -313,7 +331,7 @@ - (NSDictionary *)objectSchemaToJSONObject:(realm::ObjectSchema &)objectSchema { }; } -- (JSValueRef)valueFromDictionary:(NSDictionary *)dict { +- (JSValueRef)deserializeDictionaryValue:(NSDictionary *)dict { RPCObjectID oid = [dict[@"id"] longValue]; if (oid) { return _objects[oid]; @@ -340,7 +358,7 @@ - (JSValueRef)valueFromDictionary:(NSDictionary *)dict { JSValueRef jsValues[count]; for (NSUInteger i = 0; i < count; i++) { - jsValues[i] = [self valueFromDictionary:value[i]]; + jsValues[i] = [self deserializeDictionaryValue:value[i]]; } return JSObjectMakeArray(_context, count, jsValues, NULL); @@ -349,7 +367,7 @@ - (JSValueRef)valueFromDictionary:(NSDictionary *)dict { JSObjectRef jsObject = JSObjectMake(_context, NULL, NULL); for (NSString *key in value) { - JSValueRef jsValue = [self valueFromDictionary:value[key]]; + JSValueRef jsValue = [self deserializeDictionaryValue:value[key]]; JSStringRef jsKey = JSStringCreateWithCFString((__bridge CFStringRef)key); JSObjectSetProperty(_context, jsObject, jsKey, jsValue, 0, NULL); From 45a3c8960531d2677a80801458d2417b3bf0f5ac Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Thu, 15 Oct 2015 17:28:51 -0700 Subject: [PATCH 22/32] remove hardcoded test paths --- src/RealmJS.mm | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/src/RealmJS.mm b/src/RealmJS.mm index 246d11d6e8..5fb5a7d128 100644 --- a/src/RealmJS.mm +++ b/src/RealmJS.mm @@ -46,31 +46,13 @@ JSClassRef RJSRealmTypeClass() { return JSClassCreate(&realmTypesDefinition); } -NSString *RealmPathForFile(NSString *fileName) { +NSString *RealmFileDirectory() { #if TARGET_OS_IPHONE - NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; + return NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; #else NSString *path = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)[0]; - path = [path stringByAppendingPathComponent:[[[NSBundle mainBundle] executablePath] lastPathComponent]]; + return [path stringByAppendingPathComponent:[[[NSBundle mainBundle] executablePath] lastPathComponent]]; #endif - return [path stringByAppendingPathComponent:fileName]; -} - -static void DeleteOrThrow(NSString *path) { - NSError *error; - if (![[NSFileManager defaultManager] removeItemAtPath:path error:&error]) { - if (error.code != NSFileNoSuchFileError) { - @throw [NSException exceptionWithName:@"RLMTestException" - reason:[@"Unable to delete realm: " stringByAppendingString:error.description] - userInfo:nil]; - } - } -} - -static void DeleteRealmFilesAtPath(NSString *path) { - DeleteOrThrow(path); - DeleteOrThrow([path stringByAppendingString:@".lock"]); - DeleteOrThrow([path stringByAppendingString:@".note"]); } static JSValueRef DeleteTestFiles(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { @@ -103,12 +85,13 @@ + (void)deleteTestFiles { realm::Realm::s_global_cache.invalidate_all(); realm::Realm::s_global_cache.clear(); - // FIXME - find all realm files in the docs dir and delete them rather than hardcoding these - - DeleteRealmFilesAtPath(RealmPathForFile(@"test.realm")); - DeleteRealmFilesAtPath(RealmPathForFile(@"test1.realm")); - DeleteRealmFilesAtPath(RealmPathForFile(@"test2.realm")); - DeleteRealmFilesAtPath(@(RJSDefaultPath().c_str())); + NSFileManager *manager = [NSFileManager defaultManager]; + NSString *fileDir = RealmFileDirectory(); + for (NSString *path in [manager enumeratorAtPath:fileDir]) { + if (![manager removeItemAtPath:[fileDir stringByAppendingPathComponent:path] error:nil]) { + @throw [NSException exceptionWithName:@"removeItemAtPath error" reason:@"Failed to delete file" userInfo:nil]; + } + } } @end From 5ccc03eeb739bc149fbc9823a83a1f951dbc29d0 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Thu, 15 Oct 2015 18:48:13 -0700 Subject: [PATCH 23/32] rename some methods for clarity - try to cleanup js objects --- lib/realm.js | 4 ++-- lib/rpc.js | 6 +++--- src/RealmJS.h | 2 +- src/RealmJS.mm | 14 +++++++------- src/RealmRPC.mm | 9 +++++++-- tests/base-test.js | 2 +- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/lib/realm.js b/lib/realm.js index 3110ec0add..ca56e2f625 100644 --- a/lib/realm.js +++ b/lib/realm.js @@ -83,9 +83,9 @@ class Realm { Object.defineProperty(Realm, 'Types', {value: types}); -Object.defineProperty(Realm, 'deleteTestFiles', { +Object.defineProperty(Realm, 'clearTestState', { value: function() { - rpc.deleteTestFiles(); + rpc.clearTestState(); } }); diff --git a/lib/rpc.js b/lib/rpc.js index 5b48908511..7bf4f65f22 100644 --- a/lib/rpc.js +++ b/lib/rpc.js @@ -37,7 +37,7 @@ exports.beginTransaction = beginTransaction; exports.cancelTransaction = cancelTransaction; exports.commitTransaction = commitTransaction; -exports.deleteTestFiles = deleteTestFiles; +exports.clearTestState = clearTestState; function registerTypeConverter(type, handler) { typeConverters[type] = handler; @@ -113,8 +113,8 @@ function commitTransaction(realmId) { sendRequest('commit_transaction', {realmId}); } -function deleteTestFiles() { - sendRequest('delete_test_files'); +function clearTestState() { + sendRequest('clear_test_state'); } function serialize(realmId, value) { diff --git a/src/RealmJS.h b/src/RealmJS.h index f10133ffd6..ad65e68b18 100644 --- a/src/RealmJS.h +++ b/src/RealmJS.h @@ -25,6 +25,6 @@ // add realm apis to the given js context + (void)initializeContext:(JSContextRef)ctx; -+ (void)deleteTestFiles; ++ (void)clearTestState; @end diff --git a/src/RealmJS.mm b/src/RealmJS.mm index 5fb5a7d128..589ae7a4f7 100644 --- a/src/RealmJS.mm +++ b/src/RealmJS.mm @@ -55,8 +55,8 @@ JSClassRef RJSRealmTypeClass() { #endif } -static JSValueRef DeleteTestFiles(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { - [RealmJS deleteTestFiles]; +static JSValueRef ClearTestState(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { + [RealmJS clearTestState]; return NULL; } @@ -73,15 +73,15 @@ + (void)initializeContext:(JSContextRef)ctx { JSObjectSetProperty(ctx, globalRealmObject, typeString, typesObject, attributes, &exception); JSStringRelease(typeString); - JSStringRef deleteTestFilesString = JSStringCreateWithUTF8CString("deleteTestFiles"); - JSObjectRef deleteTestFilesFunction = JSObjectMakeFunctionWithCallback(ctx, deleteTestFilesString, DeleteTestFiles); - JSObjectSetProperty(ctx, globalRealmObject, deleteTestFilesString, deleteTestFilesFunction, attributes, &exception); - JSStringRelease(deleteTestFilesString); + JSStringRef clearTestStateString = JSStringCreateWithUTF8CString("clearTestState"); + JSObjectRef clearTestStateFunction = JSObjectMakeFunctionWithCallback(ctx, clearTestStateString, ClearTestState); + JSObjectSetProperty(ctx, globalRealmObject, clearTestStateString, clearTestStateFunction, attributes, &exception); + JSStringRelease(clearTestStateString); assert(!exception); } -+ (void)deleteTestFiles { ++ (void)clearTestState { realm::Realm::s_global_cache.invalidate_all(); realm::Realm::s_global_cache.clear(); diff --git a/src/RealmRPC.mm b/src/RealmRPC.mm index 226ea19290..fe95b7787a 100644 --- a/src/RealmRPC.mm +++ b/src/RealmRPC.mm @@ -195,8 +195,13 @@ - (instancetype)init { args:dict[@"arguments"] objectId:[dict[@"listId"] unsignedLongValue]]; }; - _requests["/delete_test_files"] = [=](NSDictionary *dict) { - [RealmJS deleteTestFiles]; + _requests["/clear_test_state"] = [=](NSDictionary *dict) { + for (auto object : _objects) { + JSValueUnprotect(_context, object.second); + } + _objects.clear(); + JSGarbageCollect(_context); + [RealmJS clearTestState]; return nil; }; } diff --git a/tests/base-test.js b/tests/base-test.js index 99e382d909..b299e70ea9 100644 --- a/tests/base-test.js +++ b/tests/base-test.js @@ -35,7 +35,7 @@ Object.defineProperties(prototype, { afterEach: { value: function() { - Realm.deleteTestFiles(); + Realm.clearTestState(); } } }); From 69bf42c4f4d729c5ae346499749a3c2efa73c48d Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Thu, 15 Oct 2015 18:50:20 -0700 Subject: [PATCH 24/32] Actually stop and dealloc RPC server --- ReactNative/RealmReact.m | 11 ++++++++++- src/RealmRPC.mm | 12 ++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ReactNative/RealmReact.m b/ReactNative/RealmReact.m index 98d23b5714..bc000ae4e1 100644 --- a/ReactNative/RealmReact.m +++ b/ReactNative/RealmReact.m @@ -65,6 +65,13 @@ - (void)setBridge:(RCTBridge *)bridge { id executor = object_getIvar(bridge, executorIvar); Ivar contextIvar = class_getInstanceVariable([executor class], "_context"); + static GCDWebServer *s_webServer; + if (s_webServer) { + [s_webServer stop]; + [s_webServer removeAllHandlers]; + s_webServer = nil; + } + // The executor could be a RCTWebSocketExecutor, in which case it won't have a JS context. if (!contextIvar) { [GCDWebServer setLogLevel:3]; @@ -90,9 +97,11 @@ - (void)setBridge:(RCTBridge *)bridge { [response setValue:@"http://localhost:8081" forAdditionalHeader:@"Access-Control-Allow-Origin"]; return response; - }]; + }]; [webServer startWithPort:8082 bonjourName:nil]; + + s_webServer = webServer; return; } diff --git a/src/RealmRPC.mm b/src/RealmRPC.mm index fe95b7787a..b6c7870fe9 100644 --- a/src/RealmRPC.mm +++ b/src/RealmRPC.mm @@ -41,11 +41,23 @@ @implementation RJSRPCServer { std::map _objects; } +- (void)dealloc { + for (auto item : _objects) { + JSValueUnprotect(_context, item.second); + } + + JSGlobalContextRelease(_context); + _requests.clear(); +} + - (instancetype)init { self = [super init]; if (self) { _context = JSGlobalContextCreate(NULL); + id _self = self; + __weak __typeof__(self) self = _self; + _requests["/create_realm"] = [=](NSDictionary *dict) { NSArray *args = dict[@"arguments"]; NSUInteger argCount = args.count; From 5edb205978f073bc32cc0e68452d972d068bd808 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Thu, 15 Oct 2015 19:48:46 -0700 Subject: [PATCH 25/32] clean up prototype and defaults state --- src/RJSSchema.hpp | 1 + src/RJSSchema.mm | 14 ++++++++++++++ src/RealmJS.mm | 2 ++ 3 files changed, 17 insertions(+) diff --git a/src/RJSSchema.hpp b/src/RJSSchema.hpp index 8faa8f5a62..0ca94790c9 100644 --- a/src/RJSSchema.hpp +++ b/src/RJSSchema.hpp @@ -31,3 +31,4 @@ realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject); JSValueRef RJSPrototypeForClassName(const std::string &className); realm::ObjectDefaults &RJSDefaultsForClassName(const std::string &className); +void RJSSchemaClearState(JSContextRef ctx); \ No newline at end of file diff --git a/src/RJSSchema.mm b/src/RJSSchema.mm index ef9fdb12fd..4b00eb9625 100644 --- a/src/RJSSchema.mm +++ b/src/RJSSchema.mm @@ -55,6 +55,20 @@ JSValueRef RJSPrototypeForClassName(const std::string &className) { return s_prototypes[className]; } +void RJSSchemaClearState(JSContextRef ctx) { + for (auto prototype : s_prototypes) { + JSValueUnprotect(ctx, prototype.second); + } + s_prototypes.clear(); + + for (auto defaults : s_defaults) { + for (auto value : defaults.second) { + JSValueUnprotect(ctx, value.second); + } + } + s_defaults.clear(); +} + static inline Property RJSParseProperty(JSContextRef ctx, JSObjectRef propertyObject) { static JSStringRef nameString = JSStringCreateWithUTF8CString("name"); static JSStringRef typeString = JSStringCreateWithUTF8CString("type"); diff --git a/src/RealmJS.mm b/src/RealmJS.mm index 589ae7a4f7..15aecb5c88 100644 --- a/src/RealmJS.mm +++ b/src/RealmJS.mm @@ -20,6 +20,7 @@ #import "RJSRealm.hpp" #import "RJSObject.hpp" #import "RJSUtil.hpp" +#import "RJSSchema.hpp" #include "shared_realm.hpp" @@ -57,6 +58,7 @@ JSClassRef RJSRealmTypeClass() { static JSValueRef ClearTestState(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { [RealmJS clearTestState]; + RJSSchemaClearState(ctx); return NULL; } From 7ae6fe4a03450beb9c76ba2ba40890b516ec0b6d Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 16 Oct 2015 10:35:26 -0700 Subject: [PATCH 26/32] make sure we have destructors for all objects --- src/RJSList.cpp | 2 +- src/RJSObject.mm | 2 +- src/RJSResults.mm | 2 +- src/RJSUtil.hpp | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/RJSList.cpp b/src/RJSList.cpp index dfb35bb578..66978780cf 100644 --- a/src/RJSList.cpp +++ b/src/RJSList.cpp @@ -224,6 +224,6 @@ const JSStaticFunction RJSListFuncs[] = { }; JSClassRef RJSListClass() { - static JSClassRef s_listClass = RJSCreateWrapperClass("RealmList", ListGetProperty, ListSetProperty, RJSListFuncs, NULL, ListPropertyNames); + static JSClassRef s_listClass = RJSCreateWrapperClass("RealmList", ListGetProperty, ListSetProperty, RJSListFuncs, ListPropertyNames); return s_listClass; } diff --git a/src/RJSObject.mm b/src/RJSObject.mm index 1d088469ed..b56c280177 100644 --- a/src/RJSObject.mm +++ b/src/RJSObject.mm @@ -58,7 +58,7 @@ void ObjectPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAcc } JSClassRef RJSObjectClass() { - static JSClassRef s_objectClass = RJSCreateWrapperClass("RealmObject", ObjectGetProperty, ObjectSetProperty, NULL, NULL, ObjectPropertyNames); + static JSClassRef s_objectClass = RJSCreateWrapperClass("RealmObject", ObjectGetProperty, ObjectSetProperty, NULL, ObjectPropertyNames); return s_objectClass; } diff --git a/src/RJSResults.mm b/src/RJSResults.mm index 7cdad982cc..594d48de4c 100644 --- a/src/RJSResults.mm +++ b/src/RJSResults.mm @@ -124,6 +124,6 @@ JSClassRef RJSResultsClass() { {"sortByProperty", SortByProperty, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {NULL, NULL}, }; - static JSClassRef s_objectClass = RJSCreateWrapperClass("Results", ResultsGetProperty, NULL, resultsFuncs, NULL, ResultsPropertyNames); + static JSClassRef s_objectClass = RJSCreateWrapperClass("Results", ResultsGetProperty, NULL, resultsFuncs, ResultsPropertyNames); return s_objectClass; } diff --git a/src/RJSUtil.hpp b/src/RJSUtil.hpp index b53f203403..0ff3beeb1b 100644 --- a/src/RJSUtil.hpp +++ b/src/RJSUtil.hpp @@ -43,10 +43,11 @@ inline T RJSGetInternal(JSObjectRef jsObject) { } template -JSClassRef RJSCreateWrapperClass(const char * name, JSObjectGetPropertyCallback getter = NULL, JSObjectSetPropertyCallback setter = NULL, const JSStaticFunction *funcs = NULL, JSObjectFinalizeCallback finalize = RJSFinalize, JSObjectGetPropertyNamesCallback propertyNames = NULL) { +JSClassRef RJSCreateWrapperClass(const char * name, JSObjectGetPropertyCallback getter = NULL, JSObjectSetPropertyCallback setter = NULL, const JSStaticFunction *funcs = NULL, + JSObjectGetPropertyNamesCallback propertyNames = NULL) { JSClassDefinition classDefinition = kJSClassDefinitionEmpty; classDefinition.className = name; - classDefinition.finalize = finalize; + classDefinition.finalize = RJSFinalize; classDefinition.getProperty = getter; classDefinition.setProperty = setter; classDefinition.staticFunctions = funcs; From 7074d66c5f83c2b0ff1c318ce6375ba5f934ae5c Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 19 Oct 2015 09:58:26 -0700 Subject: [PATCH 27/32] always use release version of core --- RealmJS.xcodeproj/project.pbxproj | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/RealmJS.xcodeproj/project.pbxproj b/RealmJS.xcodeproj/project.pbxproj index ddc6b7bafe..a0081f231a 100644 --- a/RealmJS.xcodeproj/project.pbxproj +++ b/RealmJS.xcodeproj/project.pbxproj @@ -772,7 +772,6 @@ GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( REALM_HAVE_CONFIG, - REALM_DEBUG, __ASSERTMACROS__, ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; @@ -852,7 +851,6 @@ GCC_PREPROCESSOR_DEFINITIONS = ( REALM_HAVE_CONFIG, "DEBUG=1", - REALM_DEBUG, __ASSERTMACROS__, ); HEADER_SEARCH_PATHS = ( @@ -869,8 +867,8 @@ "-isystem", core/include, ); - OTHER_LDFLAGS = "-lrealm-ios-dbg"; - OTHER_LIBTOOLFLAGS = "-lrealm-ios-dbg"; + OTHER_LDFLAGS = "-lrealm-ios"; + OTHER_LIBTOOLFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -903,7 +901,7 @@ core/include, ); OTHER_LDFLAGS = "-lrealm-ios"; - OTHER_LIBTOOLFLAGS = "-lrealm-ios"; + OTHER_LIBTOOLFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -986,7 +984,6 @@ GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( REALM_HAVE_CONFIG, - REALM_DEBUG, __ASSERTMACROS__, ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; @@ -1020,7 +1017,6 @@ GCC_PREPROCESSOR_DEFINITIONS = ( REALM_HAVE_CONFIG, "DEBUG=1", - REALM_DEBUG, __ASSERTMACROS__, ); HEADER_SEARCH_PATHS = ( @@ -1037,8 +1033,8 @@ "-isystem", core/include, ); - OTHER_LDFLAGS = "-lrealm-ios-dbg"; - OTHER_LIBTOOLFLAGS = "-lrealm-ios-dbg"; + OTHER_LDFLAGS = "-lrealm-ios"; + OTHER_LIBTOOLFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "io.realm.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; From 832e0c5e1353089cd90ad6e7cb0ea6aa487bad9f Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 19 Oct 2015 10:24:51 -0700 Subject: [PATCH 28/32] clean up ctx initiliazation/remove code duplication --- ReactNative/RealmReact.m | 42 ++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/ReactNative/RealmReact.m b/ReactNative/RealmReact.m index bc000ae4e1..5b23a8f864 100644 --- a/ReactNative/RealmReact.m +++ b/ReactNative/RealmReact.m @@ -31,7 +31,22 @@ - (JSGlobalContextRef)ctx; JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor) { Ivar contextIvar = class_getInstanceVariable([executor class], "_context"); + if (!contextIvar) { + return NULL; + } + id rctJSContext = contextIvar ? object_getIvar(executor, contextIvar) : nil; + if (!rctJSContext) { + Class RCTJavaScriptContext = NSClassFromString(@"RCTJavaScriptContext"); + if (RCTJavaScriptContext) { + JSGlobalContextRef ctx = JSGlobalContextCreate(NULL); + rctJSContext = [[RCTJavaScriptContext alloc] initWithJSContext:ctx]; + object_setIvar(executor, contextIvar, rctJSContext); + } + else { + NSLog(@"Failed to load RCTJavaScriptContext class"); + } + } return [rctJSContext ctx]; } @@ -61,10 +76,6 @@ + (NSString *)moduleName { - (void)setBridge:(RCTBridge *)bridge { _bridge = bridge; - Ivar executorIvar = class_getInstanceVariable([bridge class], "_javaScriptExecutor"); - id executor = object_getIvar(bridge, executorIvar); - Ivar contextIvar = class_getInstanceVariable([executor class], "_context"); - static GCDWebServer *s_webServer; if (s_webServer) { [s_webServer stop]; @@ -73,7 +84,9 @@ - (void)setBridge:(RCTBridge *)bridge { } // The executor could be a RCTWebSocketExecutor, in which case it won't have a JS context. - if (!contextIvar) { + Ivar executorIvar = class_getInstanceVariable([bridge class], "_javaScriptExecutor"); + id executor = object_getIvar(bridge, executorIvar); + if ([executor isMemberOfClass:NSClassFromString(@"RCTWebSocketExecutor")]) { [GCDWebServer setLogLevel:3]; GCDWebServer *webServer = [[GCDWebServer alloc] init]; RJSRPCServer *rpcServer = [[RJSRPCServer alloc] init]; @@ -106,24 +119,7 @@ - (void)setBridge:(RCTBridge *)bridge { } [executor executeBlockOnJavaScriptQueue:^{ - id rctJSContext = object_getIvar(executor, contextIvar); - JSGlobalContextRef ctx; - - if (rctJSContext) { - ctx = [rctJSContext ctx]; - } - else { - Class RCTJavaScriptContext = NSClassFromString(@"RCTJavaScriptContext"); - - if (RCTJavaScriptContext) { - ctx = JSGlobalContextCreate(NULL); - object_setIvar(executor, contextIvar, [[RCTJavaScriptContext alloc] initWithJSContext:ctx]); - } - else { - NSLog(@"Failed to load RCTJavaScriptContext class"); - } - } - + JSGlobalContextRef ctx = RealmReactGetJSGlobalContextForExecutor(executor); [RealmJS initializeContext:ctx]; }]; } From 69ea13944f1ebf0c8ca525b1f66420916ca595ae Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 19 Oct 2015 10:25:25 -0700 Subject: [PATCH 29/32] disable schema/defaults cleanup until we can ensure we are using the correct context --- src/RealmJS.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RealmJS.mm b/src/RealmJS.mm index 15aecb5c88..13076b0661 100644 --- a/src/RealmJS.mm +++ b/src/RealmJS.mm @@ -58,7 +58,7 @@ JSClassRef RJSRealmTypeClass() { static JSValueRef ClearTestState(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { [RealmJS clearTestState]; - RJSSchemaClearState(ctx); + //RJSSchemaClearState(ctx); return NULL; } From fae276816f518cd2120de52fa3dcc0472befec4a Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 19 Oct 2015 10:33:59 -0700 Subject: [PATCH 30/32] newline --- src/RJSSchema.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RJSSchema.hpp b/src/RJSSchema.hpp index 0ca94790c9..418725d4a5 100644 --- a/src/RJSSchema.hpp +++ b/src/RJSSchema.hpp @@ -31,4 +31,4 @@ realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject); JSValueRef RJSPrototypeForClassName(const std::string &className); realm::ObjectDefaults &RJSDefaultsForClassName(const std::string &className); -void RJSSchemaClearState(JSContextRef ctx); \ No newline at end of file +void RJSSchemaClearState(JSContextRef ctx); From f02fb05af47368dedf8c955c8e2f568b5a3faa0f Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 19 Oct 2015 10:52:34 -0700 Subject: [PATCH 31/32] add search paths for test path --- RealmJS.xcodeproj/project.pbxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RealmJS.xcodeproj/project.pbxproj b/RealmJS.xcodeproj/project.pbxproj index a0081f231a..e3322e7ee3 100644 --- a/RealmJS.xcodeproj/project.pbxproj +++ b/RealmJS.xcodeproj/project.pbxproj @@ -662,6 +662,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/examples/ReactExample/node_modules/react-native/React/", + "$(SRCROOT)/tests/ReactTests/node_modules/react-native/React/", ); INFOPLIST_FILE = src/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -694,6 +695,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/examples/ReactExample/node_modules/react-native/React/", + "$(SRCROOT)/tests/ReactTests/node_modules/react-native/React/", ); INFOPLIST_FILE = src/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -726,6 +728,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/examples/ReactExample/node_modules/react-native/React/", + "$(SRCROOT)/tests/ReactTests/node_modules/react-native/React/", ); INFOPLIST_FILE = src/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; From cfd618db323f5ab62502ea94792bb96d964bd9e4 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 19 Oct 2015 11:28:50 -0700 Subject: [PATCH 32/32] flag to create jscontext --- ReactNative/RealmReact.h | 2 +- ReactNative/RealmReact.m | 6 +++--- tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ReactNative/RealmReact.h b/ReactNative/RealmReact.h index 0610c6b4f3..6a0b086c9e 100644 --- a/ReactNative/RealmReact.h +++ b/ReactNative/RealmReact.h @@ -19,7 +19,7 @@ @import Foundation; @import JavaScriptCore; -extern JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor); +extern JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor, bool create); @interface RealmReact : NSObject diff --git a/ReactNative/RealmReact.m b/ReactNative/RealmReact.m index 5b23a8f864..b780b73e94 100644 --- a/ReactNative/RealmReact.m +++ b/ReactNative/RealmReact.m @@ -29,14 +29,14 @@ - (instancetype)initWithJSContext:(JSGlobalContextRef)context; - (JSGlobalContextRef)ctx; @end -JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor) { +JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor, bool create) { Ivar contextIvar = class_getInstanceVariable([executor class], "_context"); if (!contextIvar) { return NULL; } id rctJSContext = contextIvar ? object_getIvar(executor, contextIvar) : nil; - if (!rctJSContext) { + if (!rctJSContext && create) { Class RCTJavaScriptContext = NSClassFromString(@"RCTJavaScriptContext"); if (RCTJavaScriptContext) { JSGlobalContextRef ctx = JSGlobalContextCreate(NULL); @@ -119,7 +119,7 @@ - (void)setBridge:(RCTBridge *)bridge { } [executor executeBlockOnJavaScriptQueue:^{ - JSGlobalContextRef ctx = RealmReactGetJSGlobalContextForExecutor(executor); + JSGlobalContextRef ctx = RealmReactGetJSGlobalContextForExecutor(executor, true); [RealmJS initializeContext:ctx]; }]; } diff --git a/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m index abbf2081d4..58adc9f8a4 100644 --- a/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m +++ b/tests/ReactTests/ios/ReactTestsTests/RealmReactTests.m @@ -43,7 +43,7 @@ + (XCTestSuite *)defaultTestSuite { s_currentJavaScriptExecutor = [bridge valueForKey:@"javaScriptExecutor"]; // FIXME: Remove this nonsense once the crashes go away when a test fails! - JSGlobalContextRef ctx = RealmReactGetJSGlobalContextForExecutor(s_currentJavaScriptExecutor); + JSGlobalContextRef ctx = RealmReactGetJSGlobalContextForExecutor(s_currentJavaScriptExecutor, false); if (ctx) { JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(ctx, false); }