Commit Graph
6 Commits
Author SHA1 Message Date
NachoSoto 9679af3bc1 CustomerInfoDecodingTests: added test to check decoding invalid data behavior (#1659)
See also #1658.
This updates the behavior of `CustomerInfoResponse` decoding so that having invalid content inside of one of the structures fails more loudly instead of getting ignored.

For that, `@DefaultValue` no longer ignores errors, and instead `@IgnoreDecodeErrors` must be used.
For some of the values in `CustomerInfoResponse` this makes sense (like `Store`), but not for things like subscriptions where we would be losing data.
2022-06-07 16:56:04 -07:00
NachoSoto 9872dcac01 Renamed Decoder.throwValueNotFoundError (#1569)
The method doesn't actually throw, so calling `throw decoder.throwValueNotFoundError()` was confusing. Now the code reads `throw decoder.valueNotFoundError()`.
2022-05-23 18:27:35 -07:00
NachoSoto 0132b69a86 Added @IgnoreEncodable property wrapper (#1567)
This allows having properties in an `Encodable` type that won't be encoded.
This will be used to storing the `rawData` when decoding our types (see #1496).
2022-05-23 18:27:18 -07:00
NachoSoto 0864119449 Added @IgnoreDecodeErrors property wrapper (#1541)
Follow up to #1537. This will be needed for several properties of `CustomerInfo`'s response, like `managementURL`.
2022-05-10 10:30:17 -07:00
NachoSoto 3bda51b677 Created DefaultValue and DefaultDecodable (#1537)
A future PR will make use of these: #1540.
The purpose of this is to be able to define `Decodable` types with default values without needing to implement the whole `init(from decoder: Decoder)` from scratch. If any one property has a default value, that's the only way to provide it without these.

For example, `EntitlementInfo.ProductData` implements this:
```swift
init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    self.isSandbox = try container.decodeIfPresent(Bool.self, forKey: .isSandbox) ?? false
    self.originalPurchaseDate = try container.decodeIfPresent(Date.self, forKey: .originalPurchaseDate)
    self.expiresDate = try container.decodeIfPresent(Date.self, forKey: .expiresDate)
    self.unsubscribeDetectedAt = try container.decodeIfPresent(Date.self, forKey: .unsubscribeDetectedAt)
    self.billingIssuesDetectedAt = try container.decodeIfPresent(Date.self, forKey: .billingIssuesDetectedAt)
    self.periodType = container.decode(PeriodType.self, forKey: .periodType, defaultValue: .normal)
    self.store = container.decode(Store.self, forKey: .store, defaultValue: .unknownStore)
    self.ownershipType = container.decode(PurchaseOwnershipType.self,
                                          forKey: .ownershipType,
                                          defaultValue: .purchased)
}
```

With these new types, that whole implementation is unnecessary and can be data-driven instead, which is more maintanable and less error-prone:
```swift
struct ProductData: Decodable {

    @DefaultValue<PeriodType> var periodType: PeriodType
    var originalPurchaseDate: Date?
    var expiresDate: Date?
    @DefaultValue<Store> var store: Store
    @DefaultDecodable.False var isSandbox: Bool
    var unsubscribeDetectedAt: Date?
    var billingIssuesDetectedAt: Date?
    @DefaultValue<PurchaseOwnershipType> var ownershipType: PurchaseOwnershipType

}
```
2022-05-10 10:26:13 -07:00
aboedo f5697de730 renamed Purchases folder to Sources (#1416)
* renamed `Purchases` folder to `Sources`

* temporarily enabling installation test jobs

* re-disabling installation test jobs
2022-03-28 11:53:24 -03:00