Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update the Accept-Language header values to include all languages #242

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions SPTDataLoader.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -196,8 +196,8 @@
05C602FC1CCBBC5E00143BA4 /* spotify_os.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = spotify_os.xcconfig; path = ci/spotify_os.xcconfig; sourceTree = "<group>"; };
05CB0C431A1A1E8A00CA4CEF /* SPTDataLoaderRequestTaskHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPTDataLoaderRequestTaskHandler.h; sourceTree = "<group>"; };
05CB0C441A1A1E8A00CA4CEF /* SPTDataLoaderRequestTaskHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPTDataLoaderRequestTaskHandler.m; sourceTree = "<group>"; };
05EEB73D1C5C090B00A82266 /* NSBundleMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSBundleMock.h; sourceTree = "<group>"; };
05EEB73E1C5C090B00A82266 /* NSBundleMock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBundleMock.m; sourceTree = "<group>"; };
05EEB73D1C5C090B00A82266 /* NSLocaleMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSLocaleMock.h; sourceTree = "<group>"; };
05EEB73E1C5C090B00A82266 /* NSLocaleMock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSLocaleMock.m; sourceTree = "<group>"; };
2DE3DAC42344E3DA0022642E /* SPTDataLoaderServiceSessionSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPTDataLoaderServiceSessionSelector.m; sourceTree = "<group>"; };
2DE3DAC52344E3DA0022642E /* SPTDataLoaderServiceSessionSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPTDataLoaderServiceSessionSelector.h; sourceTree = "<group>"; };
2DE3DAC62344E3DA0022642E /* SPTDataLoaderService+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SPTDataLoaderService+Private.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down
35 changes: 7 additions & 28 deletions Sources/SPTDataLoader/SPTDataLoaderRequest.m
Original file line number Diff line number Diff line change
Expand Up @@ -129,43 +129,22 @@ + (NSString *)languageHeaderValue

+ (NSString *)generateLanguageHeaderValue
{
const NSInteger SPTDataLoaderRequestMaximumLanguages = 2;
NSString * const SPTDataLoaderRequestEnglishLanguageValue = @"en";
NSString * const SPTDataLoaderRequestLanguageHeaderValuesJoiner = @", ";

NSString *(^constructLanguageHeaderValue)(NSString *, double) = ^NSString *(NSString *language, double languageImportance) {
NSString * const SPTDataLoaderRequestLanguageFormatString = @"%@;q=%.2f";
return [NSString stringWithFormat:SPTDataLoaderRequestLanguageFormatString, language, languageImportance];
};

NSArray<NSString *> *localizations = [NSBundle mainBundle].preferredLocalizations;
NSMutableOrderedSet<NSString *> *languages = [NSMutableOrderedSet orderedSetWithArray:localizations];
if (languages.count > SPTDataLoaderRequestMaximumLanguages) {
const NSUInteger excess = languages.count - SPTDataLoaderRequestMaximumLanguages;
[languages removeObjectsInRange:NSMakeRange(SPTDataLoaderRequestMaximumLanguages, excess)];
}
double languageImportanceCounter = 1.0;
NSArray<NSString *> *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];
}

Expand Down
58 changes: 9 additions & 49 deletions Tests/SPTDataLoader/SPTDataLoaderRequestTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#import <objc/runtime.h>

#import "SPTDataLoaderRequest+Private.h"
#import "NSBundleMock.h"
#import "NSLocaleMock.h"

@interface SPTDataLoaderRequest ()

Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down
12 changes: 0 additions & 12 deletions Tests/SPTDataLoader/Utilities/NSBundleMock.h

This file was deleted.

15 changes: 0 additions & 15 deletions Tests/SPTDataLoader/Utilities/NSBundleMock.m

This file was deleted.

12 changes: 12 additions & 0 deletions Tests/SPTDataLoader/Utilities/NSLocaleMock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
Copyright Spotify AB.
SPDX-License-Identifier: Apache-2.0
*/

#import <Foundation/Foundation.h>

@interface NSLocaleMock : NSLocale

+ (void)setPreferredLanguages:(NSArray<NSString *> *)languages;

@end
21 changes: 21 additions & 0 deletions Tests/SPTDataLoader/Utilities/NSLocaleMock.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Copyright Spotify AB.
SPDX-License-Identifier: Apache-2.0
*/

#import "NSLocaleMock.h"

@implementation NSLocaleMock

static NSArray<NSString *> *_mockPreferredLanguages;

+ (NSArray<NSString *> *)preferredLanguages {
return _mockPreferredLanguages;
}

+ (void)setPreferredLanguages:(NSArray<NSString *> *)languages
{
_mockPreferredLanguages = languages;
}

@end
Loading