diff --git a/Stripe.xcodeproj/project.pbxproj b/Stripe.xcodeproj/project.pbxproj index c056e4bb5c9..2af17ed770f 100644 --- a/Stripe.xcodeproj/project.pbxproj +++ b/Stripe.xcodeproj/project.pbxproj @@ -324,6 +324,9 @@ 04F94DD31D22A23F004FC826 /* NSBundle+Stripe_AppName.h in Headers */ = {isa = PBXBuildFile; fileRef = 049A3F971CC76A2400F57DE7 /* NSBundle+Stripe_AppName.h */; }; 04F94DD41D22A242004FC826 /* NSBundle+Stripe_AppName.m in Sources */ = {isa = PBXBuildFile; fileRef = 049A3F981CC76A2400F57DE7 /* NSBundle+Stripe_AppName.m */; }; 04FCFA191BD59A8C00297732 /* STPCategoryLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 04FCFA171BD59A8C00297732 /* STPCategoryLoader.h */; }; + 3617A51420FE5BBB001A9E6A /* NSLocale+STPSwizzling.h in Headers */ = {isa = PBXBuildFile; fileRef = 3617A51220FE5BBB001A9E6A /* NSLocale+STPSwizzling.h */; }; + 3617A51520FE5BBB001A9E6A /* NSLocale+STPSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = 3617A51320FE5BBB001A9E6A /* NSLocale+STPSwizzling.m */; }; + 3691EB74211A4F31008C49E1 /* STPShippingAddressViewControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 3691EB73211A4F31008C49E1 /* STPShippingAddressViewControllerTest.m */; }; 8B013C891F1E784A00DD831B /* STPPaymentConfigurationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B013C881F1E784A00DD831B /* STPPaymentConfigurationTest.m */; }; 8B429AD81EF9D4B400F95F34 /* STPBankAccountParams+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B429AD71EF9D4A300F95F34 /* STPBankAccountParams+Private.h */; }; 8B429AD91EF9D4B500F95F34 /* STPBankAccountParams+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B429AD71EF9D4A300F95F34 /* STPBankAccountParams+Private.h */; }; @@ -1036,6 +1039,9 @@ 04F94D6F1D21CB20004FC826 /* StripeiOSResources.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StripeiOSResources.xcconfig; sourceTree = ""; }; 04FCFA171BD59A8C00297732 /* STPCategoryLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCategoryLoader.h; sourceTree = ""; }; 11C74B9B164043050071C2CA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 3617A51220FE5BBB001A9E6A /* NSLocale+STPSwizzling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSLocale+STPSwizzling.h"; sourceTree = ""; }; + 3617A51320FE5BBB001A9E6A /* NSLocale+STPSwizzling.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSLocale+STPSwizzling.m"; sourceTree = ""; }; + 3691EB73211A4F31008C49E1 /* STPShippingAddressViewControllerTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPShippingAddressViewControllerTest.m; sourceTree = ""; }; 4A0D74F918F6106100966D7B /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 7E0B1132203572FB00271AD3 /* fi */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = fi; path = Localizations/fi.lproj/Localizable.strings; sourceTree = ""; }; 8B013C881F1E784A00DD831B /* STPPaymentConfigurationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPPaymentConfigurationTest.m; sourceTree = ""; }; @@ -1500,12 +1506,14 @@ 04CDB5281A5F3A9300B854EE /* StripeTests */ = { isa = PBXGroup; children = ( - C18867D61E8B069E00A77634 /* Snapshot */, - C18867D71E8B07F600A77634 /* Functional */, - C18867D81E8B093300A77634 /* Unit */, - C1D23FB71D37FE0F002FD83C /* JSON */, F1B8534D1FDF544B0065A49E /* FBSnapshotTestCase+STPViewControllerLoading.h */, F1B8534E1FDF544B0065A49E /* FBSnapshotTestCase+STPViewControllerLoading.m */, + C18867D71E8B07F600A77634 /* Functional */, + C1D23FB71D37FE0F002FD83C /* JSON */, + 3617A51220FE5BBB001A9E6A /* NSLocale+STPSwizzling.h */, + 3617A51320FE5BBB001A9E6A /* NSLocale+STPSwizzling.m */, + C18867D61E8B069E00A77634 /* Snapshot */, + C1CFCB781ED5F85A00BE45DF /* stp_test_upload_image.jpeg */, C18867D91E8B0C4100A77634 /* STPFixtures.h */, C18867DA1E8B0C4100A77634 /* STPFixtures.m */, F1D96F981DC7DCDE00477E64 /* STPLocalizationUtils+STPTestAdditions.h */, @@ -1514,7 +1522,7 @@ C1CFCB6A1ED5E0F400BE45DF /* STPMocks.m */, C1D23FAF1D37FC90002FD83C /* STPTestUtils.h */, C1D23FB01D37FC90002FD83C /* STPTestUtils.m */, - C1CFCB781ED5F85A00BE45DF /* stp_test_upload_image.jpeg */, + C18867D81E8B093300A77634 /* Unit */, ); name = StripeTests; path = Tests/Tests; @@ -1669,6 +1677,7 @@ C1EEDCC91CA2186300A54582 /* STPPhoneNumberValidatorTest.m */, C1FEE5981CBFF24000A7632B /* STPPostalCodeValidatorTest.m */, F152321A1EA92F9D00D65C67 /* STPRedirectContextTest.m */, + 3691EB73211A4F31008C49E1 /* STPShippingAddressViewControllerTest.m */, 8BD87B8A1EFB136F00269C2B /* STPSourceCardDetailsTest.m */, 8B5B4B431EFDD925005CF475 /* STPSourceOwnerTest.m */, C1BD9B1E1E390A2700CEE925 /* STPSourceParamsTest.m */, @@ -2130,6 +2139,7 @@ F148ABFA1D5E88C40014FD92 /* STPTestUtils.h in Headers */, C1CFCB6D1ED5E0F800BE45DF /* STPMocks.h in Headers */, C18867DB1E8B0C4100A77634 /* STPFixtures.h in Headers */, + 3617A51420FE5BBB001A9E6A /* NSLocale+STPSwizzling.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2833,9 +2843,11 @@ F148ABFB1D5E88C70014FD92 /* STPTestUtils.m in Sources */, 8BB97F081F26645B0095122A /* NSDictionary+StripeTest.m in Sources */, 045A62AB1B8E7259000165CE /* STPPaymentCardTextFieldTest.m in Sources */, + 3617A51520FE5BBB001A9E6A /* NSLocale+STPSwizzling.m in Sources */, C1054F911FE197AE0033C87E /* STPPaymentContextSnapshotTests.m in Sources */, C127110A1DBA7E490087840D /* STPAddressViewModelTest.m in Sources */, C17D24EE1E37DBAC005CB188 /* STPSourceTest.m in Sources */, + 3691EB74211A4F31008C49E1 /* STPShippingAddressViewControllerTest.m in Sources */, C1E4F8061EBBEB0F00E611F5 /* STPCustomerContextTest.m in Sources */, B3302F4C200700AB005DDBE9 /* STPLegalEntityParamsTest.m in Sources */, F14C872F1D4FCDBA00C7CC6A /* STPPaymentContextApplePayTest.m in Sources */, diff --git a/Stripe/STPAddCardViewController.m b/Stripe/STPAddCardViewController.m index aa44ff9ee7d..94e20054a55 100644 --- a/Stripe/STPAddCardViewController.m +++ b/Stripe/STPAddCardViewController.m @@ -115,10 +115,6 @@ - (void)createAndSetupViews { STPPaymentCardTextFieldCell *paymentCell = [[STPPaymentCardTextFieldCell alloc] init]; paymentCell.paymentField.delegate = self; self.paymentCell = paymentCell; - - if (self.prefilledInformation.billingAddress != nil) { - self.addressViewModel.address = self.prefilledInformation.billingAddress; - } self.activityIndicator = [[STPPaymentActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20.0f, 20.0f)]; @@ -128,6 +124,10 @@ - (void)createAndSetupViews { self.tableView.dataSource = self; self.tableView.delegate = self; + if (self.prefilledInformation.billingAddress != nil) { + self.addressViewModel.address = self.prefilledInformation.billingAddress; + } + STPSectionHeaderView *addressHeaderView = [STPSectionHeaderView new]; addressHeaderView.theme = self.theme; addressHeaderView.title = STPLocalizedString(@"Billing Address", @"Title for billing address entry section"); @@ -398,14 +398,20 @@ - (void)paymentCardTextFieldDidEndEditingCVC:(__unused STPPaymentCardTextField * #pragma mark - STPAddressViewModelDelegate - (void)addressViewModel:(__unused STPAddressViewModel *)addressViewModel addedCellAtIndex:(NSUInteger)index { - NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:STPPaymentCardBillingAddressSection]; - [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; + NSInteger rowsInSection = [self.tableView numberOfRowsInSection:STPPaymentCardBillingAddressSection]; + if (rowsInSection != NSNotFound && rowsInSection < [self tableView:self.tableView numberOfRowsInSection:STPPaymentCardBillingAddressSection]) { + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:STPPaymentCardBillingAddressSection]; + [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; + } [self updateInputAccessoryVisiblity]; } - (void)addressViewModel:(__unused STPAddressViewModel *)addressViewModel removedCellAtIndex:(NSUInteger)index { - NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:STPPaymentCardBillingAddressSection]; - [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; + NSInteger rowsInSection = [self.tableView numberOfRowsInSection:STPPaymentCardBillingAddressSection]; + if (rowsInSection != NSNotFound && index < (NSUInteger)rowsInSection) { + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:STPPaymentCardBillingAddressSection]; + [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; + } [self updateInputAccessoryVisiblity]; } diff --git a/Tests/Tests/NSLocale+STPSwizzling.h b/Tests/Tests/NSLocale+STPSwizzling.h new file mode 100644 index 00000000000..aa3904654f2 --- /dev/null +++ b/Tests/Tests/NSLocale+STPSwizzling.h @@ -0,0 +1,16 @@ +// +// NSLocale+STPSwizzling.h +// StripeiOS Tests +// +// Created by Cameron Sabol on 7/17/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import + +@interface NSLocale (STPSwizzling) + ++ (void)stp_setCurrentLocale:(NSLocale *)locale; ++ (void)stp_resetCurrentLocale; + +@end diff --git a/Tests/Tests/NSLocale+STPSwizzling.m b/Tests/Tests/NSLocale+STPSwizzling.m new file mode 100644 index 00000000000..7386308cd99 --- /dev/null +++ b/Tests/Tests/NSLocale+STPSwizzling.m @@ -0,0 +1,59 @@ +// +// NSLocale+STPSwizzling.m +// StripeiOS Tests +// +// Created by Cameron Sabol on 7/17/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import "NSLocale+STPSwizzling.h" + +#import + +@interface NSObject (STPSwizzling) + ++ (void)stp_swizzleClassMethod:(SEL)original withReplacement:(SEL)replacement; + +@end + +@implementation NSObject (STPSwizzling) + ++ (void)stp_swizzleClassMethod:(SEL)original withReplacement:(SEL)replacement +{ + method_exchangeImplementations(class_getClassMethod(self, original), class_getClassMethod(self, replacement)); +} + +@end + +@implementation NSLocale (STPSwizzling) + +static NSLocale *_stpLocaleOverride = nil; + ++ (void)stp_setCurrentLocale:(NSLocale *)locale +{ + if (_stpLocaleOverride == nil & locale != nil) { + [self stp_swizzleClassMethod:@selector(currentLocale) withReplacement:@selector(stp_currentLocale)]; + [self stp_swizzleClassMethod:@selector(autoupdatingCurrentLocale) withReplacement:@selector(stp_autoUpdatingCurrentLocale)]; + [self stp_swizzleClassMethod:@selector(systemLocale) withReplacement:@selector(stp_systemLocale)]; + } + _stpLocaleOverride = locale; +} + ++ (void)stp_resetCurrentLocale +{ + [self stp_setCurrentLocale:nil]; +} + ++ (instancetype)stp_currentLocale { + return _stpLocaleOverride ?: [self stp_currentLocale]; +} + ++ (instancetype)stp_autoUpdatingCurrentLocale { + return _stpLocaleOverride ?: [self stp_autoUpdatingCurrentLocale]; +} + ++ (instancetype)stp_systemLocale { + return _stpLocaleOverride ?: [self stp_systemLocale]; +} + +@end diff --git a/Tests/Tests/STPAddCardViewControllerTest.m b/Tests/Tests/STPAddCardViewControllerTest.m index f65728aa770..bb345cc5a19 100644 --- a/Tests/Tests/STPAddCardViewControllerTest.m +++ b/Tests/Tests/STPAddCardViewControllerTest.m @@ -10,9 +10,11 @@ #import #import #import "NSError+Stripe.h" +#import "NSLocale+STPSwizzling.h" #import "STPCard.h" #import "STPFixtures.h" #import "STPPaymentCardTextFieldCell.h" +#import "STPPostalCodeValidator.h" @interface STPAddCardViewController (Testing) @property (nonatomic) STPPaymentCardTextFieldCell *paymentCell; @@ -38,6 +40,60 @@ - (STPAddCardViewController *)buildAddCardViewController { return vc; } +- (void)testPrefilledBillingAddress_removeAddress { + STPPaymentConfiguration *config = [STPFixtures paymentConfiguration]; + config.requiredBillingAddressFields = STPBillingAddressFieldsZip; + STPAddCardViewController *sut = [[STPAddCardViewController alloc] initWithConfiguration:config + theme:[STPTheme defaultTheme]]; + STPAddress *address = [STPAddress new]; + address.name = @"John Smith Doe"; + address.phone = @"8885551212"; + address.email = @"foo@example.com"; + address.line1 = @"55 John St"; + address.city = @"Harare"; + address.postalCode = @"10002"; + address.country = @"ZW"; // Zimbabwe does not require zip codes, while the default locale for tests (US) does + // Sanity checks + XCTAssertFalse([STPPostalCodeValidator postalCodeIsRequiredForCountryCode:@"ZW"]); + XCTAssertTrue([STPPostalCodeValidator postalCodeIsRequiredForCountryCode:@"US"]); + + STPUserInformation *prefilledInfo = [[STPUserInformation alloc] init]; + prefilledInfo.billingAddress = address; + sut.prefilledInformation = prefilledInfo; + + XCTAssertNoThrow([sut loadView]); + XCTAssertNoThrow([sut viewDidLoad]); +} + +- (void)testPrefilledBillingAddress_addAddress { + [NSLocale stp_setCurrentLocale:[NSLocale localeWithLocaleIdentifier:@"en_ZW"]]; // Zimbabwe does not require zip codes, while the default locale for tests (US) does + // Sanity checks + XCTAssertFalse([STPPostalCodeValidator postalCodeIsRequiredForCountryCode:@"ZW"]); + XCTAssertTrue([STPPostalCodeValidator postalCodeIsRequiredForCountryCode:@"US"]); + STPPaymentConfiguration *config = [STPFixtures paymentConfiguration]; + config.requiredBillingAddressFields = STPBillingAddressFieldsZip; + STPAddCardViewController *sut = [[STPAddCardViewController alloc] initWithConfiguration:config + theme:[STPTheme defaultTheme]]; + STPAddress *address = [STPAddress new]; + address.name = @"John Smith Doe"; + address.phone = @"8885551212"; + address.email = @"foo@example.com"; + address.line1 = @"55 John St"; + address.city = @"New York"; + address.state = @"NY"; + address.postalCode = @"10002"; + address.country = @"US"; + + STPUserInformation *prefilledInfo = [[STPUserInformation alloc] init]; + prefilledInfo.billingAddress = address; + sut.prefilledInformation = prefilledInfo; + + XCTAssertNoThrow([sut loadView]); + XCTAssertNoThrow([sut viewDidLoad]); + [NSLocale stp_resetCurrentLocale]; +} + + #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" diff --git a/Tests/Tests/STPShippingAddressViewControllerTest.m b/Tests/Tests/STPShippingAddressViewControllerTest.m new file mode 100644 index 00000000000..f2fbacb9357 --- /dev/null +++ b/Tests/Tests/STPShippingAddressViewControllerTest.m @@ -0,0 +1,81 @@ +// +// STPShippingAddressViewControllerTest.m +// StripeiOS Tests +// +// Created by Cameron Sabol on 8/7/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import + +#import +#import "NSLocale+STPSwizzling.h" +#import "STPFixtures.h" +#import "STPPostalCodeValidator.h" + +@interface STPShippingAddressViewControllerTest : XCTestCase + +@end + +@implementation STPShippingAddressViewControllerTest + +- (void)testPrefilledBillingAddress_removeAddress { + STPPaymentConfiguration *config = [STPFixtures paymentConfiguration]; + config.requiredShippingAddressFields = [NSSet setWithObject:STPContactFieldPostalAddress]; + + STPAddress *address = [STPAddress new]; + address.name = @"John Smith Doe"; + address.phone = @"8885551212"; + address.email = @"foo@example.com"; + address.line1 = @"55 John St"; + address.city = @"Harare"; + address.postalCode = @"10002"; + address.country = @"ZW"; // Zimbabwe does not require zip codes, while the default locale for tests (US) does + // Sanity checks + XCTAssertFalse([STPPostalCodeValidator postalCodeIsRequiredForCountryCode:@"ZW"]); + XCTAssertTrue([STPPostalCodeValidator postalCodeIsRequiredForCountryCode:@"US"]); + + STPShippingAddressViewController *sut = [[STPShippingAddressViewController alloc] initWithConfiguration:config + theme:[STPTheme defaultTheme] + currency:nil + shippingAddress:address + selectedShippingMethod:nil + prefilledInformation:nil]; + + XCTAssertNoThrow([sut loadView]); + XCTAssertNoThrow([sut viewDidLoad]); +} + +- (void)testPrefilledBillingAddress_addAddress { + [NSLocale stp_setCurrentLocale:[NSLocale localeWithLocaleIdentifier:@"en_ZW"]]; + // Zimbabwe does not require zip codes, while the default locale for tests (US) does + // Sanity checks + XCTAssertFalse([STPPostalCodeValidator postalCodeIsRequiredForCountryCode:@"ZW"]); + XCTAssertTrue([STPPostalCodeValidator postalCodeIsRequiredForCountryCode:@"US"]); + STPPaymentConfiguration *config = [STPFixtures paymentConfiguration]; + config.requiredShippingAddressFields = [NSSet setWithObject:STPContactFieldPostalAddress]; + + STPAddress *address = [STPAddress new]; + address.name = @"John Smith Doe"; + address.phone = @"8885551212"; + address.email = @"foo@example.com"; + address.line1 = @"55 John St"; + address.city = @"New York"; + address.state = @"NY"; + address.postalCode = @"10002"; + address.country = @"US"; + + STPShippingAddressViewController *sut = [[STPShippingAddressViewController alloc] initWithConfiguration:config + theme:[STPTheme defaultTheme] + currency:nil + shippingAddress:address + selectedShippingMethod:nil + prefilledInformation:nil]; + + XCTAssertNoThrow([sut loadView]); + XCTAssertNoThrow([sut viewDidLoad]); + [NSLocale stp_resetCurrentLocale]; +} + + +@end