Files
purchases-ios/Sources/LocalReceiptParsing/DataConverters/Codable+Extensions.swift
T
NachoSoto 4187316738 Encodable.jsonEncodedData: fixed tests on iOS 17 due to inconsistent key ordering (#2607)
A bunch of tests were failing on Xcode 15 due to [a change in
Swift](https://github.com/apple/swift/issues/66466), because we relying
on being able to verify that the encoded `Data` saved to caches is
consistent.
Starting on Swift 5.9 `JSONEncoder` has optimizations that mean we can't
rely on it.

To fix this, this PR does 2 things:
- Changed `JSONEncoder.prettyPrinted` to have `.sortedKeys`
- Changed test to verify the decoded response `struct`, not the raw
encoded `Data`

Note that I didn't make `JSONEncoder.default` use `.sortedKeys` because
of the potential performance impact. `Encodable.prettyPrintedData` is
used in tests like `ReceiptFetcherTests` (which this PR fixes) and for
debug purposes, but `Encodable.encodedJSON` is used everywhere.
2023-06-09 11:30:59 -07:00

84 lines
2.1 KiB
Swift

//
// Copyright RevenueCat Inc. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// Codable+Extensions.swift
//
// Created by Nacho Soto on 11/29/22.
import Foundation
extension Encodable {
/// - Throws: if encoding failed
/// - Returns: `nil` if the encoded `Data` can't be serialized into a `String`.
var prettyPrintedJSON: String? {
get throws {
return String(data: try self.prettyPrintedData, encoding: .utf8)
}
}
/// - Throws: if encoding failed
/// - Returns: `nil` if the encoded `Data` can't be serialized into a `String`.
var encodedJSON: String? {
get throws {
return String(data: try self.jsonEncodedData, encoding: .utf8)
}
}
// MARK: -
var prettyPrintedData: Data {
get throws {
return try JSONEncoder.prettyPrinted.encode(self)
}
}
/// - Note: beginning with iOS 17, the output of this is not guaranteed to be consistent due to key ordering.
/// For tests, it's better to compare `prettyPrintedData` which does sort keys.
var jsonEncodedData: Data {
get throws {
return try JSONEncoder.default.encode(self)
}
}
}
extension JSONEncoder {
static let `default`: JSONEncoder = {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.dateEncodingStrategy = .iso8601
return encoder
}()
static let prettyPrinted: JSONEncoder = {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.dateEncodingStrategy = .iso8601
encoder.outputFormatting = [.sortedKeys, .prettyPrinted]
return encoder
}()
}
extension JSONDecoder {
static let `default`: JSONDecoder = {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .iso8601
return decoder
}()
}