@react-native-firebase/app 26.4.0 → 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 (242) hide show
  1. package/CHANGELOG.md +48 -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 +182 -59
  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 +143 -12
  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 -21
  58. package/dist/module/FirebaseApp.js +10 -0
  59. package/dist/module/FirebaseApp.js.map +1 -1
  60. package/dist/module/common/deeps.js +3 -0
  61. package/dist/module/common/deeps.js.map +1 -1
  62. package/dist/module/internal/FirebaseModule.js.map +1 -1
  63. package/dist/module/internal/RNFBNativeEventEmitter.js +12 -1
  64. package/dist/module/internal/RNFBNativeEventEmitter.js.map +1 -1
  65. package/dist/module/internal/SharedEventEmitter.js +3 -1
  66. package/dist/module/internal/SharedEventEmitter.js.map +1 -1
  67. package/dist/module/internal/index.js +1 -0
  68. package/dist/module/internal/index.js.map +1 -1
  69. package/dist/module/internal/registry/app.js +7 -1
  70. package/dist/module/internal/registry/app.js.map +1 -1
  71. package/dist/module/types/app.js.map +1 -1
  72. package/dist/module/types/internal.js +2 -0
  73. package/dist/module/version.js +1 -1
  74. package/dist/typescript/lib/FirebaseApp.d.ts +7 -0
  75. package/dist/typescript/lib/FirebaseApp.d.ts.map +1 -1
  76. package/dist/typescript/lib/common/deeps.d.ts.map +1 -1
  77. package/dist/typescript/lib/internal/FirebaseModule.d.ts +2 -3
  78. package/dist/typescript/lib/internal/FirebaseModule.d.ts.map +1 -1
  79. package/dist/typescript/lib/internal/NativeModules.d.ts +4 -1
  80. package/dist/typescript/lib/internal/NativeModules.d.ts.map +1 -1
  81. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts +2 -2
  82. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts.map +1 -1
  83. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts +3 -3
  84. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts.map +1 -1
  85. package/dist/typescript/lib/internal/index.d.ts +1 -0
  86. package/dist/typescript/lib/internal/index.d.ts.map +1 -1
  87. package/dist/typescript/lib/internal/registry/app.d.ts.map +1 -1
  88. package/dist/typescript/lib/types/app.d.ts +10 -3
  89. package/dist/typescript/lib/types/app.d.ts.map +1 -1
  90. package/dist/typescript/lib/types/internal.d.ts +12 -0
  91. package/dist/typescript/lib/types/internal.d.ts.map +1 -1
  92. package/dist/typescript/lib/version.d.ts +1 -1
  93. package/firebase-schema.json +4 -0
  94. package/firebase_spm.rb +552 -96
  95. package/ios/RNFBApp/RCTConvert+FIRApp.h +2 -5
  96. package/ios/RNFBApp/RCTConvert+FIRApp.m +11 -6
  97. package/ios/RNFBApp/RCTConvert+FIROptions.h +2 -5
  98. package/ios/RNFBApp/RCTConvert+FIROptions.m +11 -10
  99. package/ios/RNFBApp/RCTConvertFIRApp.swift +86 -0
  100. package/ios/RNFBApp/RCTConvertFIROptions.swift +259 -0
  101. package/ios/RNFBApp/RNFBAppCustomAuthDomains.swift +63 -0
  102. package/ios/RNFBApp/RNFBAppInitializeOptionsMapper.swift +113 -0
  103. package/ios/RNFBApp/RNFBAppLogLevelMapper.swift +53 -0
  104. package/ios/RNFBApp/RNFBAppModule+CustomAuthDomain.m +35 -0
  105. package/ios/RNFBApp/RNFBAppModule.h +6 -2
  106. package/ios/RNFBApp/RNFBAppModule.mm +65 -228
  107. package/ios/RNFBApp/RNFBAppModuleFirebase.swift +439 -0
  108. package/ios/RNFBApp/RNFBAppModuleImplementation.h +68 -0
  109. package/ios/RNFBApp/RNFBAppModuleImplementation.m +195 -0
  110. package/ios/RNFBApp/RNFBHandleMap.m +27 -56
  111. package/ios/RNFBApp/RNFBHandleMapStorage.swift +90 -0
  112. package/ios/RNFBApp/RNFBInitializeAppArguments.swift +82 -0
  113. package/ios/RNFBApp/RNFBJSON.m +22 -38
  114. package/ios/RNFBApp/RNFBJSONImplementation.swift +71 -0
  115. package/ios/RNFBApp/RNFBMeta.m +24 -26
  116. package/ios/RNFBApp/RNFBMetaStorage.swift +76 -0
  117. package/ios/RNFBApp/RNFBNullSentinelDecoding.swift +135 -0
  118. package/ios/RNFBApp/RNFBNullSentinelInterceptor.h +30 -3
  119. package/ios/RNFBApp/RNFBNullSentinelInterceptor.m +28 -5
  120. package/ios/RNFBApp/RNFBPreferences.m +22 -20
  121. package/ios/RNFBApp/RNFBPreferencesStorage.swift +101 -0
  122. package/ios/RNFBApp/RNFBRCTEventEmitter.m +36 -93
  123. package/ios/RNFBApp/RNFBRCTEventEmitterCore.swift +161 -0
  124. package/ios/RNFBApp/RNFBSharedUtils.h +2 -5
  125. package/ios/RNFBApp/RNFBSharedUtils.m +109 -198
  126. package/ios/RNFBApp/RNFBSharedUtilsConfig.swift +72 -0
  127. package/ios/RNFBApp/RNFBSharedUtilsFIRApp.swift +271 -0
  128. package/ios/RNFBApp/RNFBSharedUtilsFormatting.swift +59 -0
  129. package/ios/RNFBApp/RNFBSharedUtilsPromiseRejection.swift +88 -0
  130. package/ios/RNFBApp/RNFBUtilsHelpers.swift +116 -0
  131. package/ios/RNFBApp/RNFBUtilsModule+Foundation.m +44 -0
  132. package/ios/RNFBApp/RNFBUtilsModule+PhotoAssets.m +47 -0
  133. package/ios/RNFBApp/RNFBUtilsModule.h +11 -1
  134. package/ios/RNFBApp/RNFBUtilsModule.mm +10 -85
  135. package/ios/RNFBApp/RNFBUtilsModuleImplementation.h +32 -0
  136. package/ios/RNFBApp/RNFBUtilsModuleImplementation.m +56 -0
  137. package/ios/RNFBApp/RNFBVersion.m +1 -1
  138. package/ios/RNFBApp.xcodeproj/project.pbxproj +100 -0
  139. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FIRApp.m +171 -0
  140. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FirebaseCore.h +78 -0
  141. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FIRInstallations.m +7 -0
  142. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FirebaseInstallations.h +8 -0
  143. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppModuleHostStub.m +55 -0
  144. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.h +89 -0
  145. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.mm +30 -0
  146. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.h +19 -0
  147. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.m +32 -0
  148. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridgeModule.h +19 -0
  149. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.h +28 -0
  150. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.m +23 -0
  151. package/ios/RNFBAppUnitTests/HostStubs/React/RCTEventEmitter.h +9 -0
  152. package/ios/RNFBAppUnitTests/HostStubs/React/RCTInvalidating.h +24 -0
  153. package/ios/RNFBAppUnitTests/HostStubs/React/RCTUtils.h +9 -0
  154. package/ios/RNFBAppUnitTests/HostStubs/module.modulemap +13 -0
  155. package/ios/RNFBAppUnitTests/RCTConvertFIRAppFacadeTests.m +61 -0
  156. package/ios/RNFBAppUnitTests/RCTConvertFIRAppTests.swift +73 -0
  157. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsFacadeTests.m +57 -0
  158. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsTests.swift +243 -0
  159. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsFacadeTests.m +73 -0
  160. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsTests.swift +70 -0
  161. package/ios/RNFBAppUnitTests/RNFBAppInitializeOptionsMapperTests.swift +190 -0
  162. package/ios/RNFBAppUnitTests/RNFBAppLogLevelFacadeTests.m +76 -0
  163. package/ios/RNFBAppUnitTests/RNFBAppLogLevelMapperTests.swift +59 -0
  164. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseFacadeTests.m +215 -0
  165. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseTests.swift +430 -0
  166. package/ios/RNFBAppUnitTests/RNFBAppModuleLifecycleTests.m +206 -0
  167. package/ios/RNFBAppUnitTests/RNFBAppModuleShellTests.mm +367 -0
  168. package/ios/RNFBAppUnitTests/RNFBAppUnitTests.xcodeproj/project.pbxproj +355 -2
  169. package/ios/RNFBAppUnitTests/RNFBFirebaseAppClientTests.swift +165 -0
  170. package/ios/RNFBAppUnitTests/RNFBHandleMapStorageTests.swift +121 -0
  171. package/ios/RNFBAppUnitTests/RNFBInitializeAppArgumentsTests.swift +256 -0
  172. package/ios/RNFBAppUnitTests/RNFBJSONImplementationTests.swift +126 -0
  173. package/ios/RNFBAppUnitTests/RNFBJSONTests.m +172 -0
  174. package/ios/RNFBAppUnitTests/RNFBMetaStorageTests.swift +106 -0
  175. package/ios/RNFBAppUnitTests/RNFBMetaTests.m +65 -0
  176. package/ios/RNFBAppUnitTests/RNFBNullSentinelDecodingTests.swift +286 -0
  177. package/ios/RNFBAppUnitTests/RNFBNullSentinelInterceptorTests.m +312 -0
  178. package/ios/RNFBAppUnitTests/RNFBPreferencesStorageTests.swift +105 -0
  179. package/ios/RNFBAppUnitTests/RNFBPreferencesTests.m +110 -0
  180. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterCoreTests.swift +163 -0
  181. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterFacadeTests.m +141 -0
  182. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigFacadeTests.m +100 -0
  183. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigTests.swift +234 -0
  184. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppFacadeTests.m +145 -0
  185. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppTests.swift +173 -0
  186. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingFacadeTests.m +38 -0
  187. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingTests.swift +82 -0
  188. package/ios/RNFBAppUnitTests/RNFBSharedUtilsNullSentinelTests.m +35 -0
  189. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionFacadeTests.m +107 -0
  190. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionTests.swift +133 -0
  191. package/ios/RNFBAppUnitTests/RNFBUtilsHelpersTests.swift +144 -0
  192. package/ios/RNFBAppUnitTests/RNFBUtilsModuleFacadeTests.m +72 -0
  193. package/ios/RNFBAppUnitTests/RNFBUtilsModuleShellTests.mm +282 -0
  194. package/ios/RNFBFirebase/Package.swift +53 -0
  195. package/ios/RNFBFirebase/Sources/RNFBFirebase/RNFBFirebase.swift +285 -0
  196. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/Public/.gitkeep +0 -0
  197. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/RNFBFirebaseBridge.m +169 -0
  198. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/include/RNFBFirebaseBridge.h +52 -0
  199. package/ios/RNFBFirebaseUnitTests/RNFBAppDynamicFacadeTests.swift +240 -0
  200. package/{android/src/main/java/io/invertase/firebase/common/RNFBHandleCollisionException.java → ios/RNFBFirebaseUnitTests/RNFBFirebaseClientImport.swift} +23 -14
  201. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/project.pbxproj +588 -0
  202. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBFirebaseUnitTests.xcscheme +83 -0
  203. package/ios_config.sh +50 -22
  204. package/lib/FirebaseApp.ts +10 -0
  205. package/lib/common/deeps.ts +3 -0
  206. package/lib/internal/FirebaseModule.ts +6 -3
  207. package/lib/internal/NativeModules.ts +4 -1
  208. package/lib/internal/RNFBNativeEventEmitter.ts +14 -5
  209. package/lib/internal/SharedEventEmitter.ts +5 -1
  210. package/lib/internal/index.ts +1 -0
  211. package/lib/internal/react-native-vendor-emitter.d.ts +11 -0
  212. package/lib/internal/registry/app.ts +7 -1
  213. package/lib/types/app.ts +10 -3
  214. package/lib/types/internal.ts +19 -0
  215. package/lib/version.ts +1 -1
  216. package/package.json +8 -8
  217. package/plugin/build/ios/appDelegate.js +2 -2
  218. package/plugin/build/ios/podfile.js +16 -16
  219. package/plugin/build/pluginConfig.d.ts +4 -2
  220. package/plugin/src/ios/appDelegate.ts +2 -2
  221. package/plugin/src/ios/podfile.ts +20 -23
  222. package/plugin/src/pluginConfig.ts +4 -2
  223. package/android/src/main/java/io/invertase/firebase/common/RNFBHandleMap.java +0 -150
  224. package/android/src/main/java/io/invertase/firebase/common/TaskExecutorService.java +0 -148
  225. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.java +0 -62
  226. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebasePreferences.java +0 -91
  227. package/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java +0 -224
  228. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseApp.java +0 -46
  229. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java +0 -49
  230. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppRegistrar.java +0 -35
  231. package/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java +0 -192
  232. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEvent.java +0 -53
  233. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitter.java +0 -606
  234. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseJSON.java +0 -109
  235. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseMeta.java +0 -101
  236. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseModule.java +0 -146
  237. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebasePreferences.java +0 -96
  238. package/android/src/reactnative/java/io/invertase/firebase/common/SharedUtils.java +0 -441
  239. package/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java +0 -223
  240. package/android/src/test/java/io/invertase/firebase/common/RNFBHandleMapTest.java +0 -275
  241. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseJSONTest.java +0 -108
  242. package/android/src/test/java/io/invertase/firebase/common/TaskExecutorServiceTest.java +0 -97
@@ -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,256 @@
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 RNFBInitializeAppArgumentsTests: XCTestCase {
21
+ private func nullSentinel() -> NSDictionary {
22
+ ["__rnfbNull": true] as NSDictionary
23
+ }
24
+
25
+ private func requiredOptions() -> NSDictionary {
26
+ [
27
+ "apiKey": "key",
28
+ "appId": "1:123:ios:abc",
29
+ "messagingSenderId": "123",
30
+ "projectId": "project",
31
+ ] as NSDictionary
32
+ }
33
+
34
+ private func optionsByAdding(_ extra: [String: Any]) -> NSDictionary {
35
+ let options = NSMutableDictionary(dictionary: requiredOptions())
36
+ options.addEntries(from: extra)
37
+ return options
38
+ }
39
+
40
+ func testOptions_sentinelIosBundleId_isDropped() {
41
+ let result = RNFBInitializeAppArguments.normalizedOptions(
42
+ optionsByAdding(["iosBundleId": nullSentinel()])
43
+ )!
44
+ XCTAssertNil(result["iosBundleId"])
45
+ XCTAssertFalse(result.allKeys.contains { ($0 as? String) == "iosBundleId" })
46
+ }
47
+
48
+ func testOptions_sentinelIosClientId_isDropped() {
49
+ let result = RNFBInitializeAppArguments.normalizedOptions(
50
+ optionsByAdding(["iosClientId": nullSentinel()])
51
+ )!
52
+ XCTAssertFalse(result.allKeys.contains { ($0 as? String) == "iosClientId" })
53
+ }
54
+
55
+ func testOptions_sentinelAppGroupId_isDropped() {
56
+ let result = RNFBInitializeAppArguments.normalizedOptions(
57
+ optionsByAdding(["appGroupId": nullSentinel()])
58
+ )!
59
+ XCTAssertFalse(result.allKeys.contains { ($0 as? String) == "appGroupId" })
60
+ }
61
+
62
+ func testOptions_sentinelAuthDomain_isDropped() {
63
+ let result = RNFBInitializeAppArguments.normalizedOptions(
64
+ optionsByAdding(["authDomain": nullSentinel()])
65
+ )!
66
+ XCTAssertNil(result["authDomain"])
67
+ XCTAssertFalse(result.allKeys.contains { ($0 as? String) == "authDomain" })
68
+ }
69
+
70
+ func testOptions_sentinelDatabaseUrlAndStorageBucket_areDropped() {
71
+ let result = RNFBInitializeAppArguments.normalizedOptions(
72
+ optionsByAdding(["databaseURL": nullSentinel(), "storageBucket": nullSentinel()])
73
+ )!
74
+ XCTAssertFalse(result.allKeys.contains { ($0 as? String) == "databaseURL" })
75
+ XCTAssertFalse(result.allKeys.contains { ($0 as? String) == "storageBucket" })
76
+ }
77
+
78
+ func testOptions_plainNSNullOptionalKey_isDropped() {
79
+ let result = RNFBInitializeAppArguments.normalizedOptions(
80
+ optionsByAdding(["iosBundleId": NSNull()])
81
+ )!
82
+ XCTAssertFalse(result.allKeys.contains { ($0 as? String) == "iosBundleId" })
83
+ }
84
+
85
+ func testOptions_allOptionalKeysNull_onlyRequiredKeysRemain() {
86
+ let result = RNFBInitializeAppArguments.normalizedOptions(
87
+ optionsByAdding([
88
+ "databaseURL": nullSentinel(),
89
+ "storageBucket": nullSentinel(),
90
+ "iosBundleId": nullSentinel(),
91
+ "iosClientId": nullSentinel(),
92
+ "appGroupId": nullSentinel(),
93
+ "authDomain": nullSentinel(),
94
+ ])
95
+ )
96
+ XCTAssertEqual(result, requiredOptions())
97
+ }
98
+
99
+ func testOptions_realStrings_areUnchanged() {
100
+ let input = optionsByAdding([
101
+ "databaseURL": "https://db.firebaseio.com",
102
+ "storageBucket": "bucket.appspot.com",
103
+ "iosBundleId": "com.example.app",
104
+ "iosClientId": "client-id",
105
+ "appGroupId": "group.com.example",
106
+ "authDomain": "example.firebaseapp.com",
107
+ ])
108
+ XCTAssertEqual(RNFBInitializeAppArguments.normalizedOptions(input), input)
109
+ }
110
+
111
+ func testOptions_nullOptionalKeyDoesNotAffectSiblingStrings() {
112
+ let result = RNFBInitializeAppArguments.normalizedOptions(
113
+ optionsByAdding([
114
+ "iosBundleId": nullSentinel(),
115
+ "iosClientId": "client-id",
116
+ "authDomain": "example.firebaseapp.com",
117
+ ])
118
+ )!
119
+ XCTAssertFalse(result.allKeys.contains { ($0 as? String) == "iosBundleId" })
120
+ XCTAssertEqual(result["iosClientId"] as? String, "client-id")
121
+ XCTAssertEqual(result["authDomain"] as? String, "example.firebaseapp.com")
122
+ XCTAssertEqual(result["apiKey"] as? String, "key")
123
+ }
124
+
125
+ func testOptions_nonOptionalKeyWithNull_isLeftAsNSNull() {
126
+ let result = RNFBInitializeAppArguments.normalizedOptions(
127
+ optionsByAdding(["projectId": nullSentinel()])
128
+ )!
129
+ XCTAssertTrue(result["projectId"] is NSNull)
130
+ XCTAssertEqual(result["apiKey"] as? String, "key")
131
+ }
132
+
133
+ func testOptions_oneKeyDictionaryThatIsNotSentinel_isUnchanged() {
134
+ let input = ["apiKey": "key"] as NSDictionary
135
+ XCTAssertEqual(RNFBInitializeAppArguments.normalizedOptions(input), input)
136
+ }
137
+
138
+ func testOptions_sentinelLookalikeValueForOptionalKey_isNotDropped() {
139
+ let notSentinel = ["__rnfbNull": false] as NSDictionary
140
+ let result = RNFBInitializeAppArguments.normalizedOptions(
141
+ optionsByAdding(["iosBundleId": notSentinel])
142
+ )!
143
+ XCTAssertEqual(result["iosBundleId"] as? NSDictionary, notSentinel)
144
+ }
145
+
146
+ func testOptions_nil_returnsNil() {
147
+ XCTAssertNil(RNFBInitializeAppArguments.normalizedOptions(nil))
148
+ }
149
+
150
+ func testOptions_rootSentinel_returnsNil() {
151
+ XCTAssertNil(RNFBInitializeAppArguments.normalizedOptions(nullSentinel()))
152
+ }
153
+
154
+ func testOptions_doesNotMutateInput() {
155
+ let input = optionsByAdding(["iosBundleId": nullSentinel()])
156
+ let copy = input.copy() as! NSDictionary
157
+ _ = RNFBInitializeAppArguments.normalizedOptions(input)
158
+ XCTAssertEqual(input, copy)
159
+ }
160
+
161
+ func testAppConfig_sentinelName_isDropped_andSentinelDataCollection_becomesNo() {
162
+ let result = RNFBInitializeAppArguments.normalizedAppConfig([
163
+ "name": nullSentinel(),
164
+ "automaticDataCollectionEnabled": nullSentinel(),
165
+ ])!
166
+ XCTAssertEqual(result.count, 1)
167
+ XCTAssertNil(result["name"])
168
+ XCTAssertEqual(result["automaticDataCollectionEnabled"] as? Bool, false)
169
+ }
170
+
171
+ func testAppConfig_nsNullDataCollection_becomesNo() {
172
+ let result = RNFBInitializeAppArguments.normalizedAppConfig([
173
+ "automaticDataCollectionEnabled": NSNull(),
174
+ ])!
175
+ XCTAssertEqual(result["automaticDataCollectionEnabled"] as? Bool, false)
176
+ }
177
+
178
+ func testAppConfig_omittedDataCollection_staysOmitted() {
179
+ let result = RNFBInitializeAppArguments.normalizedAppConfig(["name": "secondary"])!
180
+ XCTAssertNil(result["automaticDataCollectionEnabled"])
181
+ }
182
+
183
+ func testAppConfig_realValues_areUnchanged() {
184
+ let input = ["name": "secondary", "automaticDataCollectionEnabled": true] as NSDictionary
185
+ XCTAssertEqual(RNFBInitializeAppArguments.normalizedAppConfig(input), input)
186
+ }
187
+
188
+ func testAppConfig_unknownKeyWithNull_isLeftAsNSNull() {
189
+ let result = RNFBInitializeAppArguments.normalizedAppConfig([
190
+ "name": "secondary",
191
+ "extra": nullSentinel(),
192
+ ])!
193
+ XCTAssertEqual(result["name"] as? String, "secondary")
194
+ XCTAssertTrue(result["extra"] is NSNull)
195
+ }
196
+
197
+ func testAppConfig_nil_returnsNil() {
198
+ XCTAssertNil(RNFBInitializeAppArguments.normalizedAppConfig(nil))
199
+ }
200
+
201
+ func testAppConfig_rootSentinel_returnsNil() {
202
+ XCTAssertNil(RNFBInitializeAppArguments.normalizedAppConfig(nullSentinel()))
203
+ }
204
+
205
+ func testAutoDataCollection_yes_returnsYes() {
206
+ XCTAssertEqual(
207
+ RNFBInitializeAppArguments.automaticDataCollectionEnabled(fromAppConfig: [
208
+ "automaticDataCollectionEnabled": true,
209
+ ]),
210
+ NSNumber(value: true)
211
+ )
212
+ }
213
+
214
+ func testAutoDataCollection_explicitNo_returnsNo() {
215
+ let result = RNFBInitializeAppArguments.automaticDataCollectionEnabled(fromAppConfig: [
216
+ "automaticDataCollectionEnabled": false,
217
+ ])
218
+ XCTAssertNotNil(result)
219
+ XCTAssertFalse(result!.boolValue)
220
+ }
221
+
222
+ func testAutoDataCollection_absentKey_returnsNil() {
223
+ XCTAssertNil(
224
+ RNFBInitializeAppArguments.automaticDataCollectionEnabled(fromAppConfig: ["name": "secondary"])
225
+ )
226
+ }
227
+
228
+ func testAutoDataCollection_nilAppConfig_returnsNil() {
229
+ XCTAssertNil(RNFBInitializeAppArguments.automaticDataCollectionEnabled(fromAppConfig: nil))
230
+ }
231
+
232
+ func testAutoDataCollection_NSNull_returnsNil() {
233
+ XCTAssertNil(
234
+ RNFBInitializeAppArguments.automaticDataCollectionEnabled(fromAppConfig: [
235
+ "automaticDataCollectionEnabled": NSNull(),
236
+ ])
237
+ )
238
+ }
239
+
240
+ func testAutoDataCollection_sentinelNormalizedUpstream_returnsNo() {
241
+ let normalized = RNFBInitializeAppArguments.normalizedAppConfig([
242
+ "automaticDataCollectionEnabled": nullSentinel(),
243
+ ])
244
+ let result = RNFBInitializeAppArguments.automaticDataCollectionEnabled(fromAppConfig: normalized)
245
+ XCTAssertNotNil(result)
246
+ XCTAssertFalse(result!.boolValue)
247
+ }
248
+
249
+ func testAutoDataCollection_nonNumberValue_returnsNil() {
250
+ XCTAssertNil(
251
+ RNFBInitializeAppArguments.automaticDataCollectionEnabled(fromAppConfig: [
252
+ "automaticDataCollectionEnabled": "true",
253
+ ])
254
+ )
255
+ }
256
+ }
@@ -0,0 +1,126 @@
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 RNFBJSONImplementationTests: XCTestCase {
21
+ private func base64(_ object: Any) throws -> String {
22
+ try JSONSerialization.data(withJSONObject: object).base64EncodedString()
23
+ }
24
+
25
+ func testNilInvalidBase64AndInvalidJSONProduceEmptyDictionaries() {
26
+ let implementations = [
27
+ RNFBJSONImplementation(rawValue: nil),
28
+ RNFBJSONImplementation(rawValue: "not base64"),
29
+ RNFBJSONImplementation(rawValue: Data("{".utf8).base64EncodedString()),
30
+ ]
31
+
32
+ for implementation in implementations {
33
+ XCTAssertFalse(implementation.contains("missing"))
34
+ XCTAssertEqual(
35
+ implementation.value(forKey: "missing", defaultValue: "fallback" as NSString) as? String,
36
+ "fallback"
37
+ )
38
+ XCTAssertEqual(implementation.jsonObject() as? NSDictionary, NSDictionary())
39
+ }
40
+ }
41
+
42
+ func testValidObjectPreservesFoundationValuesAndDefaultsOnlyForNilLookup() throws {
43
+ let implementation = RNFBJSONImplementation(rawValue: try base64([
44
+ "boolean": true,
45
+ "number": 3,
46
+ "string": "value",
47
+ "array": ["one", 2],
48
+ "object": ["nested": "value"],
49
+ "null": NSNull(),
50
+ ]))
51
+
52
+ XCTAssertTrue(implementation.contains("boolean"))
53
+ XCTAssertTrue(implementation.contains("null"))
54
+ XCTAssertFalse(implementation.contains("missing"))
55
+ XCTAssertEqual(
56
+ implementation.value(forKey: "missing", defaultValue: "fallback" as NSString) as? String,
57
+ "fallback"
58
+ )
59
+ XCTAssertTrue(implementation.value(
60
+ forKey: "null",
61
+ defaultValue: "fallback" as NSString
62
+ ) is NSNull)
63
+
64
+ let parsed = implementation.jsonObject() as! NSDictionary
65
+ XCTAssertEqual(parsed["boolean"] as? Bool, true)
66
+ XCTAssertEqual(parsed["number"] as? Int, 3)
67
+ XCTAssertEqual(parsed["string"] as? String, "value")
68
+ XCTAssertEqual(parsed["array"] as? NSArray, ["one", 2] as NSArray)
69
+ XCTAssertEqual(parsed["object"] as? NSDictionary, ["nested": "value"] as NSDictionary)
70
+ }
71
+
72
+ func testLookupMatchesNSDictionaryKVCForSpecialKeys() {
73
+ let dictionary: NSDictionary = [
74
+ "count": "count value",
75
+ "@count": "at-count value",
76
+ "description": "description value",
77
+ ]
78
+ let implementation = RNFBJSONImplementation(jsonObject: dictionary)
79
+
80
+ for key in ["count", "@count", "description"] {
81
+ XCTAssertEqual(
82
+ implementation.value(forKey: key, defaultValue: nil) as? NSObject,
83
+ dictionary.value(forKey: key) as? NSObject
84
+ )
85
+ XCTAssertEqual(implementation.contains(key), dictionary.value(forKey: key) != nil)
86
+ }
87
+ }
88
+
89
+ func testValidTopLevelArrayIsPreserved() throws {
90
+ let implementation = RNFBJSONImplementation(rawValue: try base64(["one", 2]))
91
+
92
+ XCTAssertEqual(implementation.jsonObject() as? NSArray, ["one", 2] as NSArray)
93
+ }
94
+
95
+ func testParsingIsAnInitializationSnapshot() throws {
96
+ let first = RNFBJSONImplementation(rawValue: try base64(["value": "first"]))
97
+ let second = RNFBJSONImplementation(rawValue: try base64(["value": "second"]))
98
+
99
+ XCTAssertEqual(first.value(forKey: "value", defaultValue: nil) as? String, "first")
100
+ XCTAssertEqual(second.value(forKey: "value", defaultValue: nil) as? String, "second")
101
+ }
102
+
103
+ func testRawJSONPreservesLegacyDecodeBehavior() {
104
+ XCTAssertEqual(RNFBJSONImplementation.rawJSON(from: nil), "{}")
105
+ XCTAssertNil(RNFBJSONImplementation.rawJSON(from: "not base64"))
106
+
107
+ let invalidJSON = "not JSON"
108
+ XCTAssertEqual(
109
+ RNFBJSONImplementation.rawJSON(
110
+ from: Data(invalidJSON.utf8).base64EncodedString()
111
+ ),
112
+ invalidJSON
113
+ )
114
+
115
+ let invalidUTF8 = Data([0xff, 0xfe]).base64EncodedString()
116
+ XCTAssertNil(RNFBJSONImplementation.rawJSON(from: invalidUTF8))
117
+
118
+ let validJSON = #"{"value":true}"#
119
+ XCTAssertEqual(
120
+ RNFBJSONImplementation.rawJSON(
121
+ from: Data(validJSON.utf8).base64EncodedString()
122
+ ),
123
+ validJSON
124
+ )
125
+ }
126
+ }