@react-native-firebase/auth 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 (56) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/RNFBAuth.podspec +8 -2
  3. package/android/build.gradle +5 -0
  4. package/android/src/main/java/io/invertase/firebase/auth/AuthListenerHandle.java +26 -0
  5. package/android/src/main/java/io/invertase/firebase/auth/NativeRNFBTurboAuth.java +68 -102
  6. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthCacheRegistry.kt +77 -0
  7. package/android/src/main/java/io/invertase/firebase/auth/RNFBAuthListenerRegistry.kt +76 -0
  8. package/android/src/test/java/io/invertase/firebase/auth/RNFBAuthCacheRegistryTest.java +184 -0
  9. package/android/src/test/java/io/invertase/firebase/auth/RNFBAuthListenerRegistryTest.java +171 -0
  10. package/dist/module/ActionCodeURL.js +1 -1
  11. package/dist/module/ActionCodeURL.js.map +1 -1
  12. package/dist/module/index.js +1 -2
  13. package/dist/module/index.js.map +1 -1
  14. package/dist/module/version.js +1 -1
  15. package/dist/typescript/lib/ActionCodeURL.d.ts.map +1 -1
  16. package/dist/typescript/lib/types/internal.d.ts +2 -3
  17. package/dist/typescript/lib/types/internal.d.ts.map +1 -1
  18. package/dist/typescript/lib/version.d.ts +1 -1
  19. package/ios/RNFBAuth/RNFBAuthCacheRegistry.h +41 -0
  20. package/ios/RNFBAuth/RNFBAuthCacheRegistry.m +84 -0
  21. package/ios/RNFBAuth/RNFBAuthCacheRegistryStorage.swift +53 -0
  22. package/ios/RNFBAuth/RNFBAuthErrorCodeMapper.swift +333 -0
  23. package/ios/RNFBAuth/RNFBAuthHelper.m +147 -262
  24. package/ios/RNFBAuth/RNFBAuthListenerRegistry.h +39 -0
  25. package/ios/RNFBAuth/RNFBAuthListenerRegistry.m +83 -0
  26. package/ios/RNFBAuth/RNFBAuthListenerRegistryStorage.swift +76 -0
  27. package/ios/RNFBAuth/RNFBAuthNullSentinelDecoder.h +40 -0
  28. package/ios/RNFBAuth/RNFBAuthNullSentinelDecoder.m +49 -0
  29. package/ios/RNFBAuth.xcodeproj/project.pbxproj +22 -0
  30. package/ios/RNFBAuthUnitTests/RNFBAuthCacheRegistryStorageTests.swift +72 -0
  31. package/ios/RNFBAuthUnitTests/RNFBAuthCacheRegistryTests.m +131 -0
  32. package/ios/RNFBAuthUnitTests/RNFBAuthErrorCodeMapperTests.swift +250 -0
  33. package/ios/RNFBAuthUnitTests/RNFBAuthListenerRegistryStorageTests.swift +122 -0
  34. package/ios/RNFBAuthUnitTests/RNFBAuthListenerRegistryTests.m +152 -0
  35. package/ios/RNFBAuthUnitTests/RNFBAuthNullSentinelDecodeTests.m +78 -0
  36. package/ios/RNFBAuthUnitTests/RNFBAuthUnitTests.xcodeproj/project.pbxproj +311 -0
  37. package/ios/RNFBAuthUnitTests/RNFBAuthUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBAuthUnitTests.xcscheme +69 -0
  38. package/lib/ActionCodeURL.ts +1 -2
  39. package/lib/index.ts +1 -1
  40. package/lib/types/internal.ts +2 -2
  41. package/lib/version.ts +1 -1
  42. package/package.json +5 -4
  43. package/plugin/build/index.js +4 -0
  44. package/plugin/build/ios/index.d.ts +2 -1
  45. package/plugin/build/ios/index.js +3 -1
  46. package/plugin/build/ios/openUrlFix.js +12 -0
  47. package/plugin/build/ios/sceneDelegate.d.ts +34 -0
  48. package/plugin/build/ios/sceneDelegate.js +127 -0
  49. package/plugin/build/ios/sceneLifecycle.d.ts +32 -0
  50. package/plugin/build/ios/sceneLifecycle.js +115 -0
  51. package/plugin/src/index.ts +9 -1
  52. package/plugin/src/ios/index.ts +2 -1
  53. package/plugin/src/ios/openUrlFix.ts +15 -0
  54. package/plugin/src/ios/sceneDelegate.ts +159 -0
  55. package/plugin/src/ios/sceneLifecycle.ts +134 -0
  56. package/plugin/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,83 @@
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 "RNFBAuthListenerRegistry.h"
19
+
20
+ #if __has_include("RNFBHandleMap.h")
21
+ #import "RNFBHandleMap.h"
22
+ #else
23
+ #import "RNFBApp/RNFBHandleMap.h"
24
+ #endif
25
+
26
+ #if __has_include(<RNFBAuth/RNFBAuth-Swift.h>)
27
+ #import <RNFBAuth/RNFBAuth-Swift.h>
28
+ #elif __has_include("RNFBAuth-Swift.h")
29
+ #import "RNFBAuth-Swift.h"
30
+ #elif __has_include("RNFBHandleMapStorage-Swift.inc")
31
+ #import "RNFBHandleMapStorage-Swift.inc"
32
+ #else
33
+ #error "RNFBAuthListenerRegistryStorage Swift interface not found"
34
+ #endif
35
+
36
+ @interface RNFBAuthListenerRegistry ()
37
+ @property(nonatomic, strong) RNFBAuthListenerRegistryStorage *storage;
38
+ @end
39
+
40
+ @implementation RNFBAuthListenerRegistry
41
+
42
+ - (instancetype)init {
43
+ self = [super init];
44
+ if (self) {
45
+ _storage = [[RNFBAuthListenerRegistryStorage alloc] init];
46
+ }
47
+ return self;
48
+ }
49
+
50
+ - (BOOL)put:(id)key value:(id)value error:(NSError **)error {
51
+ if (![self.storage putIfAbsent:key value:value]) {
52
+ if (error != nil) {
53
+ NSString *message = [NSString stringWithFormat:@"Handle id already registered: %@", key];
54
+ *error = [NSError errorWithDomain:RNFBHandleMapErrorDomain
55
+ code:RNFBHandleMapErrorCollision
56
+ userInfo:@{NSLocalizedDescriptionKey : message}];
57
+ }
58
+ return NO;
59
+ }
60
+ return YES;
61
+ }
62
+
63
+ - (BOOL)putOrDiscard:(id)key value:(id)value {
64
+ return [self.storage putOrDiscard:key value:value];
65
+ }
66
+
67
+ - (id)get:(id)key {
68
+ return [self.storage get:key];
69
+ }
70
+
71
+ - (id)take:(id)key {
72
+ return [self.storage take:key];
73
+ }
74
+
75
+ - (void)takeAndRemove:(id)key {
76
+ [self.storage takeAndRemove:key];
77
+ }
78
+
79
+ - (void)removeAll {
80
+ [self.storage removeAll];
81
+ }
82
+
83
+ @end
@@ -0,0 +1,76 @@
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
+
19
+ #if canImport(RNFBApp)
20
+ import RNFBApp
21
+ #endif
22
+
23
+ /// Auth-state / id-token listener map storage. Composes `RNFBHandleMapStorage`.
24
+ /// `putOrDiscard` is first-wins and calls `remove` on the incoming value on collision.
25
+ /// Unique `put` collision errors stay on the ObjC façade.
26
+ @objc(RNFBAuthListenerRegistryStorage)
27
+ public final class RNFBAuthListenerRegistryStorage: NSObject {
28
+ private static let removeSelector = Selector(("remove"))
29
+
30
+ private let storage = RNFBHandleMapStorage()
31
+
32
+ private func removeHandle(_ handle: AnyObject?) {
33
+ guard let handle = handle, handle.responds(to: Self.removeSelector) else {
34
+ return
35
+ }
36
+ _ = handle.perform(Self.removeSelector)
37
+ }
38
+
39
+ /// First-wins store without discarding the incoming value. Used by façade `put`.
40
+ @objc(putIfAbsent:value:)
41
+ public func putIfAbsent(_ key: AnyObject, value: AnyObject) -> Bool {
42
+ storage.putIfAbsent(key, value: value)
43
+ }
44
+
45
+ /// Unique put. On collision, `remove`s the incoming value and leaves the existing mapping.
46
+ @objc(putOrDiscard:value:)
47
+ public func putOrDiscard(_ key: AnyObject, value: AnyObject) -> Bool {
48
+ if storage.putIfAbsent(key, value: value) {
49
+ return true
50
+ }
51
+ removeHandle(value)
52
+ return false
53
+ }
54
+
55
+ @objc(get:)
56
+ public func get(_ key: AnyObject) -> AnyObject? {
57
+ storage.get(key)
58
+ }
59
+
60
+ @objc(take:)
61
+ public func take(_ key: AnyObject) -> AnyObject? {
62
+ storage.take(key)
63
+ }
64
+
65
+ @objc(takeAndRemove:)
66
+ public func takeAndRemove(_ key: AnyObject) {
67
+ removeHandle(storage.take(key))
68
+ }
69
+
70
+ @objc
71
+ public func removeAll() {
72
+ for handle in storage.takeAll() {
73
+ removeHandle(handle)
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,40 @@
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 <Foundation/Foundation.h>
19
+
20
+ /**
21
+ * Decodes New Architecture null sentinels for updateProfile. Foundation only so unit tests can
22
+ * compile it without the Firebase SDK.
23
+ */
24
+ @interface RNFBAuthNullSentinelDecoder : NSObject
25
+
26
+ /**
27
+ * Decode sentinels and turn NSNull into nil before profileChangeRequest writes.
28
+ * FIRUserProfileChangeRequest clears a field when the property is set to nil (not the same as
29
+ * leaving it unassigned). NSDictionary cannot store nil, so cleared keys are omitted and
30
+ * subscript returns nil, the same value updateProfile reads.
31
+ * displayName/photoURL null arrive as { __rnfbNull: true } and/or NSNull after decode.
32
+ */
33
+ + (NSDictionary *)decodedProfileProps:(NSDictionary *)props;
34
+
35
+ /**
36
+ * photoURL clear arm: omitted/nil decoded value must become nil (not @""), not URLWithString:.
37
+ */
38
+ + (NSURL *)photoURLFromDecodedValue:(id)value;
39
+
40
+ @end
@@ -0,0 +1,49 @@
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 "RNFBAuthNullSentinelDecoder.h"
19
+
20
+ #if __has_include(<RNFBApp/RNFBApp-Swift.h>)
21
+ #import <RNFBApp/RNFBApp-Swift.h>
22
+ #elif __has_include("RNFBApp-Swift.h")
23
+ #import "RNFBApp-Swift.h"
24
+ #elif __has_include("RNFBHandleMapStorage-Swift.inc")
25
+ #import "RNFBHandleMapStorage-Swift.inc"
26
+ #else
27
+ #error "RNFBApp Swift interface not found"
28
+ #endif
29
+
30
+ @implementation RNFBAuthNullSentinelDecoder
31
+
32
+ + (NSDictionary *)decodedProfileProps:(NSDictionary *)props {
33
+ NSDictionary *decoded = [RNFBNullSentinelDecoder decodeNullSentinels:props];
34
+ NSMutableDictionary *normalized = [NSMutableDictionary dictionaryWithCapacity:decoded.count];
35
+ for (NSString *key in decoded) {
36
+ id value = decoded[key];
37
+ if (value == [NSNull null]) {
38
+ continue;
39
+ }
40
+ normalized[key] = value;
41
+ }
42
+ return normalized;
43
+ }
44
+
45
+ + (NSURL *)photoURLFromDecodedValue:(id)value {
46
+ return value == nil ? nil : [NSURL URLWithString:value];
47
+ }
48
+
49
+ @end
@@ -8,6 +8,10 @@
8
8
 
9
9
  /* Begin PBXBuildFile section */
10
10
  2744B98621F45429004F8E3F /* RNFBAuthModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBAuthModule.mm */; };
11
+ RNFBAUTH0000000000000001 /* RNFBAuthCacheRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = RNFBAUTH0000000000000002 /* RNFBAuthCacheRegistry.m */; };
12
+ RNFBAUTH0000000000000003 /* RNFBAuthCacheRegistryStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = RNFBAUTH0000000000000004 /* RNFBAuthCacheRegistryStorage.swift */; };
13
+ RNFBAUTH0000000000000008 /* RNFBAuthListenerRegistryStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = RNFBAUTH0000000000000009 /* RNFBAuthListenerRegistryStorage.swift */; };
14
+ RNFBAUTH000000000000000A /* RNFBAuthErrorCodeMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = RNFBAUTH000000000000000B /* RNFBAuthErrorCodeMapper.swift */; };
11
15
  /* End PBXBuildFile section */
12
16
 
13
17
  /* Begin PBXCopyFilesBuildPhase section */
@@ -26,6 +30,11 @@
26
30
  2744B98221F45429004F8E3F /* libRNFBAuth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBAuth.a; sourceTree = BUILT_PRODUCTS_DIR; };
27
31
  2744B98421F45429004F8E3F /* RNFBAuthModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAuthModule.h; path = RNFBAuth/RNFBAuthModule.h; sourceTree = SOURCE_ROOT; };
28
32
  2744B98521F45429004F8E3F /* RNFBAuthModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = RNFBAuthModule.mm; path = RNFBAuth/RNFBAuthModule.mm; sourceTree = SOURCE_ROOT; };
33
+ RNFBAUTH0000000000000005 /* RNFBAuthCacheRegistry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAuthCacheRegistry.h; path = RNFBAuth/RNFBAuthCacheRegistry.h; sourceTree = SOURCE_ROOT; };
34
+ RNFBAUTH0000000000000002 /* RNFBAuthCacheRegistry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBAuthCacheRegistry.m; path = RNFBAuth/RNFBAuthCacheRegistry.m; sourceTree = SOURCE_ROOT; };
35
+ RNFBAUTH0000000000000004 /* RNFBAuthCacheRegistryStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAuthCacheRegistryStorage.swift; path = RNFBAuth/RNFBAuthCacheRegistryStorage.swift; sourceTree = SOURCE_ROOT; };
36
+ RNFBAUTH0000000000000009 /* RNFBAuthListenerRegistryStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAuthListenerRegistryStorage.swift; path = RNFBAuth/RNFBAuthListenerRegistryStorage.swift; sourceTree = SOURCE_ROOT; };
37
+ RNFBAUTH000000000000000B /* RNFBAuthErrorCodeMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAuthErrorCodeMapper.swift; path = RNFBAuth/RNFBAuthErrorCodeMapper.swift; sourceTree = SOURCE_ROOT; };
29
38
  /* End PBXFileReference section */
30
39
 
31
40
  /* Begin PBXFrameworksBuildPhase section */
@@ -52,6 +61,11 @@
52
61
  children = (
53
62
  2744B9A121F48736004F8E3F /* converters */,
54
63
  2744B98C21F45C64004F8E3F /* common */,
64
+ RNFBAUTH0000000000000005 /* RNFBAuthCacheRegistry.h */,
65
+ RNFBAUTH0000000000000002 /* RNFBAuthCacheRegistry.m */,
66
+ RNFBAUTH0000000000000004 /* RNFBAuthCacheRegistryStorage.swift */,
67
+ RNFBAUTH0000000000000009 /* RNFBAuthListenerRegistryStorage.swift */,
68
+ RNFBAUTH000000000000000B /* RNFBAuthErrorCodeMapper.swift */,
55
69
  2744B98421F45429004F8E3F /* RNFBAuthModule.h */,
56
70
  2744B98521F45429004F8E3F /* RNFBAuthModule.mm */,
57
71
  );
@@ -124,6 +138,10 @@
124
138
  isa = PBXSourcesBuildPhase;
125
139
  buildActionMask = 2147483647;
126
140
  files = (
141
+ RNFBAUTH0000000000000003 /* RNFBAuthCacheRegistryStorage.swift in Sources */,
142
+ RNFBAUTH0000000000000001 /* RNFBAuthCacheRegistry.m in Sources */,
143
+ RNFBAUTH0000000000000008 /* RNFBAuthListenerRegistryStorage.swift in Sources */,
144
+ RNFBAUTH000000000000000A /* RNFBAuthErrorCodeMapper.swift in Sources */,
127
145
  2744B98621F45429004F8E3F /* RNFBAuthModule.mm in Sources */,
128
146
  );
129
147
  runOnlyForDeploymentPostprocessing = 0;
@@ -150,6 +168,7 @@
150
168
  CODE_SIGN_STYLE = Automatic;
151
169
  COPY_PHASE_STRIP = NO;
152
170
  DEBUG_INFORMATION_FORMAT = dwarf;
171
+ DEFINES_MODULE = YES;
153
172
  GCC_C_LANGUAGE_STANDARD = gnu11;
154
173
  GCC_DYNAMIC_NO_PIC = NO;
155
174
  GCC_OPTIMIZATION_LEVEL = 0;
@@ -166,6 +185,7 @@
166
185
  PRODUCT_NAME = "$(TARGET_NAME)";
167
186
  SDKROOT = iphoneos;
168
187
  SKIP_INSTALL = YES;
188
+ SWIFT_VERSION = 5.10;
169
189
  TARGETED_DEVICE_FAMILY = "1,2";
170
190
  };
171
191
  name = Debug;
@@ -189,6 +209,7 @@
189
209
  CODE_SIGN_STYLE = Automatic;
190
210
  COPY_PHASE_STRIP = NO;
191
211
  DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
212
+ DEFINES_MODULE = YES;
192
213
  ENABLE_NS_ASSERTIONS = NO;
193
214
  GCC_C_LANGUAGE_STANDARD = gnu11;
194
215
  GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
@@ -200,6 +221,7 @@
200
221
  PRODUCT_NAME = "$(TARGET_NAME)";
201
222
  SDKROOT = iphoneos;
202
223
  SKIP_INSTALL = YES;
224
+ SWIFT_VERSION = 5.10;
203
225
  TARGETED_DEVICE_FAMILY = "1,2";
204
226
  VALIDATE_PRODUCT = YES;
205
227
  };
@@ -0,0 +1,72 @@
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 XCTest
18
+
19
+ final class RNFBAuthCacheRegistryStorageTests: XCTestCase {
20
+ private var storage: RNFBAuthCacheRegistryStorage!
21
+
22
+ override func setUp() {
23
+ super.setUp()
24
+ storage = RNFBAuthCacheRegistryStorage()
25
+ }
26
+
27
+ func testPutOrDiscard_storesWhenFree() {
28
+ XCTAssertTrue(storage.putOrDiscard("k1" as NSString, value: "payload" as NSString))
29
+ XCTAssertEqual(storage.get("k1" as NSString) as? NSString, "payload")
30
+ }
31
+
32
+ func testPutOrDiscard_collision_keepsExisting() {
33
+ XCTAssertTrue(storage.putOrDiscard("k1" as NSString, value: "first" as NSString))
34
+ XCTAssertFalse(storage.putOrDiscard("k1" as NSString, value: "second" as NSString))
35
+ XCTAssertEqual(storage.get("k1" as NSString) as? NSString, "first")
36
+ }
37
+
38
+ func testPutReplacing_whenFree_returnsNil() {
39
+ XCTAssertNil(storage.putReplacing("k1" as NSString, value: "payload" as NSString))
40
+ XCTAssertEqual(storage.get("k1" as NSString) as? NSString, "payload")
41
+ }
42
+
43
+ func testPutReplacing_whenOccupied_returnsDisplaced() {
44
+ XCTAssertTrue(storage.putOrDiscard("k1" as NSString, value: "first" as NSString))
45
+ let displaced = storage.putReplacing("k1" as NSString, value: "second" as NSString)
46
+ XCTAssertEqual(displaced as? NSString, "first")
47
+ XCTAssertEqual(storage.get("k1" as NSString) as? NSString, "second")
48
+ }
49
+
50
+ func testGet_whenFree_isNil() {
51
+ XCTAssertNil(storage.get("missing" as NSString))
52
+ }
53
+
54
+ func testTake_removesAndReturns() {
55
+ XCTAssertTrue(storage.putOrDiscard("k1" as NSString, value: "payload" as NSString))
56
+ XCTAssertEqual(storage.take("k1" as NSString) as? NSString, "payload")
57
+ XCTAssertNil(storage.get("k1" as NSString))
58
+ }
59
+
60
+ func testTake_whenFree_isNil() {
61
+ XCTAssertNil(storage.take("missing" as NSString))
62
+ }
63
+
64
+ func testTakeAll_returnsSnapshotAndLeavesEmpty() {
65
+ XCTAssertTrue(storage.putOrDiscard("a" as NSString, value: "1" as NSString))
66
+ XCTAssertTrue(storage.putOrDiscard("b" as NSString, value: "2" as NSString))
67
+ let remaining = storage.takeAll()
68
+ XCTAssertEqual(remaining.count, 2)
69
+ XCTAssertNil(storage.get("a" as NSString))
70
+ XCTAssertNil(storage.get("b" as NSString))
71
+ }
72
+ }
@@ -0,0 +1,131 @@
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 "RNFBAuthCacheRegistry.h"
21
+ #import "RNFBHandleMap.h"
22
+
23
+ @interface RNFBAuthCacheRegistryTests : XCTestCase
24
+ @property(nonatomic, strong) RNFBAuthCacheRegistry *registry;
25
+ @end
26
+
27
+ @implementation RNFBAuthCacheRegistryTests
28
+
29
+ - (void)setUp {
30
+ [super setUp];
31
+ self.registry = [[RNFBAuthCacheRegistry alloc] init];
32
+ }
33
+
34
+ - (void)testPutGetTake_happyPath {
35
+ NSError *error = nil;
36
+ XCTAssertTrue([self.registry put:@"k1" value:@"payload" error:&error]);
37
+ XCTAssertNil(error);
38
+ XCTAssertEqualObjects(@"payload", [self.registry get:@"k1"]);
39
+ XCTAssertEqualObjects(@"payload", [self.registry take:@"k1"]);
40
+ XCTAssertNil([self.registry get:@"k1"]);
41
+ }
42
+
43
+ - (void)testPut_occupiedId_returnsCollision {
44
+ XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
45
+
46
+ NSError *error = nil;
47
+ XCTAssertFalse([self.registry put:@"k1" value:@"second" error:&error]);
48
+ XCTAssertNotNil(error);
49
+ XCTAssertEqualObjects(error.domain, RNFBHandleMapErrorDomain);
50
+ XCTAssertEqual(error.code, RNFBHandleMapErrorCollision);
51
+ XCTAssertEqualObjects(@"first", [self.registry get:@"k1"]);
52
+ }
53
+
54
+ - (void)testPut_occupiedId_nilErrorOut_returnsNo {
55
+ XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
56
+ XCTAssertFalse([self.registry put:@"k1" value:@"second" error:nil]);
57
+ XCTAssertEqualObjects(@"first", [self.registry get:@"k1"]);
58
+ }
59
+
60
+ - (void)testGet_whenFree_isNil {
61
+ XCTAssertNil([self.registry get:@"missing"]);
62
+ }
63
+
64
+ - (void)testTake_whenFree_isNil {
65
+ XCTAssertNil([self.registry take:@"missing"]);
66
+ }
67
+
68
+ - (void)testPutOrDiscard_storesWhenFree {
69
+ XCTAssertTrue([self.registry putOrDiscard:@"k1" value:@"payload"]);
70
+ XCTAssertEqualObjects(@"payload", [self.registry get:@"k1"]);
71
+ }
72
+
73
+ - (void)testPutOrDiscard_collision_keepsExisting {
74
+ XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
75
+ XCTAssertFalse([self.registry putOrDiscard:@"k1" value:@"second"]);
76
+ XCTAssertEqualObjects(@"first", [self.registry get:@"k1"]);
77
+ }
78
+
79
+ - (void)testPutReplacing_whenFree_stores {
80
+ XCTAssertTrue([self.registry putReplacing:@"k1" value:@"payload"]);
81
+ XCTAssertEqualObjects(@"payload", [self.registry get:@"k1"]);
82
+ }
83
+
84
+ - (void)testPutReplacing_whenOccupied_replacesLastWins {
85
+ XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
86
+ XCTAssertTrue([self.registry putReplacing:@"k1" value:@"second"]);
87
+ XCTAssertEqualObjects(@"second", [self.registry get:@"k1"]);
88
+ }
89
+
90
+ - (void)testPutReplacing_sameIdFromTwoThreads_lastWins {
91
+ XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
92
+
93
+ dispatch_group_t group = dispatch_group_create();
94
+ dispatch_group_enter(group);
95
+ dispatch_group_enter(group);
96
+
97
+ dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
98
+ [self.registry putReplacing:@"k1" value:@"second"];
99
+ dispatch_group_leave(group);
100
+ });
101
+ dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
102
+ [self.registry putReplacing:@"k1" value:@"third"];
103
+ dispatch_group_leave(group);
104
+ });
105
+
106
+ dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
107
+ id stored = [self.registry get:@"k1"];
108
+ XCTAssertTrue([stored isEqual:@"second"] || [stored isEqual:@"third"]);
109
+ }
110
+
111
+ - (void)testPut_afterTake_allowsReuse {
112
+ XCTAssertTrue([self.registry put:@"k1" value:@"first" error:nil]);
113
+ XCTAssertEqualObjects(@"first", [self.registry take:@"k1"]);
114
+ XCTAssertTrue([self.registry put:@"k1" value:@"second" error:nil]);
115
+ XCTAssertEqualObjects(@"second", [self.registry get:@"k1"]);
116
+ }
117
+
118
+ - (void)testClear_removesAll {
119
+ XCTAssertTrue([self.registry put:@"a" value:@"1" error:nil]);
120
+ XCTAssertTrue([self.registry put:@"b" value:@"2" error:nil]);
121
+ [self.registry clear];
122
+ XCTAssertNil([self.registry get:@"a"]);
123
+ XCTAssertNil([self.registry get:@"b"]);
124
+ }
125
+
126
+ - (void)testClear_empty_isNoOp {
127
+ [self.registry clear];
128
+ XCTAssertNil([self.registry get:@"k1"]);
129
+ }
130
+
131
+ @end