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

Fixes crash in STPAddCardViewController with some prefilled billing addresses #1004

Merged
merged 4 commits into from
Aug 9, 2018

Conversation

csabol-stripe
Copy link
Contributor

Summary

Fixes STPAddCardViewController STPAddressViewModelDelegate methods to check for valid table view inserts and removes.

In cases where a zip code is required and the user's locale doesn't support zip codes but their billing address includes one (or vice-versa),
this was causing a crash because we were trying to add or remove cells that were already there or were never there respectively.

Motivation

#999

Testing

I wrote automated tests for the cases that were previously causing crashes

… check for valid table view inserts and removes.

In cases where a zip code is required and the user's locale doesn't support zip codes but their billing address includes one (or vice-versa),
this was causing a crash because we were trying to add or remove cells that were already there or were never there respectively.
Copy link
Contributor

@danj-stripe danj-stripe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I understand what the problem is, and how this is addressing it. I'm curious if there's something better we can do to handle the add/removed cell calls


@implementation NSObject (STPSwizzling)

+ (void)stp_swizzleClassMethod:(SEL)original withReplacement:(SEL)replacement
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you consider using the STPAspects code instead?

This is a really simple usage, and since it's test code I don't think it needs to get fancy, mostly just curious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't even know that existed! I'll keep in mind for next time

[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self updateInputAccessoryVisiblity];
NSInteger rowsInSection = [self.tableView numberOfRowsInSection:STPPaymentCardBillingAddressSection];
if (rowsInSection != NSNotFound && rowsInSection < [self tableView:self.tableView numberOfRowsInSection:STPPaymentCardBillingAddressSection]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to (cleanly) push this down into the STPAddressViewModel? It looks like it's already trying to track showingPostalCodeCell, and has logic for whether it's being added or removed based on updates to the address.

Or maybe we should move the _addressViewModel.delegate = self line to after we set the pre-filled info, because we don't care about updates to the ViewModel until after we've finished creating the views? That might allow us to avoid this complexity completely?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to (cleanly) push this down into the STPAddressViewModel?

I actually prefer the logic to live in the view controller because this situation is a result of layout passes/table view caching/etc. that I think the view controller is closer too than the view model (correct me if I'm wrong in my view model understanding :) ).

Or maybe we should move the _addressViewModel.delegate = self line to after we set the pre-filled info, because we don't care about updates to the ViewModel until after we've finished creating the views? That might allow us to avoid this complexity completely?

I thought about this. I believe that change would also fix the crash, but this solution is more robust

if (rowsInSection != NSNotFound && index < (NSUInteger)rowsInSection) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:STPPaymentCardBillingAddressSection];
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
[self updateInputAccessoryVisiblity];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it important that the call to updateInputAccessoryVisibility is inside the if block for add, but outside it for remove?

I don't think so, but wanted to see if there was something I'm missing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, I'll move it out of the if in remove for consistency :)

@csabol-stripe
Copy link
Contributor Author

I'm curious if there's something better we can do to handle the add/removed cell calls

I played around with the idea of a larger fix that avoids delegate calls that are too early, etc. I ended up deciding that this solution is not too hacky, pretty robust, and ultimately the best bang for our buck. Happy to reconsider/discuss if you feel differently!

@csabol-stripe
Copy link
Contributor Author

@danj-stripe pointed out that STPShippingAddressViewController has pretty much identical code. I'm going to try triggering the crash there and fix in this patch

Copy link
Contributor

@danj-stripe danj-stripe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

I have some minor nits, where I think the tests could be better self-documenting and more robust to changes (given we just tripped over that in #1010).

prefilledInformation:nil];

[sut loadView];
[sut viewDidLoad];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT about adding XCTAssertNoThrow calls around these?

I think that'd catch the NSInternalInconsistencyException that was being triggered. If so, it'd give a better failure message if it regresses, and it helps document what these tests are looking for. As it is, without context this test looks like a no-op.

Same for the matching tests of the other class.

}

- (void)testPrefilledBillingAddress_addAddress {
[NSLocale stp_setCurrentLocale:[NSLocale localeWithLocaleIdentifier:@"en_ZW"]];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT about adding assertions (or a separate test?) that postalCodeIsRequiredForCountryCode: returns the expected values?

If ZW starts requiring a postal code, or we stop requiring it for US, we start testing a different code path, and the code could break silently.

It also helps document what's being tested, and why those countries were chosen.

@@ -41,6 +42,53 @@ - (STPAddCardViewController *)buildAddCardViewController {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

- (void)testPrefilledBillingAddress_removeAddress {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these need to be inside the #pragma clang diagnostic ignored "-Warc-performSelector-leaks" block? It might be slightly better to move them outside.

@stripe-ci stripe-ci removed the approved label Aug 9, 2018
Copy link
Contributor

@danj-stripe danj-stripe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

@csabol-stripe csabol-stripe merged commit 7a721d8 into master Aug 9, 2018
@csabol-stripe csabol-stripe deleted the csabol/IOS-829_zip_crash branch August 9, 2018 18:02
csabol-stripe pushed a commit that referenced this pull request Apr 26, 2022
* Fix bug when shadow is nil and double apply of shadow

* Hide shadow when using `StackViewWithSeparator`

* Add shadow snapshots

* update snapshots

* resolve snapshot merge conflicts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants