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

fix: Adds fallback dictionary when serialising device info. #279

Merged
merged 5 commits into from
May 24, 2018

Conversation

fractalwrench
Copy link
Contributor

@fractalwrench fractalwrench commented May 15, 2018

Goal

Previously the device tab was serialised using the dictionary supplied from the report, which could be null if the keypath did not exist. This could result in the device tab being completely null. This fix uses an empty dictionary as a fallback so that at least some information (freeDisk, locale, simulator) will always be returned.

Changeset

Changed

Initialise empty dictionary and defensively add items from report to it.

Tests

Added a failing unit test for the encountered scenario then passed it.

Review

For the submitter, initial self-review:

  • Commented on code changes inline explain the reasoning behind the approach
  • Reviewed the test cases added for completeness and possible points for discussion
  • A changelog entry was added for the goal of this pull request
  • Check the scope of the changeset - is everything in the diff required for the pull request?
  • This pull request is ready for:
    • Initial review of the intended approach, not yet feature complete
    • Structural review of the classes, functions, and properties modified
    • Final review

For the pull request reviewer(s), this changeset has been reviewed for:

  • Consistency across platforms for structures or concepts added or modified
  • Consistency between the changeset and the goal stated above
  • Internal consistency with the rest of the library - is there any overlap between existing interfaces and any which have been added?
  • Usage friction - is the proposed change in usage cumbersome or complicated?
  • Performance and complexity - are there any cases of unexpected O(n^3) when iterating, recursing, flat mapping, etc?
  • Concurrency concerns - if components are accessed asynchronously, what issues will arise
  • Thoroughness of added tests and any missing edge cases
  • Idiomatic use of the language

Previously the device tab was serialised using the dictionary supplied from the report, which could
be null if the keypath did not exist. This fix uses an empty dictionary as a fallback so that at
least some information (freeDisk, locale, simulator) will always be returned.
@fractalwrench fractalwrench requested a review from a team May 15, 2018 09:45
kattrali
kattrali previously approved these changes May 15, 2018
Copy link
Contributor

@kattrali kattrali 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, left a few nits.

[[report valueForKeyPath:@"user.state.deviceState"] mutableCopy];

NSMutableDictionary *device = [NSMutableDictionary new];
NSDictionary *state = [[report valueForKeyPath:@"user.state.deviceState"] mutableCopy];
Copy link
Contributor

Choose a reason for hiding this comment

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

This no longer needs to be a mutable copy since the entries are being copied instead of appending to the original.

Choose a reason for hiding this comment

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

For consideration: Since valueForKey: can throw exceptions for incorrect keys, and since keypaths can't be checked by the compiler, is it worth considering wrapping these in a @try/@catch? It's certainly very unlikely these will throw, but not impossible.

XCTAssertNotNil(device[@"simulator"]);
}

@end
Copy link
Contributor

Choose a reason for hiding this comment

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

What happens if the report argument is nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've tested this out and a dictionary is returned with the same contents as if an empty dictionary had been passed in. Adding this as a test would currently fail the suite with an error, presumably due to the fact we've enabled strict build settings and this method parameter is enabled as NonNull. Do you feel we need to change anything so that this can be unit tested?

Choose a reason for hiding this comment

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

Is it possible to loosen the restrictions on just the test files? It seems like it might be useful to have a test like that

@kastiglione
Copy link

👍

martin308
martin308 previously approved these changes May 16, 2018
Copy link

@martin308 martin308 left a comment

Choose a reason for hiding this comment

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

Mostly looks good to me, added a question and a thought on the tests

NSMutableDictionary *device =
[[report valueForKeyPath:@"user.state.deviceState"] mutableCopy];

NSMutableDictionary *device = [NSMutableDictionary new];

Choose a reason for hiding this comment

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

Would it be better to do something like this? I'm not sure how initWithDictionary handles nil

NSDictionary *state = [report valueForKeyPath:@"user.state.deviceState"];
NSMutableDictionary* device = [[NSMutableDictionary alloc] initWithDictionary: state];

Copy link
Contributor Author

Choose a reason for hiding this comment

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

initWithDictionary: requires a Nonnull parameter, whereas addEntriesFromDictionary: handles a nil param.

XCTAssertNotNil(device[@"simulator"]);
}

@end

Choose a reason for hiding this comment

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

Is it possible to loosen the restrictions on just the test files? It seems like it might be useful to have a test like that

@fractalwrench
Copy link
Contributor Author

@martin308 I've added a test for a nil dictionary by using #pragma to loosen the restrictions.

@fractalwrench fractalwrench requested a review from a team May 17, 2018 13:47
#pragma clang diagnostic ignored "-Wnonnull"

- (void)testNilDictSerialisation {
XCTAssertNotNil(BSGParseDevice(nil));

Choose a reason for hiding this comment

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

This could return an empty dictionary and still pass. I think this should check the contents too.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto this 👆 - the test should check the values are what is expected.

#pragma clang diagnostic ignored "-Wnonnull"

- (void)testNilDictSerialisation {
XCTAssertNotNil(BSGParseDevice(nil));
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto this 👆 - the test should check the values are what is expected.

}

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
Copy link
Contributor

Choose a reason for hiding this comment

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

The pragma declarations should wrap what is being ignored as closely as possible to avoid any unintended usages.

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
NSDictionary *device = BSGParseDevice(nil);
#pragma clang diagnostic pop

XCTAssertNotNil(device);
// ... (more)

@fractalwrench
Copy link
Contributor Author

Thanks for the review comments - I've addressed the pragma + validation comments.

}


@end

Choose a reason for hiding this comment

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

Do we need a test for a valid dictionary that contains the expected key?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is tested elsewhere I believe

Copy link

@martin308 martin308 left a comment

Choose a reason for hiding this comment

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

Left one question about another possible test, otherwise this LGTM

@kattrali kattrali merged commit 61aab87 into master May 24, 2018
@kattrali kattrali deleted the device-state-serialisation-fix branch May 24, 2018 03:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants