From 4053621ad8164bca58f458b2d441669b1d7ddcb4 Mon Sep 17 00:00:00 2001 From: Jessy Naus Date: Tue, 1 Apr 2025 16:25:14 +0200 Subject: [PATCH] Update the Accept-Language header values to include all languages --- SPTDataLoader.xcodeproj/project.pbxproj | 12 ++-- Sources/SPTDataLoader/SPTDataLoaderRequest.m | 35 +++-------- .../SPTDataLoader/SPTDataLoaderRequestTest.m | 58 +++---------------- Tests/SPTDataLoader/Utilities/NSBundleMock.h | 12 ---- Tests/SPTDataLoader/Utilities/NSBundleMock.m | 15 ----- Tests/SPTDataLoader/Utilities/NSLocaleMock.h | 12 ++++ Tests/SPTDataLoader/Utilities/NSLocaleMock.m | 21 +++++++ 7 files changed, 55 insertions(+), 110 deletions(-) delete mode 100644 Tests/SPTDataLoader/Utilities/NSBundleMock.h delete mode 100644 Tests/SPTDataLoader/Utilities/NSBundleMock.m create mode 100644 Tests/SPTDataLoader/Utilities/NSLocaleMock.h create mode 100644 Tests/SPTDataLoader/Utilities/NSLocaleMock.m diff --git a/SPTDataLoader.xcodeproj/project.pbxproj b/SPTDataLoader.xcodeproj/project.pbxproj index 07e8b91..1dcbd39 100644 --- a/SPTDataLoader.xcodeproj/project.pbxproj +++ b/SPTDataLoader.xcodeproj/project.pbxproj @@ -43,7 +43,7 @@ 059940A91A150C90006D6BE9 /* SPTDataLoaderResponseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 059940A81A150C90006D6BE9 /* SPTDataLoaderResponseTest.m */; }; 05A3BCB61D649CC000735F87 /* SPTDataLoaderCancellationTokenFactoryMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 05A3BCB51D649CC000735F87 /* SPTDataLoaderCancellationTokenFactoryMock.m */; }; 05CB0C451A1A1E8A00CA4CEF /* SPTDataLoaderRequestTaskHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 05CB0C441A1A1E8A00CA4CEF /* SPTDataLoaderRequestTaskHandler.m */; }; - 05EEB73F1C5C090B00A82266 /* NSBundleMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 05EEB73E1C5C090B00A82266 /* NSBundleMock.m */; }; + 05EEB73F1C5C090B00A82266 /* NSLocaleMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 05EEB73E1C5C090B00A82266 /* NSLocaleMock.m */; }; 2DE3DAC72344E3DA0022642E /* SPTDataLoaderServiceSessionSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DE3DAC42344E3DA0022642E /* SPTDataLoaderServiceSessionSelector.m */; }; 2DE3DACA2344E5060022642E /* SPTDataLoaderServiceSessionSelectorMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DE3DAC92344E5060022642E /* SPTDataLoaderServiceSessionSelectorMock.m */; }; 3426C1ED24CB1C7B00B919B4 /* SPTDataLoaderBlockWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3426C1EC24CB1C7B00B919B4 /* SPTDataLoaderBlockWrapper.m */; }; @@ -196,8 +196,8 @@ 05C602FC1CCBBC5E00143BA4 /* spotify_os.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = spotify_os.xcconfig; path = ci/spotify_os.xcconfig; sourceTree = ""; }; 05CB0C431A1A1E8A00CA4CEF /* SPTDataLoaderRequestTaskHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPTDataLoaderRequestTaskHandler.h; sourceTree = ""; }; 05CB0C441A1A1E8A00CA4CEF /* SPTDataLoaderRequestTaskHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPTDataLoaderRequestTaskHandler.m; sourceTree = ""; }; - 05EEB73D1C5C090B00A82266 /* NSBundleMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSBundleMock.h; sourceTree = ""; }; - 05EEB73E1C5C090B00A82266 /* NSBundleMock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBundleMock.m; sourceTree = ""; }; + 05EEB73D1C5C090B00A82266 /* NSLocaleMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSLocaleMock.h; sourceTree = ""; }; + 05EEB73E1C5C090B00A82266 /* NSLocaleMock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSLocaleMock.m; sourceTree = ""; }; 2DE3DAC42344E3DA0022642E /* SPTDataLoaderServiceSessionSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPTDataLoaderServiceSessionSelector.m; sourceTree = ""; }; 2DE3DAC52344E3DA0022642E /* SPTDataLoaderServiceSessionSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPTDataLoaderServiceSessionSelector.h; sourceTree = ""; }; 2DE3DAC62344E3DA0022642E /* SPTDataLoaderService+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SPTDataLoaderService+Private.h"; sourceTree = ""; }; @@ -496,8 +496,8 @@ F5F63D9D2531320F000A07D1 /* Utilities */ = { isa = PBXGroup; children = ( - 05EEB73D1C5C090B00A82266 /* NSBundleMock.h */, - 05EEB73E1C5C090B00A82266 /* NSBundleMock.m */, + 05EEB73D1C5C090B00A82266 /* NSLocaleMock.h */, + 05EEB73E1C5C090B00A82266 /* NSLocaleMock.m */, 48E7EEC42059288E00BB7CCC /* NSDataMock.h */, 48E7EEC52059288F00BB7CCC /* NSDataMock.m */, 48E7EEC220591A2E00BB7CCC /* NSFileManagerMock.h */, @@ -714,7 +714,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 05EEB73F1C5C090B00A82266 /* NSBundleMock.m in Sources */, + 05EEB73F1C5C090B00A82266 /* NSLocaleMock.m in Sources */, 059940431A14BA28006D6BE9 /* SPTDataLoaderRequestResponseHandlerMock.m in Sources */, 48E7EEC62059288F00BB7CCC /* NSDataMock.m in Sources */, 0599409F1A14F60F006D6BE9 /* SPTDataLoaderTest.m in Sources */, diff --git a/Sources/SPTDataLoader/SPTDataLoaderRequest.m b/Sources/SPTDataLoader/SPTDataLoaderRequest.m index 37b7e30..16fab2d 100644 --- a/Sources/SPTDataLoader/SPTDataLoaderRequest.m +++ b/Sources/SPTDataLoader/SPTDataLoaderRequest.m @@ -129,8 +129,6 @@ + (NSString *)languageHeaderValue + (NSString *)generateLanguageHeaderValue { - const NSInteger SPTDataLoaderRequestMaximumLanguages = 2; - NSString * const SPTDataLoaderRequestEnglishLanguageValue = @"en"; NSString * const SPTDataLoaderRequestLanguageHeaderValuesJoiner = @", "; NSString *(^constructLanguageHeaderValue)(NSString *, double) = ^NSString *(NSString *language, double languageImportance) { @@ -138,34 +136,15 @@ + (NSString *)generateLanguageHeaderValue return [NSString stringWithFormat:SPTDataLoaderRequestLanguageFormatString, language, languageImportance]; }; - NSArray *localizations = [NSBundle mainBundle].preferredLocalizations; - NSMutableOrderedSet *languages = [NSMutableOrderedSet orderedSetWithArray:localizations]; - if (languages.count > SPTDataLoaderRequestMaximumLanguages) { - const NSUInteger excess = languages.count - SPTDataLoaderRequestMaximumLanguages; - [languages removeObjectsInRange:NSMakeRange(SPTDataLoaderRequestMaximumLanguages, excess)]; - } - double languageImportanceCounter = 1.0; + NSArray *languages = [NSLocale preferredLanguages]; + NSMutableArray *languageHeaderValues = [NSMutableArray arrayWithCapacity:languages.count]; - BOOL containsEnglish = NO; - for (NSString *language in languages) { - if (!containsEnglish) { - NSString * const SPTDataLoaderRequestLanguageLocaleSeparator = @"-"; - NSString *languageValue = [language componentsSeparatedByString:SPTDataLoaderRequestLanguageLocaleSeparator].firstObject; - if ([languageValue isEqualToString:SPTDataLoaderRequestEnglishLanguageValue]) { - containsEnglish = YES; - } - } - if (languageImportanceCounter == 1.0) { - [languageHeaderValues addObject:language]; - } else { - [languageHeaderValues addObject:constructLanguageHeaderValue(language, languageImportanceCounter)]; - } - languageImportanceCounter -= (1.0 / languages.count); - } - if (!containsEnglish) { - [languageHeaderValues addObject:constructLanguageHeaderValue(SPTDataLoaderRequestEnglishLanguageValue, 0.01)]; - } + [languages enumerateObjectsUsingBlock:^(NSString *language, NSUInteger idx, BOOL *stop) { + const double languageImportance = 1.0 - idx * (1.0 / languages.count); + [languageHeaderValues addObject:constructLanguageHeaderValue(language, languageImportance)]; + }]; + return [languageHeaderValues componentsJoinedByString:SPTDataLoaderRequestLanguageHeaderValuesJoiner]; } diff --git a/Tests/SPTDataLoader/SPTDataLoaderRequestTest.m b/Tests/SPTDataLoader/SPTDataLoaderRequestTest.m index 25e1d6d..a74211d 100644 --- a/Tests/SPTDataLoader/SPTDataLoaderRequestTest.m +++ b/Tests/SPTDataLoader/SPTDataLoaderRequestTest.m @@ -7,7 +7,7 @@ #import #import "SPTDataLoaderRequest+Private.h" -#import "NSBundleMock.h" +#import "NSLocaleMock.h" @interface SPTDataLoaderRequest () @@ -140,24 +140,24 @@ - (void)testCopy XCTAssertEqual(request.shouldStopRedirection, self.request.shouldStopRedirection, @"The stop redirection was not copied correctly"); } -- (void)testAcceptLanguageWithNoEnglishLanguages +- (void)testAcceptLanguage { - NSBundleMock *bundleMock = [NSBundleMock new]; - bundleMock.mockPreferredLocalizations = @[ @"fr-CA", @"pt-PT", @"es-419" ]; + // When the language identifier does not contain a region designator, NSLocale uses the user's preferred region. + [NSLocaleMock setPreferredLanguages:@[ @"en-US", @"fr-SE", @"ja-SE", @"sv-SE", @"mk-SE", @"nl-SE" ]]; + + Method originalMethod = class_getClassMethod(NSLocale.class, @selector(preferredLanguages)); + Method fakeMethod = class_getClassMethod(NSLocaleMock.class, @selector(preferredLanguages)); - Method originalMethod = class_getClassMethod(NSBundle.class, @selector(mainBundle)); IMP originalMethodImplementation = method_getImplementation(originalMethod); + IMP fakeMethodImplementation = method_getImplementation(fakeMethod); - IMP fakeMethodImplementation = imp_implementationWithBlock(^ { - return bundleMock; - }); method_setImplementation(originalMethod, fakeMethodImplementation); NSString *languageValues = [SPTDataLoaderRequest generateLanguageHeaderValue]; method_setImplementation(originalMethod, originalMethodImplementation); - XCTAssertEqualObjects(@"fr-CA, pt-PT;q=0.50, en;q=0.01", languageValues); + XCTAssertEqualObjects(@"en-US;q=1.00, fr-SE;q=0.83, ja-SE;q=0.67, sv-SE;q=0.50, mk-SE;q=0.33, nl-SE;q=0.17", languageValues); } - (void)testDescription @@ -170,46 +170,6 @@ - (void)testDescription @"The description should contain the URL of the request."); } -- (void)testAcceptLanguageWithMultipleLanguagesContainingEnglish -{ - NSBundleMock *bundleMock = [NSBundleMock new]; - bundleMock.mockPreferredLocalizations = @[ @"fr-CA", @"en", @"pt-PT" ]; - - Method originalMethod = class_getClassMethod(NSBundle.class, @selector(mainBundle)); - IMP originalMethodImplementation = method_getImplementation(originalMethod); - - IMP fakeMethodImplementation = imp_implementationWithBlock(^ { - return bundleMock; - }); - method_setImplementation(originalMethod, fakeMethodImplementation); - - NSString *languageValues = [SPTDataLoaderRequest generateLanguageHeaderValue]; - - method_setImplementation(originalMethod, originalMethodImplementation); - - XCTAssertEqualObjects(@"fr-CA, en;q=0.50", languageValues); -} - -- (void)testAcceptLanguageRemovesDuplicateLocalizations -{ - NSBundleMock *bundleMock = [NSBundleMock new]; - bundleMock.mockPreferredLocalizations = @[ @"es-419", @"es-419", @"pt-PT" ]; - - Method originalMethod = class_getClassMethod(NSBundle.class, @selector(mainBundle)); - IMP originalMethodImplementation = method_getImplementation(originalMethod); - - IMP fakeMethodImplementation = imp_implementationWithBlock(^ { - return bundleMock; - }); - method_setImplementation(originalMethod, fakeMethodImplementation); - - NSString *languageValues = [SPTDataLoaderRequest generateLanguageHeaderValue]; - - method_setImplementation(originalMethod, originalMethodImplementation); - - XCTAssertEqualObjects(@"es-419, pt-PT;q=0.50, en;q=0.01", languageValues); -} - - (void)testDeleteMethod { self.request.method = SPTDataLoaderRequestMethodDelete; diff --git a/Tests/SPTDataLoader/Utilities/NSBundleMock.h b/Tests/SPTDataLoader/Utilities/NSBundleMock.h deleted file mode 100644 index 4195015..0000000 --- a/Tests/SPTDataLoader/Utilities/NSBundleMock.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - Copyright Spotify AB. - SPDX-License-Identifier: Apache-2.0 - */ - -#import - -@interface NSBundleMock : NSBundle - -@property (readwrite, copy, atomic) NSArray *mockPreferredLocalizations; - -@end diff --git a/Tests/SPTDataLoader/Utilities/NSBundleMock.m b/Tests/SPTDataLoader/Utilities/NSBundleMock.m deleted file mode 100644 index 4d27485..0000000 --- a/Tests/SPTDataLoader/Utilities/NSBundleMock.m +++ /dev/null @@ -1,15 +0,0 @@ -/* - Copyright Spotify AB. - SPDX-License-Identifier: Apache-2.0 - */ - -#import "NSBundleMock.h" - -@implementation NSBundleMock - -- (NSArray *)preferredLocalizations -{ - return self.mockPreferredLocalizations; -} - -@end diff --git a/Tests/SPTDataLoader/Utilities/NSLocaleMock.h b/Tests/SPTDataLoader/Utilities/NSLocaleMock.h new file mode 100644 index 0000000..1a69a3c --- /dev/null +++ b/Tests/SPTDataLoader/Utilities/NSLocaleMock.h @@ -0,0 +1,12 @@ +/* + Copyright Spotify AB. + SPDX-License-Identifier: Apache-2.0 + */ + +#import + +@interface NSLocaleMock : NSLocale + ++ (void)setPreferredLanguages:(NSArray *)languages; + +@end diff --git a/Tests/SPTDataLoader/Utilities/NSLocaleMock.m b/Tests/SPTDataLoader/Utilities/NSLocaleMock.m new file mode 100644 index 0000000..0e0fd0d --- /dev/null +++ b/Tests/SPTDataLoader/Utilities/NSLocaleMock.m @@ -0,0 +1,21 @@ +/* + Copyright Spotify AB. + SPDX-License-Identifier: Apache-2.0 + */ + +#import "NSLocaleMock.h" + +@implementation NSLocaleMock + +static NSArray *_mockPreferredLanguages; + ++ (NSArray *)preferredLanguages { + return _mockPreferredLanguages; +} + ++ (void)setPreferredLanguages:(NSArray *)languages +{ + _mockPreferredLanguages = languages; +} + +@end