Skip to content

Commit 7cca76b

Browse files
committed
Fixing refresh parameters mismatch bug
1 parent 5a0d207 commit 7cca76b

2 files changed

Lines changed: 191 additions & 3 deletions

File tree

GoogleSignIn/Sources/GIDEMMSupport.m

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ typedef NS_ENUM(NSInteger, ErrorCode) {
5858
ErrorCodeAppVerificationRequired,
5959
};
6060

61+
@interface GIDEMMSupport ()
62+
63+
+ (NSDictionary<NSString *, NSString *> *)
64+
dictionaryWithStringValuesFromDictionary:(NSDictionary *)originalDictionary;
65+
66+
@end
67+
6168
@implementation GIDEMMSupport
6269

6370
- (instancetype)init {
@@ -115,9 +122,11 @@ + (NSDictionary *)parametersWithParameters:(NSDictionary *)parameters
115122
#pragma mark - GTMAuthSessionDelegate
116123

117124
- (nullable NSDictionary<NSString *,NSString *> *)
118-
additionalTokenRefreshParametersForAuthSession:(GTMAuthSession *)authSession {
119-
return [GIDEMMSupport updatedEMMParametersWithParameters:
120-
authSession.authState.lastTokenResponse.additionalParameters];
125+
additionalTokenRefreshParametersForAuthSession:(GTMAuthSession *)authSession {
126+
NSDictionary *additionalParameters = authSession.authState.lastTokenResponse.additionalParameters;
127+
NSDictionary *updatedAdditionalParameters =
128+
[GIDEMMSupport updatedEMMParametersWithParameters:additionalParameters];
129+
return [GIDEMMSupport dictionaryWithStringValuesFromDictionary:updatedAdditionalParameters];
121130
}
122131

123132
- (void)updateErrorForAuthSession:(GTMAuthSession *)authSession
@@ -128,6 +137,48 @@ - (void)updateErrorForAuthSession:(GTMAuthSession *)authSession
128137
}];
129138
}
130139

140+
#pragma mark - Private Helpers
141+
142+
+ (NSDictionary<NSString *, NSString *> *)
143+
dictionaryWithStringValuesFromDictionary:(NSDictionary *)originalDictionary {
144+
NSMutableDictionary<NSString *, NSString *> *stringifiedDictionary =
145+
[NSMutableDictionary dictionaryWithCapacity:originalDictionary.count];
146+
147+
[originalDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
148+
// Case 1: The value is already of `NSString` type.
149+
if ([value isKindOfClass:[NSString class]]) {
150+
stringifiedDictionary[key] = value;
151+
return;
152+
}
153+
154+
// Case 2: The value is of `NSNumber` type (which includes `BOOL` type).
155+
if ([value isKindOfClass:[NSNumber class]]) {
156+
if (CFGetTypeID((__bridge CFTypeRef)value) == CFBooleanGetTypeID()) {
157+
stringifiedDictionary[key] = [value boolValue] ? @"true" : @"false";
158+
} else {
159+
stringifiedDictionary[key] = [value stringValue];
160+
}
161+
return;
162+
}
163+
164+
// Case 3: The value is of NSArray or NSDictionary type.
165+
// To satisfy `GTMAppAuth`'s requirement for [String: String] parameters, the entire
166+
// object is serialized into a single JSON string.
167+
if ([NSJSONSerialization isValidJSONObject:value]) {
168+
NSError *error = nil;
169+
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:value options:0 error:&error];
170+
171+
if (jsonData && !error) {
172+
stringifiedDictionary[key] = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
173+
} else {
174+
stringifiedDictionary[key] = [value description];
175+
}
176+
return;
177+
}
178+
}];
179+
return stringifiedDictionary;
180+
}
181+
131182
@end
132183

133184
NS_ASSUME_NONNULL_END

GoogleSignIn/Tests/Unit/GIDEMMSupportTest.m

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@
5959
static NSString *const kDeviceOSKey = @"device_os";
6060
static NSString *const kEMMPasscodeInfoKey = @"emm_passcode_info";
6161

62+
@interface GIDEMMSupport (Private)
63+
+ (NSDictionary<NSString *, NSString *> *)
64+
dictionaryWithStringValuesFromDictionary:(NSDictionary *)originalDictionary;
65+
@end
66+
6267
@interface GIDEMMSupportTest : XCTestCase
6368
// The view controller that has been presented, if any.
6469
@property(nonatomic, strong, nullable) UIViewController *presentedViewController;
@@ -274,6 +279,138 @@ - (void)testHandleTokenFetchEMMError_errorIsNotEMM {
274279
[self waitForExpectations:@[ called ] timeout:1];
275280
}
276281

282+
# pragma mark - String Conversion Tests
283+
284+
- (void)testStringConversion_withAnyNumber_isConvertedToString {
285+
NSDictionary *inputDictionary = @{ @"number_key": @12345 };
286+
287+
NSDictionary *resultDictionary = [GIDEMMSupport
288+
dictionaryWithStringValuesFromDictionary:inputDictionary];
289+
290+
XCTAssertTrue([resultDictionary[@"number_key"] isKindOfClass:[NSString class]]);
291+
XCTAssertEqualObjects(resultDictionary[@"number_key"], @"12345",
292+
@"The NSNumber should be converted to a string.");
293+
}
294+
295+
- (void)testStringConversion_withNumberOne_isConvertedToString {
296+
NSDictionary *inputDictionary = @{ @"number_key": @1 };
297+
298+
NSDictionary *resultDictionary = [GIDEMMSupport
299+
dictionaryWithStringValuesFromDictionary:inputDictionary];
300+
301+
XCTAssertTrue([resultDictionary[@"number_key"] isKindOfClass:[NSString class]]);
302+
XCTAssertEqualObjects(resultDictionary[@"number_key"], @"1",
303+
@"The NSNumber should be converted to a string.");
304+
}
305+
306+
- (void)testStringConversion_withNumberZero_isConvertedToString {
307+
NSDictionary *inputDictionary = @{ @"number_key": @0};
308+
309+
NSDictionary *resultDictionary = [GIDEMMSupport
310+
dictionaryWithStringValuesFromDictionary:inputDictionary];
311+
312+
XCTAssertTrue([resultDictionary[@"number_key"] isKindOfClass:[NSString class]]);
313+
XCTAssertEqualObjects(resultDictionary[@"number_key"], @"0",
314+
@"The NSNumber should be converted to a string.");
315+
}
316+
317+
- (void)testStringConversion_withBooleanYes_isConvertedToTrueString {
318+
NSDictionary *inputDictionary = @{ @"bool_key": @YES };
319+
320+
NSDictionary *resultDictionary = [GIDEMMSupport
321+
dictionaryWithStringValuesFromDictionary:inputDictionary];
322+
323+
XCTAssertTrue([resultDictionary[@"bool_key"] isKindOfClass:[NSString class]],
324+
@"The value should be an NSString.");
325+
XCTAssertEqualObjects(resultDictionary[@"bool_key"], @"true",
326+
@"The boolean YES should be converted to the string 'true'.");
327+
}
328+
329+
- (void)testStringConversion_withBooleanNo_isConvertedToFalseString {
330+
NSDictionary *inputDictionary = @{ @"bool_key": @NO };
331+
332+
NSDictionary *resultDictionary = [GIDEMMSupport
333+
dictionaryWithStringValuesFromDictionary:inputDictionary];
334+
335+
XCTAssertTrue([resultDictionary[@"bool_key"] isKindOfClass:[NSString class]],
336+
@"The value should be an NSString.");
337+
XCTAssertEqualObjects(resultDictionary[@"bool_key"], @"false",
338+
@"The boolean NO should be converted to the string 'false'.");
339+
}
340+
341+
- (void)testStringConversion_withString_remainsUnchanged {
342+
NSDictionary *inputDictionary = @{ @"string_key": @"hello" };
343+
344+
NSDictionary *resultDictionary = [GIDEMMSupport
345+
dictionaryWithStringValuesFromDictionary:inputDictionary];
346+
347+
XCTAssertTrue([resultDictionary[@"string_key"] isKindOfClass:[NSString class]],
348+
@"The value should still be an NSString.");
349+
XCTAssertEqualObjects(resultDictionary[@"string_key"], @"hello",
350+
@"The original string value should be preserved.");
351+
}
352+
353+
- (void)testStringConversion_withArray_isConvertedToJSONString {
354+
NSDictionary *inputDictionary = @{
355+
@"array_key": @[ @1, @"two", @YES ]
356+
};
357+
358+
NSDictionary *resultDictionary = [GIDEMMSupport
359+
dictionaryWithStringValuesFromDictionary:inputDictionary];
360+
361+
XCTAssertTrue([resultDictionary[@"array_key"] isKindOfClass:[NSString class]],
362+
@"The value should be an NSString.");
363+
XCTAssertEqualObjects(resultDictionary[@"array_key"], @"[1,\"two\",true]",
364+
@"The array should be serialized into a JSON string.");
365+
}
366+
367+
- (void)testStringConversion_withDictionary_isConvertedToJSONString {
368+
NSDictionary *valueAsDictionary = @{ @"nested_key": @"nested_value" };
369+
NSDictionary *inputDictionary = @{
370+
@"dict_key": @{
371+
@"nested_key": @"nested_value"
372+
}
373+
};
374+
375+
NSDictionary *resultDictionary = [GIDEMMSupport
376+
dictionaryWithStringValuesFromDictionary:inputDictionary];
377+
378+
XCTAssertTrue([resultDictionary[@"dict_key"] isKindOfClass:[NSString class]],
379+
@"The value should be an NSString.");
380+
XCTAssertEqualObjects(resultDictionary[@"dict_key"], @"{\"nested_key\":\"nested_value\"}",
381+
@"The dictionary should be serialized into a JSON string.");
382+
}
383+
384+
- (void)testStringConversion_withMixedTypes_allAreConverted {
385+
NSDictionary *inputDictionary = @{
386+
@"string_key": @"hello",
387+
@"number_key": @987,
388+
@"bool_key": @YES,
389+
@"array_key": @[ @"a", @NO ],
390+
};
391+
392+
NSDictionary *resultDictionary = [GIDEMMSupport
393+
dictionaryWithStringValuesFromDictionary:inputDictionary];
394+
395+
XCTAssertTrue([resultDictionary[@"string_key"] isKindOfClass:[NSString class]]);
396+
XCTAssertEqualObjects(resultDictionary[@"string_key"], @"hello");
397+
398+
XCTAssertTrue([resultDictionary[@"number_key"] isKindOfClass:[NSString class]]);
399+
XCTAssertEqualObjects(resultDictionary[@"number_key"], @"987");
400+
401+
XCTAssertTrue([resultDictionary[@"bool_key"] isKindOfClass:[NSString class]]);
402+
XCTAssertEqualObjects(resultDictionary[@"bool_key"], @"true");
403+
404+
XCTAssertTrue([resultDictionary[@"array_key"] isKindOfClass:[NSString class]]);
405+
XCTAssertEqualObjects(resultDictionary[@"array_key"], @"[\"a\",false]");
406+
}
407+
408+
- (void)testStringConversion_withEmptyDictionary_returnsEmptyDictionary {
409+
NSDictionary *resultDictionary = [GIDEMMSupport dictionaryWithStringValuesFromDictionary:@{}];
410+
411+
XCTAssertEqual(resultDictionary.count, 0, @"The resulting dictionary should be empty.");
412+
}
413+
277414
# pragma mark - Helpers
278415

279416
- (NSString *)systemVersion {

0 commit comments

Comments
 (0)