Skip to content

Commit

Permalink
Merge pull request #1004 from stripe/csabol/IOS-829_zip_crash
Browse files Browse the repository at this point in the history
Fixes crash in STPAddCardViewController with some prefilled billing addresses
  • Loading branch information
csabol-stripe authored Aug 9, 2018
2 parents a8922af + 9e21431 commit 7a721d8
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 13 deletions.
22 changes: 17 additions & 5 deletions Stripe.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
8B39128220E2F99600098401 /* EPSSource.json in Resources */ = {isa = PBXBuildFile; fileRef = 8B39128120E2F99600098401 /* EPSSource.json */; };
8B39128320E2F9A100098401 /* BancontactSource.json in Resources */ = {isa = PBXBuildFile; fileRef = 8B39127F20E2F6A500098401 /* BancontactSource.json */; };
Expand Down Expand Up @@ -1042,6 +1045,9 @@
04F94D6F1D21CB20004FC826 /* StripeiOSResources.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StripeiOSResources.xcconfig; sourceTree = "<group>"; };
04FCFA171BD59A8C00297732 /* STPCategoryLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCategoryLoader.h; sourceTree = "<group>"; };
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 = "<group>"; };
3617A51320FE5BBB001A9E6A /* NSLocale+STPSwizzling.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSLocale+STPSwizzling.m"; sourceTree = "<group>"; };
3691EB73211A4F31008C49E1 /* STPShippingAddressViewControllerTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPShippingAddressViewControllerTest.m; sourceTree = "<group>"; };
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 = "<group>"; };
8B013C881F1E784A00DD831B /* STPPaymentConfigurationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPPaymentConfigurationTest.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1512,12 +1518,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 */,
Expand All @@ -1526,7 +1534,7 @@
C1CFCB6A1ED5E0F400BE45DF /* STPMocks.m */,
C1D23FAF1D37FC90002FD83C /* STPTestUtils.h */,
C1D23FB01D37FC90002FD83C /* STPTestUtils.m */,
C1CFCB781ED5F85A00BE45DF /* stp_test_upload_image.jpeg */,
C18867D81E8B093300A77634 /* Unit */,
);
name = StripeTests;
path = Tests/Tests;
Expand Down Expand Up @@ -1687,6 +1695,7 @@
C1EEDCC91CA2186300A54582 /* STPPhoneNumberValidatorTest.m */,
C1FEE5981CBFF24000A7632B /* STPPostalCodeValidatorTest.m */,
F152321A1EA92F9D00D65C67 /* STPRedirectContextTest.m */,
3691EB73211A4F31008C49E1 /* STPShippingAddressViewControllerTest.m */,
8BD87B8A1EFB136F00269C2B /* STPSourceCardDetailsTest.m */,
8B5B4B431EFDD925005CF475 /* STPSourceOwnerTest.m */,
C1BD9B1E1E390A2700CEE925 /* STPSourceParamsTest.m */,
Expand Down Expand Up @@ -2148,6 +2157,7 @@
F148ABFA1D5E88C40014FD92 /* STPTestUtils.h in Headers */,
C1CFCB6D1ED5E0F800BE45DF /* STPMocks.h in Headers */,
C18867DB1E8B0C4100A77634 /* STPFixtures.h in Headers */,
3617A51420FE5BBB001A9E6A /* NSLocale+STPSwizzling.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2857,9 +2867,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 */,
Expand Down
22 changes: 14 additions & 8 deletions Stripe/STPAddCardViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -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)];

Expand All @@ -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");
Expand Down Expand Up @@ -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];
}

Expand Down
16 changes: 16 additions & 0 deletions Tests/Tests/NSLocale+STPSwizzling.h
Original file line number Diff line number Diff line change
@@ -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 <Foundation/Foundation.h>

@interface NSLocale (STPSwizzling)

+ (void)stp_setCurrentLocale:(NSLocale *)locale;
+ (void)stp_resetCurrentLocale;

@end
59 changes: 59 additions & 0 deletions Tests/Tests/NSLocale+STPSwizzling.m
Original file line number Diff line number Diff line change
@@ -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 <objc/runtime.h>

@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
56 changes: 56 additions & 0 deletions Tests/Tests/STPAddCardViewControllerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
#import <OCMock/OCMock.h>
#import <Stripe/Stripe.h>
#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;
Expand All @@ -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"

Expand Down
81 changes: 81 additions & 0 deletions Tests/Tests/STPShippingAddressViewControllerTest.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//
// STPShippingAddressViewControllerTest.m
// StripeiOS Tests
//
// Created by Cameron Sabol on 8/7/18.
// Copyright © 2018 Stripe, Inc. All rights reserved.
//

#import <XCTest/XCTest.h>

#import <Stripe/Stripe.h>
#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

0 comments on commit 7a721d8

Please sign in to comment.