@react-native-firebase/app 26.3.3 → 27.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +10 -27
  3. package/RNFBApp.podspec +13 -5
  4. package/android/build.gradle +3 -0
  5. package/android/src/main/java/io/invertase/firebase/common/RNFBHandleCollisionException.kt +29 -0
  6. package/android/src/main/java/io/invertase/firebase/common/RNFBHandleMap.kt +146 -0
  7. package/android/src/main/java/io/invertase/firebase/common/TaskExecutorService.kt +156 -0
  8. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.kt +44 -0
  9. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebasePreferences.kt +100 -0
  10. package/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.kt +250 -0
  11. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseApp.kt +64 -0
  12. package/android/src/reactnative/java/io/invertase/firebase/app/{ReactNativeFirebaseAppInitProvider.java → ReactNativeFirebaseAppInitProvider.kt} +3 -4
  13. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.kt +47 -0
  14. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppRegistrar.kt +33 -0
  15. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseVersion.java +1 -1
  16. package/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.kt +185 -0
  17. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEvent.kt +35 -0
  18. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitter.kt +662 -0
  19. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseJSON.kt +103 -0
  20. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseMeta.kt +96 -0
  21. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseModule.kt +140 -0
  22. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebasePreferences.kt +109 -0
  23. package/android/src/reactnative/java/io/invertase/firebase/common/SharedUtils.kt +451 -0
  24. package/android/src/reactnative/java/io/invertase/firebase/interfaces/{ContextProvider.java → ContextProvider.kt} +8 -8
  25. package/android/src/reactnative/java/io/invertase/firebase/interfaces/{NativeError.java → NativeError.kt} +8 -8
  26. package/android/src/reactnative/java/io/invertase/firebase/interfaces/{NativeEvent.java → NativeEvent.kt} +6 -6
  27. package/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.kt +219 -0
  28. package/android/src/test/java/expo/core/ModuleRegistry.java +9 -0
  29. package/android/src/test/java/io/invertase/firebase/app/NativeRNFBTurboAppTest.java +208 -60
  30. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppComponentsJavaCompatibilityTest.java +70 -0
  31. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppJavaCompatibilityTest.java +60 -0
  32. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackageTest.java +165 -0
  33. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppTest.kt +167 -0
  34. package/android/src/test/java/io/invertase/firebase/common/RCTConvertFirebaseJavaCompatibilityTest.java +112 -0
  35. package/android/src/test/java/io/invertase/firebase/common/RCTConvertFirebaseTest.kt +317 -0
  36. package/android/src/test/java/io/invertase/firebase/common/RNFBHandleMapTest.kt +309 -0
  37. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitterJavaCompatibilityTest.java +176 -0
  38. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitterTest.java +144 -13
  39. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseEventTest.kt +61 -0
  40. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseJSONJavaCompatibilityTest.java +85 -0
  41. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseJSONTest.kt +296 -0
  42. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseMetaJavaCompatibilityTest.java +67 -0
  43. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseMetaTest.kt +246 -0
  44. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseModuleTest.kt +254 -0
  45. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebasePreferencesJavaCompatibilityTest.java +87 -0
  46. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebasePreferencesTest.kt +260 -0
  47. package/android/src/test/java/io/invertase/firebase/common/SharedUtilsJavaCompatibilityTest.java +255 -0
  48. package/android/src/test/java/io/invertase/firebase/common/SharedUtilsTest.kt +674 -0
  49. package/android/src/test/java/io/invertase/firebase/common/TaskExecutorServiceTest.kt +290 -0
  50. package/android/src/test/java/io/invertase/firebase/common/UniversalFirebaseModuleJavaCompatibilityTest.java +178 -0
  51. package/android/src/test/java/io/invertase/firebase/common/UniversalFirebasePreferencesJavaCompatibilityTest.java +99 -0
  52. package/android/src/test/java/io/invertase/firebase/common/UniversalFirebasePreferencesTest.kt +217 -0
  53. package/android/src/test/java/io/invertase/firebase/commoncompat/ReactNativeFirebaseModuleJavaCompatibilityTest.java +176 -0
  54. package/android/src/test/java/io/invertase/firebase/commoncompat/ReactNativeFirebaseModuleKotlinCompatibilityTest.kt +52 -0
  55. package/android/src/test/java/io/invertase/firebase/interfaces/InterfacesJavaCompatibilityTest.java +144 -0
  56. package/android/src/test/java/io/invertase/firebase/interfaces/NativeEventTest.kt +56 -0
  57. package/android/src/test/java/io/invertase/firebase/utils/NativeRNFBTurboUtilsTest.java +517 -23
  58. package/dist/module/FirebaseApp.js +10 -0
  59. package/dist/module/FirebaseApp.js.map +1 -1
  60. package/dist/module/common/Base64.js +13 -21
  61. package/dist/module/common/Base64.js.map +1 -1
  62. package/dist/module/common/deeps.js +3 -0
  63. package/dist/module/common/deeps.js.map +1 -1
  64. package/dist/module/common/index.js +17 -9
  65. package/dist/module/common/index.js.map +1 -1
  66. package/dist/module/internal/FirebaseModule.js.map +1 -1
  67. package/dist/module/internal/RNFBNativeEventEmitter.js +12 -1
  68. package/dist/module/internal/RNFBNativeEventEmitter.js.map +1 -1
  69. package/dist/module/internal/SharedEventEmitter.js +3 -1
  70. package/dist/module/internal/SharedEventEmitter.js.map +1 -1
  71. package/dist/module/internal/asyncStorage.js +7 -11
  72. package/dist/module/internal/asyncStorage.js.map +1 -1
  73. package/dist/module/internal/index.js +1 -0
  74. package/dist/module/internal/index.js.map +1 -1
  75. package/dist/module/internal/logger.js +44 -40
  76. package/dist/module/internal/logger.js.map +1 -1
  77. package/dist/module/internal/nativeModuleAndroidIos.js +2 -29
  78. package/dist/module/internal/nativeModuleAndroidIos.js.map +1 -1
  79. package/dist/module/internal/nativeModuleDebug.js +74 -0
  80. package/dist/module/internal/nativeModuleDebug.js.map +1 -0
  81. package/dist/module/internal/nativeModuleWeb.js +9 -29
  82. package/dist/module/internal/nativeModuleWeb.js.map +1 -1
  83. package/dist/module/internal/registry/app.js +8 -2
  84. package/dist/module/internal/registry/app.js.map +1 -1
  85. package/dist/module/internal/registry/modular.js +2 -2
  86. package/dist/module/internal/registry/modular.js.map +1 -1
  87. package/dist/module/internal/registry/nativeModule.js +3 -3
  88. package/dist/module/internal/registry/nativeModule.js.map +1 -1
  89. package/dist/module/internal/web/RNFBAppModule.js +16 -15
  90. package/dist/module/internal/web/RNFBAppModule.js.map +1 -1
  91. package/dist/module/internal/web/memidb/lib/FakeEventTarget.js +3 -1
  92. package/dist/module/internal/web/memidb/lib/FakeEventTarget.js.map +1 -1
  93. package/dist/module/types/app.js.map +1 -1
  94. package/dist/module/types/internal.js +2 -0
  95. package/dist/module/version.js +1 -1
  96. package/dist/typescript/lib/FirebaseApp.d.ts +7 -0
  97. package/dist/typescript/lib/FirebaseApp.d.ts.map +1 -1
  98. package/dist/typescript/lib/common/Base64.d.ts.map +1 -1
  99. package/dist/typescript/lib/common/deeps.d.ts.map +1 -1
  100. package/dist/typescript/lib/common/index.d.ts.map +1 -1
  101. package/dist/typescript/lib/internal/FirebaseModule.d.ts +2 -3
  102. package/dist/typescript/lib/internal/FirebaseModule.d.ts.map +1 -1
  103. package/dist/typescript/lib/internal/NativeModules.d.ts +4 -1
  104. package/dist/typescript/lib/internal/NativeModules.d.ts.map +1 -1
  105. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts +2 -2
  106. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts.map +1 -1
  107. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts +3 -3
  108. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts.map +1 -1
  109. package/dist/typescript/lib/internal/asyncStorage.d.ts.map +1 -1
  110. package/dist/typescript/lib/internal/index.d.ts +1 -0
  111. package/dist/typescript/lib/internal/index.d.ts.map +1 -1
  112. package/dist/typescript/lib/internal/logger.d.ts.map +1 -1
  113. package/dist/typescript/lib/internal/nativeModuleAndroidIos.d.ts.map +1 -1
  114. package/dist/typescript/lib/internal/nativeModuleDebug.d.ts +2 -0
  115. package/dist/typescript/lib/internal/nativeModuleDebug.d.ts.map +1 -0
  116. package/dist/typescript/lib/internal/nativeModuleWeb.d.ts.map +1 -1
  117. package/dist/typescript/lib/internal/registry/app.d.ts.map +1 -1
  118. package/dist/typescript/lib/internal/web/RNFBAppModule.d.ts +7 -7
  119. package/dist/typescript/lib/internal/web/RNFBAppModule.d.ts.map +1 -1
  120. package/dist/typescript/lib/types/app.d.ts +10 -3
  121. package/dist/typescript/lib/types/app.d.ts.map +1 -1
  122. package/dist/typescript/lib/types/internal.d.ts +12 -0
  123. package/dist/typescript/lib/types/internal.d.ts.map +1 -1
  124. package/dist/typescript/lib/version.d.ts +1 -1
  125. package/firebase-schema.json +5 -1
  126. package/firebase_spm.rb +552 -96
  127. package/ios/RNFBApp/RCTConvert+FIRApp.h +2 -5
  128. package/ios/RNFBApp/RCTConvert+FIRApp.m +11 -6
  129. package/ios/RNFBApp/RCTConvert+FIROptions.h +2 -5
  130. package/ios/RNFBApp/RCTConvert+FIROptions.m +11 -10
  131. package/ios/RNFBApp/RCTConvertFIRApp.swift +86 -0
  132. package/ios/RNFBApp/RCTConvertFIROptions.swift +259 -0
  133. package/ios/RNFBApp/RNFBAppCustomAuthDomains.swift +63 -0
  134. package/ios/RNFBApp/RNFBAppInitializeOptionsMapper.swift +113 -0
  135. package/ios/RNFBApp/RNFBAppLogLevelMapper.swift +53 -0
  136. package/ios/RNFBApp/RNFBAppModule+CustomAuthDomain.m +35 -0
  137. package/ios/RNFBApp/RNFBAppModule.h +6 -2
  138. package/ios/RNFBApp/RNFBAppModule.mm +67 -204
  139. package/ios/RNFBApp/RNFBAppModuleFirebase.swift +439 -0
  140. package/ios/RNFBApp/RNFBAppModuleImplementation.h +68 -0
  141. package/ios/RNFBApp/RNFBAppModuleImplementation.m +195 -0
  142. package/ios/RNFBApp/RNFBHandleMap.h +73 -0
  143. package/ios/RNFBApp/RNFBHandleMap.m +87 -0
  144. package/ios/RNFBApp/RNFBHandleMapStorage.swift +90 -0
  145. package/ios/RNFBApp/RNFBInitializeAppArguments.swift +82 -0
  146. package/ios/RNFBApp/RNFBJSON.m +22 -38
  147. package/ios/RNFBApp/RNFBJSONImplementation.swift +71 -0
  148. package/ios/RNFBApp/RNFBMeta.m +24 -26
  149. package/ios/RNFBApp/RNFBMetaStorage.swift +76 -0
  150. package/ios/RNFBApp/RNFBNullSentinelDecoding.swift +135 -0
  151. package/ios/RNFBApp/RNFBNullSentinelInterceptor.h +30 -3
  152. package/ios/RNFBApp/RNFBNullSentinelInterceptor.m +28 -5
  153. package/ios/RNFBApp/RNFBPreferences.m +22 -20
  154. package/ios/RNFBApp/RNFBPreferencesStorage.swift +101 -0
  155. package/ios/RNFBApp/RNFBRCTEventEmitter.m +36 -93
  156. package/ios/RNFBApp/RNFBRCTEventEmitterCore.swift +161 -0
  157. package/ios/RNFBApp/RNFBSharedUtils.h +2 -5
  158. package/ios/RNFBApp/RNFBSharedUtils.m +109 -197
  159. package/ios/RNFBApp/RNFBSharedUtilsConfig.swift +72 -0
  160. package/ios/RNFBApp/RNFBSharedUtilsFIRApp.swift +271 -0
  161. package/ios/RNFBApp/RNFBSharedUtilsFormatting.swift +59 -0
  162. package/ios/RNFBApp/RNFBSharedUtilsPromiseRejection.swift +88 -0
  163. package/ios/RNFBApp/RNFBUtilsHelpers.swift +116 -0
  164. package/ios/RNFBApp/RNFBUtilsModule+Foundation.m +44 -0
  165. package/ios/RNFBApp/RNFBUtilsModule+PhotoAssets.m +47 -0
  166. package/ios/RNFBApp/RNFBUtilsModule.h +11 -1
  167. package/ios/RNFBApp/RNFBUtilsModule.mm +10 -85
  168. package/ios/RNFBApp/RNFBUtilsModuleImplementation.h +32 -0
  169. package/ios/RNFBApp/RNFBUtilsModuleImplementation.m +56 -0
  170. package/ios/RNFBApp/RNFBVersion.m +1 -1
  171. package/ios/RNFBApp.xcodeproj/project.pbxproj +106 -0
  172. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FIRApp.m +171 -0
  173. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FirebaseCore.h +78 -0
  174. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FIRInstallations.m +7 -0
  175. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FirebaseInstallations.h +8 -0
  176. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppModuleHostStub.m +55 -0
  177. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.h +89 -0
  178. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.mm +30 -0
  179. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.h +19 -0
  180. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.m +32 -0
  181. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridgeModule.h +19 -0
  182. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.h +28 -0
  183. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.m +23 -0
  184. package/ios/RNFBAppUnitTests/HostStubs/React/RCTEventEmitter.h +9 -0
  185. package/ios/RNFBAppUnitTests/HostStubs/React/RCTInvalidating.h +24 -0
  186. package/ios/RNFBAppUnitTests/HostStubs/React/RCTUtils.h +9 -0
  187. package/ios/RNFBAppUnitTests/HostStubs/module.modulemap +13 -0
  188. package/ios/RNFBAppUnitTests/RCTConvertFIRAppFacadeTests.m +61 -0
  189. package/ios/RNFBAppUnitTests/RCTConvertFIRAppTests.swift +73 -0
  190. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsFacadeTests.m +57 -0
  191. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsTests.swift +243 -0
  192. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsFacadeTests.m +73 -0
  193. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsTests.swift +70 -0
  194. package/ios/RNFBAppUnitTests/RNFBAppInitializeOptionsMapperTests.swift +190 -0
  195. package/ios/RNFBAppUnitTests/RNFBAppLogLevelFacadeTests.m +76 -0
  196. package/ios/RNFBAppUnitTests/RNFBAppLogLevelMapperTests.swift +59 -0
  197. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseFacadeTests.m +215 -0
  198. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseTests.swift +430 -0
  199. package/ios/RNFBAppUnitTests/RNFBAppModuleLifecycleTests.m +206 -0
  200. package/ios/RNFBAppUnitTests/RNFBAppModuleShellTests.mm +367 -0
  201. package/ios/RNFBAppUnitTests/RNFBAppUnitTests.xcodeproj/project.pbxproj +590 -0
  202. package/ios/RNFBAppUnitTests/RNFBAppUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBAppUnitTests.xcscheme +69 -0
  203. package/ios/RNFBAppUnitTests/RNFBFirebaseAppClientTests.swift +165 -0
  204. package/ios/RNFBAppUnitTests/RNFBHandleMapStorageTests.swift +121 -0
  205. package/ios/RNFBAppUnitTests/RNFBHandleMapTests.m +238 -0
  206. package/ios/RNFBAppUnitTests/RNFBInitializeAppArgumentsTests.swift +256 -0
  207. package/ios/RNFBAppUnitTests/RNFBJSONImplementationTests.swift +126 -0
  208. package/ios/RNFBAppUnitTests/RNFBJSONTests.m +172 -0
  209. package/ios/RNFBAppUnitTests/RNFBMetaStorageTests.swift +106 -0
  210. package/ios/RNFBAppUnitTests/RNFBMetaTests.m +65 -0
  211. package/ios/RNFBAppUnitTests/RNFBNullSentinelDecodingTests.swift +286 -0
  212. package/ios/RNFBAppUnitTests/RNFBNullSentinelInterceptorTests.m +312 -0
  213. package/ios/RNFBAppUnitTests/RNFBPreferencesStorageTests.swift +105 -0
  214. package/ios/RNFBAppUnitTests/RNFBPreferencesTests.m +110 -0
  215. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterCoreTests.swift +163 -0
  216. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterFacadeTests.m +141 -0
  217. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigFacadeTests.m +100 -0
  218. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigTests.swift +234 -0
  219. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppFacadeTests.m +145 -0
  220. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppTests.swift +173 -0
  221. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingFacadeTests.m +38 -0
  222. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingTests.swift +82 -0
  223. package/ios/RNFBAppUnitTests/RNFBSharedUtilsNullSentinelTests.m +35 -0
  224. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionFacadeTests.m +107 -0
  225. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionTests.swift +133 -0
  226. package/ios/RNFBAppUnitTests/RNFBUtilsHelpersTests.swift +144 -0
  227. package/ios/RNFBAppUnitTests/RNFBUtilsModuleFacadeTests.m +72 -0
  228. package/ios/RNFBAppUnitTests/RNFBUtilsModuleShellTests.mm +282 -0
  229. package/ios/RNFBFirebase/Package.swift +53 -0
  230. package/ios/RNFBFirebase/Sources/RNFBFirebase/RNFBFirebase.swift +285 -0
  231. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/Public/.gitkeep +0 -0
  232. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/RNFBFirebaseBridge.m +169 -0
  233. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/include/RNFBFirebaseBridge.h +52 -0
  234. package/ios/RNFBFirebaseUnitTests/RNFBAppDynamicFacadeTests.swift +240 -0
  235. package/{android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppRegistrar.java → ios/RNFBFirebaseUnitTests/RNFBFirebaseClientImport.swift} +22 -17
  236. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/project.pbxproj +588 -0
  237. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBFirebaseUnitTests.xcscheme +83 -0
  238. package/ios_config.sh +50 -22
  239. package/lib/FirebaseApp.ts +10 -0
  240. package/lib/common/Base64.ts +10 -16
  241. package/lib/common/deeps.ts +3 -0
  242. package/lib/common/index.ts +20 -9
  243. package/lib/internal/FirebaseModule.ts +6 -3
  244. package/lib/internal/NativeModules.ts +4 -1
  245. package/lib/internal/RNFBNativeEventEmitter.ts +14 -5
  246. package/lib/internal/SharedEventEmitter.ts +5 -1
  247. package/lib/internal/asyncStorage.ts +7 -11
  248. package/lib/internal/index.ts +1 -0
  249. package/lib/internal/logger.ts +53 -43
  250. package/lib/internal/nativeModuleAndroidIos.ts +2 -40
  251. package/lib/internal/nativeModuleDebug.ts +97 -0
  252. package/lib/internal/nativeModuleWeb.ts +10 -40
  253. package/lib/internal/react-native-vendor-emitter.d.ts +11 -0
  254. package/lib/internal/registry/app.ts +8 -2
  255. package/lib/internal/registry/modular.ts +2 -2
  256. package/lib/internal/registry/nativeModule.ts +3 -3
  257. package/lib/internal/web/RNFBAppModule.ts +16 -15
  258. package/lib/internal/web/memidb/lib/FakeEventTarget.js +3 -1
  259. package/lib/types/app.ts +10 -3
  260. package/lib/types/internal.ts +19 -0
  261. package/lib/version.ts +1 -1
  262. package/package.json +9 -8
  263. package/plugin/build/ios/appDelegate.js +19 -9
  264. package/plugin/build/ios/podfile.js +16 -16
  265. package/plugin/build/pluginConfig.d.ts +4 -2
  266. package/plugin/src/ios/appDelegate.ts +45 -15
  267. package/plugin/src/ios/podfile.ts +20 -23
  268. package/plugin/src/pluginConfig.ts +4 -2
  269. package/android/src/main/java/io/invertase/firebase/common/TaskExecutorService.java +0 -124
  270. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.java +0 -62
  271. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebasePreferences.java +0 -91
  272. package/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java +0 -222
  273. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseApp.java +0 -46
  274. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java +0 -49
  275. package/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java +0 -191
  276. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEvent.java +0 -53
  277. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitter.java +0 -606
  278. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseJSON.java +0 -107
  279. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseMeta.java +0 -101
  280. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseModule.java +0 -146
  281. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebasePreferences.java +0 -96
  282. package/android/src/reactnative/java/io/invertase/firebase/common/SharedUtils.java +0 -441
  283. package/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java +0 -223
@@ -0,0 +1,69 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Scheme
3
+ LastUpgradeVersion = "2600"
4
+ version = "1.7">
5
+ <BuildAction
6
+ parallelizeBuildables = "YES"
7
+ buildImplicitDependencies = "YES">
8
+ <BuildActionEntries>
9
+ <BuildActionEntry
10
+ buildForTesting = "YES"
11
+ buildForRunning = "YES"
12
+ buildForProfiling = "NO"
13
+ buildForArchiving = "NO"
14
+ buildForAnalyzing = "YES">
15
+ <BuildableReference
16
+ BuildableIdentifier = "primary"
17
+ BlueprintIdentifier = "A10000000000000000000002"
18
+ BuildableName = "RNFBAppUnitTests.xctest"
19
+ BlueprintName = "RNFBAppUnitTests"
20
+ ReferencedContainer = "container:RNFBAppUnitTests.xcodeproj">
21
+ </BuildableReference>
22
+ </BuildActionEntry>
23
+ </BuildActionEntries>
24
+ </BuildAction>
25
+ <TestAction
26
+ buildConfiguration = "Debug"
27
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29
+ shouldUseLaunchSchemeArgsEnv = "YES"
30
+ codeCoverageEnabled = "YES">
31
+ <Testables>
32
+ <TestableReference
33
+ skipped = "NO">
34
+ <BuildableReference
35
+ BuildableIdentifier = "primary"
36
+ BlueprintIdentifier = "A10000000000000000000002"
37
+ BuildableName = "RNFBAppUnitTests.xctest"
38
+ BlueprintName = "RNFBAppUnitTests"
39
+ ReferencedContainer = "container:RNFBAppUnitTests.xcodeproj">
40
+ </BuildableReference>
41
+ </TestableReference>
42
+ </Testables>
43
+ </TestAction>
44
+ <LaunchAction
45
+ buildConfiguration = "Debug"
46
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48
+ launchStyle = "0"
49
+ useCustomWorkingDirectory = "NO"
50
+ ignoresPersistentStateOnLaunch = "NO"
51
+ debugDocumentVersioning = "YES"
52
+ debugServiceExtension = "internal"
53
+ allowLocationSimulation = "YES">
54
+ </LaunchAction>
55
+ <ProfileAction
56
+ buildConfiguration = "Release"
57
+ shouldUseLaunchSchemeArgsEnv = "YES"
58
+ savedToolIdentifier = ""
59
+ useCustomWorkingDirectory = "NO"
60
+ debugDocumentVersioning = "YES">
61
+ </ProfileAction>
62
+ <AnalyzeAction
63
+ buildConfiguration = "Debug">
64
+ </AnalyzeAction>
65
+ <ArchiveAction
66
+ buildConfiguration = "Release"
67
+ revealArchiveInOrganizer = "YES">
68
+ </ArchiveAction>
69
+ </Scheme>
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import FirebaseCore
18
+ import Foundation
19
+ import RNFBFirebase
20
+ import XCTest
21
+
22
+ @_silgen_name("RNFBFirebaseInstallationsLinked")
23
+ private func RNFBFirebaseInstallationsLinked() -> ObjCBool
24
+
25
+ final class RNFBFirebaseAppClientTests: XCTestCase {
26
+ override func tearDown() {
27
+ FirebaseApp.resetRegistryForTesting()
28
+ FirebaseConfiguration.resetForTesting()
29
+ super.tearDown()
30
+ }
31
+
32
+ func testInstallationsLinkageAnchorIsDistinctFromNSObject() {
33
+ XCTAssertTrue(RNFBFirebaseInstallationsLinked().boolValue)
34
+ }
35
+
36
+ func testCreateOptionsPreservesNilIdentifiersAndDeallocates() {
37
+ weak var released: FirebaseOptions?
38
+ autoreleasepool {
39
+ let created = RNFBFirebaseOptionsClient.create(googleAppID: nil, gcmSenderID: nil)
40
+ let options = created as! FirebaseOptions
41
+ released = options
42
+ XCTAssertNil(options.googleAppID)
43
+ XCTAssertNil(options.gcmSenderID)
44
+ }
45
+ XCTAssertNil(released)
46
+ }
47
+
48
+ func testOptionsClientRoundTripsMutableFields() {
49
+ let created = RNFBFirebaseOptionsClient.create(googleAppID: "app-id", gcmSenderID: "sender-id")
50
+ let createdOptions = created as! FirebaseOptions
51
+ XCTAssertEqual(createdOptions.googleAppID, "app-id")
52
+ XCTAssertEqual(createdOptions.gcmSenderID, "sender-id")
53
+
54
+ RNFBFirebaseOptionsClient.setAPIKey("api-key", on: created)
55
+ RNFBFirebaseOptionsClient.setProjectID("project-id", on: created)
56
+ RNFBFirebaseOptionsClient.setClientID("client-id", on: created)
57
+ RNFBFirebaseOptionsClient.setDatabaseURL("https://example.firebaseio.com", on: created)
58
+ RNFBFirebaseOptionsClient.setStorageBucket("example.appspot.com", on: created)
59
+ RNFBFirebaseOptionsClient.setBundleID("com.example.app", on: created)
60
+ RNFBFirebaseOptionsClient.setAppGroupID("group.com.example", on: created)
61
+
62
+ XCTAssertEqual(RNFBFirebaseOptionsClient.apiKey(created), "api-key")
63
+ XCTAssertEqual(RNFBFirebaseOptionsClient.projectID(created), "project-id")
64
+ XCTAssertEqual(RNFBFirebaseOptionsClient.clientID(created), "client-id")
65
+ XCTAssertEqual(RNFBFirebaseOptionsClient.databaseURL(created), "https://example.firebaseio.com")
66
+ XCTAssertEqual(RNFBFirebaseOptionsClient.storageBucket(created), "example.appspot.com")
67
+ XCTAssertEqual(RNFBFirebaseOptionsClient.bundleID(created), "com.example.app")
68
+ XCTAssertEqual(RNFBFirebaseOptionsClient.appGroupID(created), "group.com.example")
69
+
70
+ // Pre-port `options.bundleID = nil` removed the key. nil must reach the SDK setter.
71
+ RNFBFirebaseOptionsClient.setBundleID(nil, on: created)
72
+ RNFBFirebaseOptionsClient.setAppGroupID(nil, on: created)
73
+ XCTAssertNil(createdOptions.bundleID)
74
+ XCTAssertNil(RNFBFirebaseOptionsClient.bundleID(created))
75
+ XCTAssertNil(RNFBFirebaseOptionsClient.appGroupID(created))
76
+ }
77
+
78
+ func testAppLookupConfigureSnapshotAndAllApps() {
79
+ XCTAssertNil(RNFBFirebaseAppClient.defaultApp())
80
+ XCTAssertNil(RNFBFirebaseAppClient.app(named: "missing"))
81
+ XCTAssertNil(RNFBFirebaseAppClient.allApps())
82
+
83
+ let options = RNFBFirebaseOptionsClient.create(googleAppID: "app-id", gcmSenderID: "sender-id")
84
+ RNFBFirebaseOptionsClient.setAPIKey("api-key", on: options)
85
+ RNFBFirebaseOptionsClient.setProjectID("project-id", on: options)
86
+ RNFBFirebaseOptionsClient.setClientID("client-id", on: options)
87
+ RNFBFirebaseOptionsClient.setDatabaseURL("https://example.firebaseio.com", on: options)
88
+ RNFBFirebaseOptionsClient.setStorageBucket("example.appspot.com", on: options)
89
+
90
+ RNFBFirebaseAppClient.configure(options: options)
91
+ let defaultApp = RNFBFirebaseAppClient.defaultApp()
92
+ XCTAssertNotNil(defaultApp)
93
+
94
+ let namedOptions = RNFBFirebaseOptionsClient.create(googleAppID: "named-app", gcmSenderID: "named-sender")
95
+ RNFBFirebaseAppClient.configure(name: "secondary", options: namedOptions)
96
+ let named = RNFBFirebaseAppClient.app(named: "secondary")
97
+ XCTAssertNotNil(named)
98
+
99
+ let apps = RNFBFirebaseAppClient.allApps()
100
+ XCTAssertEqual(apps?.count, 2)
101
+
102
+ let snapshot = RNFBFirebaseAppClient.snapshot(of: defaultApp!)
103
+ XCTAssertEqual(snapshot.name, "__FIRAPP_DEFAULT")
104
+ XCTAssertEqual(snapshot.googleAppID, "app-id")
105
+ XCTAssertEqual(snapshot.gcmSenderID, "sender-id")
106
+ XCTAssertEqual(snapshot.apiKey, "api-key")
107
+ XCTAssertEqual(snapshot.projectID, "project-id")
108
+ XCTAssertEqual(snapshot.clientID, "client-id")
109
+ XCTAssertEqual(snapshot.databaseURL, "https://example.firebaseio.com")
110
+ XCTAssertEqual(snapshot.storageBucket, "example.appspot.com")
111
+ XCTAssertFalse(snapshot.isDataCollectionDefaultEnabled)
112
+
113
+ XCTAssertFalse(RNFBFirebaseAppClient.setDataCollectionDefaultEnabled(true, forApp: NSObject()))
114
+ XCTAssertTrue(RNFBFirebaseAppClient.setDataCollectionDefaultEnabled(true, forApp: defaultApp!))
115
+ XCTAssertTrue(RNFBFirebaseAppClient.snapshot(of: defaultApp!).isDataCollectionDefaultEnabled)
116
+ }
117
+
118
+ func testDefaultPlistConfigureCreatesDefaultApp() {
119
+ // The dynamic probe app (test-rn-bare) calls this overload from its AppDelegate.
120
+ XCTAssertNil(RNFBFirebaseAppClient.defaultApp())
121
+ RNFBFirebaseAppClient.configure()
122
+ XCTAssertNotNil(RNFBFirebaseAppClient.defaultApp())
123
+ }
124
+
125
+ func testDeleteAppRejectsNonFirebaseAndRemovesLiveApp() {
126
+ var completionCalled = false
127
+ XCTAssertFalse(
128
+ RNFBFirebaseAppClient.deleteApp(NSObject()) { _ in
129
+ completionCalled = true
130
+ }
131
+ )
132
+ XCTAssertFalse(completionCalled)
133
+
134
+ let options = RNFBFirebaseOptionsClient.create(googleAppID: "app-id", gcmSenderID: "sender")
135
+ RNFBFirebaseAppClient.configure(name: "secondary", options: options)
136
+ let app = RNFBFirebaseAppClient.app(named: "secondary")!
137
+ let expectation = expectation(description: "delete")
138
+ XCTAssertTrue(
139
+ RNFBFirebaseAppClient.deleteApp(app) { success in
140
+ XCTAssertTrue(success)
141
+ expectation.fulfill()
142
+ }
143
+ )
144
+ waitForExpectations(timeout: 1)
145
+ XCTAssertNil(RNFBFirebaseAppClient.app(named: "secondary"))
146
+ }
147
+
148
+ func testLoggerLevelPassesThroughKnownAndUnknownValues() {
149
+ RNFBFirebaseAppClient.setLoggerLevel(7)
150
+ XCTAssertEqual(FirebaseConfiguration.shared.loggerLevel, unsafeBitCast(7, to: FirebaseLoggerLevel.self))
151
+ RNFBFirebaseAppClient.setLoggerLevel(99)
152
+ XCTAssertEqual(FirebaseConfiguration.shared.loggerLevel, unsafeBitCast(99, to: FirebaseLoggerLevel.self))
153
+ }
154
+
155
+ func testRegisterLibrarySkipsMissingSelectorAndRecordsWhenPresent() {
156
+ FirebaseApp.setRegisterLibraryAvailableForTesting(false)
157
+ RNFBFirebaseAppClient.registerLibrary(name: "skipped-c", version: "0")
158
+ XCTAssertNil(FirebaseApp.lastRegisteredLibraryNameForTesting())
159
+ FirebaseApp.setRegisterLibraryAvailableForTesting(true)
160
+
161
+ RNFBFirebaseAppClient.registerLibrary(name: "react-native-firebase", version: "9.9.9")
162
+ XCTAssertEqual(FirebaseApp.lastRegisteredLibraryNameForTesting(), "react-native-firebase")
163
+ XCTAssertEqual(FirebaseApp.lastRegisteredLibraryVersionForTesting(), "9.9.9")
164
+ }
165
+ }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import Foundation
18
+ import XCTest
19
+
20
+ final class RNFBHandleMapStorageTests: XCTestCase {
21
+ private var storage: RNFBHandleMapStorage!
22
+
23
+ override func setUp() {
24
+ super.setUp()
25
+ storage = RNFBHandleMapStorage()
26
+ }
27
+
28
+ func testStorageOperationsPreserveExactPointers() {
29
+ let first = NSMutableString(string: "equal")
30
+ let equalButDistinct = NSMutableString(string: "equal")
31
+ let replacement = NSObject()
32
+
33
+ XCTAssertEqual(first, equalButDistinct)
34
+ XCTAssertFalse(first === equalButDistinct)
35
+
36
+ XCTAssertTrue(storage.putIfAbsent(1 as NSNumber, value: first))
37
+ XCTAssertFalse(storage.putIfAbsent(1 as NSNumber, value: replacement))
38
+ XCTAssertTrue(storage.get(1 as NSNumber) === first)
39
+
40
+ XCTAssertTrue(storage.putIfAbsentOrSame(1 as NSNumber, value: first))
41
+ XCTAssertFalse(storage.putIfAbsentOrSame(1 as NSNumber, value: equalButDistinct))
42
+ XCTAssertTrue(storage.get(1 as NSNumber) === first)
43
+
44
+ XCTAssertTrue(storage.putIfAbsentOrSame(2 as NSNumber, value: equalButDistinct))
45
+ XCTAssertTrue(storage.get(2 as NSNumber) === equalButDistinct)
46
+
47
+ XCTAssertNil(storage.putReplacing(3 as NSNumber, value: first))
48
+ XCTAssertTrue(storage.putReplacing(3 as NSNumber, value: replacement) === first)
49
+ XCTAssertTrue(storage.take(3 as NSNumber) === replacement)
50
+ XCTAssertNil(storage.take(3 as NSNumber))
51
+ }
52
+
53
+ func testTakeIfMissingDoesNotCallConditionAndFalseLeavesValue() {
54
+ var conditionCalled = false
55
+ XCTAssertNil(storage.takeIf(1 as NSNumber) { _ in
56
+ conditionCalled = true
57
+ return true
58
+ })
59
+ XCTAssertFalse(conditionCalled)
60
+
61
+ let value = NSObject()
62
+ XCTAssertTrue(storage.putIfAbsent(1 as NSNumber, value: value))
63
+ XCTAssertNil(storage.takeIf(1 as NSNumber) { candidate in
64
+ conditionCalled = true
65
+ XCTAssertTrue(candidate === value)
66
+ return false
67
+ })
68
+ XCTAssertTrue(conditionCalled)
69
+ XCTAssertTrue(storage.get(1 as NSNumber) === value)
70
+ }
71
+
72
+ func testTakeIfConditionRunsUnderRecursiveLock() {
73
+ let value = NSObject()
74
+ XCTAssertTrue(storage.putIfAbsent(1 as NSNumber, value: value))
75
+
76
+ let conditionEntered = DispatchSemaphore(value: 0)
77
+ let releaseCondition = DispatchSemaphore(value: 0)
78
+ let takeIfDone = DispatchSemaphore(value: 0)
79
+ let competingTakeDone = DispatchSemaphore(value: 0)
80
+ var taken: AnyObject?
81
+ var competingTake: AnyObject?
82
+
83
+ DispatchQueue.global().async {
84
+ taken = self.storage.takeIf(1 as NSNumber) { candidate in
85
+ XCTAssertTrue(candidate === value)
86
+ XCTAssertTrue(self.storage.get(1 as NSNumber) === value)
87
+ conditionEntered.signal()
88
+ XCTAssertEqual(releaseCondition.wait(timeout: .now() + 5), .success)
89
+ return true
90
+ }
91
+ takeIfDone.signal()
92
+ }
93
+
94
+ XCTAssertEqual(conditionEntered.wait(timeout: .now() + 5), .success)
95
+ DispatchQueue.global().async {
96
+ competingTake = self.storage.take(1 as NSNumber)
97
+ competingTakeDone.signal()
98
+ }
99
+
100
+ XCTAssertEqual(competingTakeDone.wait(timeout: .now() + 0.1), .timedOut)
101
+ releaseCondition.signal()
102
+ XCTAssertEqual(takeIfDone.wait(timeout: .now() + 5), .success)
103
+ XCTAssertEqual(competingTakeDone.wait(timeout: .now() + 5), .success)
104
+ XCTAssertTrue(taken === value)
105
+ XCTAssertNil(competingTake)
106
+ }
107
+
108
+ func testTakeAllReturnsSnapshotThenClears() {
109
+ let first = NSObject()
110
+ let second = NSObject()
111
+ XCTAssertTrue(storage.putIfAbsent(1 as NSNumber, value: first))
112
+ XCTAssertTrue(storage.putIfAbsent(2 as NSNumber, value: second))
113
+
114
+ let values = storage.takeAll()
115
+
116
+ XCTAssertEqual(values.count, 2)
117
+ XCTAssertTrue(values.contains { $0 === first })
118
+ XCTAssertTrue(values.contains { $0 === second })
119
+ XCTAssertTrue(storage.takeAll().isEmpty)
120
+ }
121
+ }
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <XCTest/XCTest.h>
19
+
20
+ #import "RNFBHandleMap.h"
21
+
22
+ /**
23
+ * XCTest coverage for RNFBHandleMap. Tests must not invoke methods on stored values — the map only
24
+ * moves pointers.
25
+ */
26
+ @interface RNFBHandleMapTests : XCTestCase
27
+ @property(nonatomic, strong) RNFBHandleMap *map;
28
+ @end
29
+
30
+ @implementation RNFBHandleMapTests
31
+
32
+ - (void)setUp {
33
+ [super setUp];
34
+ self.map = [[RNFBHandleMap alloc] init];
35
+ }
36
+
37
+ - (void)testPutGetTake_happyPath {
38
+ NSObject *handle = [[NSObject alloc] init];
39
+ NSError *error = nil;
40
+ XCTAssertTrue([self.map put:@1 value:handle error:&error]);
41
+ XCTAssertNil(error);
42
+
43
+ XCTAssertEqual(handle, [self.map get:@1]);
44
+ XCTAssertEqual(handle, [self.map take:@1]);
45
+ XCTAssertNil([self.map get:@1]);
46
+ }
47
+
48
+ - (void)testTake_missingKey_returnsNil {
49
+ XCTAssertNil([self.map take:@99]);
50
+ XCTAssertNil([self.map get:@99]);
51
+ }
52
+
53
+ - (void)testTakeAll_returnsSnapshotAndLeavesMapEmpty {
54
+ NSObject *a = [[NSObject alloc] init];
55
+ NSObject *b = [[NSObject alloc] init];
56
+ XCTAssertTrue([self.map put:@1 value:a error:nil]);
57
+ XCTAssertTrue([self.map put:@2 value:b error:nil]);
58
+
59
+ NSArray *snapshot = [self.map takeAll];
60
+
61
+ XCTAssertEqual(snapshot.count, 2u);
62
+ XCTAssertTrue([snapshot containsObject:a]);
63
+ XCTAssertTrue([snapshot containsObject:b]);
64
+ XCTAssertNil([self.map get:@1]);
65
+ XCTAssertNil([self.map get:@2]);
66
+ XCTAssertEqual([self.map takeAll].count, 0u);
67
+ }
68
+
69
+ - (void)testPut_occupiedId_returnsCollision {
70
+ NSObject *first = [[NSObject alloc] init];
71
+ XCTAssertTrue([self.map put:@1 value:first error:nil]);
72
+
73
+ NSError *error = nil;
74
+ XCTAssertFalse([self.map put:@1 value:[[NSObject alloc] init] error:&error]);
75
+ XCTAssertNotNil(error);
76
+ XCTAssertEqualObjects(error.domain, RNFBHandleMapErrorDomain);
77
+ XCTAssertEqual(error.code, RNFBHandleMapErrorCollision);
78
+ XCTAssertTrue([error.localizedDescription containsString:@"1"]);
79
+ XCTAssertEqual(first, [self.map get:@1]);
80
+
81
+ XCTAssertFalse([self.map put:@1 value:[[NSObject alloc] init] error:nil]);
82
+ XCTAssertEqual(first, [self.map get:@1]);
83
+ }
84
+
85
+ - (void)testPutIfAbsent_whenFree_storesAndReturnsYes {
86
+ NSObject *handle = [[NSObject alloc] init];
87
+ XCTAssertTrue([self.map putIfAbsent:@1 value:handle]);
88
+ XCTAssertEqual(handle, [self.map get:@1]);
89
+ }
90
+
91
+ - (void)testPutIfAbsent_whenOccupied_keepsExistingAndReturnsNo {
92
+ NSObject *first = [[NSObject alloc] init];
93
+ NSObject *second = [[NSObject alloc] init];
94
+ XCTAssertTrue([self.map put:@1 value:first error:nil]);
95
+ XCTAssertFalse([self.map putIfAbsent:@1 value:second]);
96
+ XCTAssertEqual(first, [self.map get:@1]);
97
+ }
98
+
99
+ - (void)testPutIfAbsentOrSame_whenAbsent_storesAndReturnsYes {
100
+ NSObject *handle = [[NSObject alloc] init];
101
+ XCTAssertTrue([self.map putIfAbsentOrSame:@1 value:handle]);
102
+ XCTAssertEqual(handle, [self.map get:@1]);
103
+ }
104
+
105
+ - (void)testPutIfAbsentOrSame_whenSameInstance_returnsYes {
106
+ NSObject *handle = [[NSObject alloc] init];
107
+ XCTAssertTrue([self.map put:@1 value:handle error:nil]);
108
+ XCTAssertTrue([self.map putIfAbsentOrSame:@1 value:handle]);
109
+ XCTAssertEqual(handle, [self.map get:@1]);
110
+ }
111
+
112
+ - (void)testPutIfAbsentOrSame_whenDifferent_returnsNo {
113
+ NSObject *first = [[NSObject alloc] init];
114
+ NSObject *second = [[NSObject alloc] init];
115
+ XCTAssertTrue([self.map put:@1 value:first error:nil]);
116
+ XCTAssertFalse([self.map putIfAbsentOrSame:@1 value:second]);
117
+ XCTAssertEqual(first, [self.map get:@1]);
118
+ }
119
+
120
+ - (void)testPutReplacing_whenFree_storesAndReturnsNil {
121
+ NSObject *handle = [[NSObject alloc] init];
122
+ XCTAssertNil([self.map putReplacing:@1 value:handle]);
123
+ XCTAssertEqual(handle, [self.map get:@1]);
124
+ }
125
+
126
+ - (void)testPutReplacing_whenOccupied_replacesLastWins {
127
+ NSObject *first = [[NSObject alloc] init];
128
+ NSObject *second = [[NSObject alloc] init];
129
+ XCTAssertTrue([self.map put:@1 value:first error:nil]);
130
+ XCTAssertEqual(first, [self.map putReplacing:@1 value:second]);
131
+ XCTAssertEqual(second, [self.map get:@1]);
132
+ }
133
+
134
+ - (void)testPut_afterTake_allowsReuse {
135
+ NSObject *first = [[NSObject alloc] init];
136
+ NSObject *second = [[NSObject alloc] init];
137
+ XCTAssertTrue([self.map put:@1 value:first error:nil]);
138
+ XCTAssertEqual(first, [self.map take:@1]);
139
+ XCTAssertTrue([self.map put:@1 value:second error:nil]);
140
+ XCTAssertEqual(second, [self.map get:@1]);
141
+ }
142
+
143
+ - (void)testTakeIf_whenConditionYes_removesAndReturns {
144
+ NSObject *handle = [[NSObject alloc] init];
145
+ XCTAssertTrue([self.map put:@1 value:handle error:nil]);
146
+ XCTAssertEqual(handle, [self.map takeIf:@1
147
+ when:^BOOL(id value) {
148
+ return value == handle;
149
+ }]);
150
+ XCTAssertNil([self.map get:@1]);
151
+ }
152
+
153
+ - (void)testTakeIf_whenConditionNo_leavesMapping {
154
+ NSObject *handle = [[NSObject alloc] init];
155
+ XCTAssertTrue([self.map put:@1 value:handle error:nil]);
156
+ XCTAssertNil([self.map takeIf:@1
157
+ when:^BOOL(id value) {
158
+ return NO;
159
+ }]);
160
+ XCTAssertEqual(handle, [self.map get:@1]);
161
+ }
162
+
163
+ - (void)testTakeIf_whenMissing_returnsNil {
164
+ XCTAssertNil([self.map takeIf:@99
165
+ when:^BOOL(id value) {
166
+ return YES;
167
+ }]);
168
+ }
169
+
170
+ - (void)testTake_sameIdFromTwoThreads_onlyOneReturnsNonNull {
171
+ NSObject *handle = [[NSObject alloc] init];
172
+ XCTAssertTrue([self.map put:@1 value:handle error:nil]);
173
+
174
+ dispatch_semaphore_t start = dispatch_semaphore_create(0);
175
+ dispatch_semaphore_t done = dispatch_semaphore_create(0);
176
+ __block id first = [NSNull null];
177
+ __block id second = [NSNull null];
178
+
179
+ dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
180
+ dispatch_semaphore_wait(start, DISPATCH_TIME_FOREVER);
181
+ first = [self.map take:@1];
182
+ dispatch_semaphore_signal(done);
183
+ });
184
+ dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
185
+ dispatch_semaphore_wait(start, DISPATCH_TIME_FOREVER);
186
+ second = [self.map take:@1];
187
+ dispatch_semaphore_signal(done);
188
+ });
189
+
190
+ dispatch_semaphore_signal(start);
191
+ dispatch_semaphore_signal(start);
192
+ XCTAssertEqual(dispatch_semaphore_wait(done, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC)),
193
+ 0);
194
+ XCTAssertEqual(dispatch_semaphore_wait(done, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC)),
195
+ 0);
196
+
197
+ BOOL onlyFirst = first == handle && second == nil;
198
+ BOOL onlySecond = second == handle && first == nil;
199
+ XCTAssertTrue(onlyFirst || onlySecond);
200
+ XCTAssertNil([self.map get:@1]);
201
+ }
202
+
203
+ - (void)testPutReplacing_sameIdFromTwoThreads_lastWins {
204
+ NSObject *first = [[NSObject alloc] init];
205
+ NSObject *second = [[NSObject alloc] init];
206
+ NSObject *third = [[NSObject alloc] init];
207
+ XCTAssertTrue([self.map put:@1 value:first error:nil]);
208
+
209
+ dispatch_semaphore_t start = dispatch_semaphore_create(0);
210
+ dispatch_semaphore_t done = dispatch_semaphore_create(0);
211
+ __block id prevA = [NSNull null];
212
+ __block id prevB = [NSNull null];
213
+
214
+ dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
215
+ dispatch_semaphore_wait(start, DISPATCH_TIME_FOREVER);
216
+ prevA = [self.map putReplacing:@1 value:second];
217
+ dispatch_semaphore_signal(done);
218
+ });
219
+ dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
220
+ dispatch_semaphore_wait(start, DISPATCH_TIME_FOREVER);
221
+ prevB = [self.map putReplacing:@1 value:third];
222
+ dispatch_semaphore_signal(done);
223
+ });
224
+
225
+ dispatch_semaphore_signal(start);
226
+ dispatch_semaphore_signal(start);
227
+ XCTAssertEqual(dispatch_semaphore_wait(done, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC)),
228
+ 0);
229
+ XCTAssertEqual(dispatch_semaphore_wait(done, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC)),
230
+ 0);
231
+
232
+ id winner = [self.map get:@1];
233
+ XCTAssertTrue(winner == second || winner == third);
234
+ id returnedFirst = prevA == first ? prevA : prevB;
235
+ XCTAssertEqual(first, returnedFirst);
236
+ }
237
+
238
+ @end