Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Custom Decoder that can be used to create Decodable instances that are populated with random values
import Foundation
extension Decodable {
public static func randomInstance() throws -> Self {
let decoder = RandomDecoder()
return try Self(from: decoder)
}
}
private class RandomDecoder: Decoder {
let codingPath: [CodingKey] = []
let userInfo: [CodingUserInfoKey: Any] = [:]
init() { }
func container<Key: CodingKey>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> {
return .init(KeyedContainer<Key>())
}
func unkeyedContainer() throws -> UnkeyedDecodingContainer {
return UnkeyedContainer()
}
func singleValueContainer() throws -> SingleValueDecodingContainer {
return SingleValueContainer()
}
struct KeyedContainer<Key: CodingKey>: KeyedDecodingContainerProtocol {
let allKeys: [Key] = []
let codingPath: [CodingKey] = []
init() { }
func contains(_ key: Key) -> Bool {
return true
}
func decodeNil(forKey key: Key) throws -> Bool {
return Bool.random()
}
func decode<T: Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
return try T.randomInstance()
}
func nestedContainer<NestedKey: CodingKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> {
return .init(KeyedContainer<NestedKey>())
}
func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
return UnkeyedContainer()
}
func superDecoder() throws -> Decoder {
return RandomDecoder()
}
func superDecoder(forKey key: Key) throws -> Decoder {
return RandomDecoder()
}
}
struct UnkeyedContainer: UnkeyedDecodingContainer {
let codingPath: [CodingKey] = []
let count: Int? = (0...5).randomElement()
var isAtEnd: Bool { return currentIndex == (count ?? 0) }
private(set) var currentIndex = 0
init() { }
mutating func decodeNil() throws -> Bool {
return Bool.random()
}
mutating func decode<T: Decodable>(_ type: T.Type) throws -> T {
defer { currentIndex += 1 }
return try T.randomInstance()
}
mutating func nestedContainer<NestedKey: CodingKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> {
return .init(KeyedContainer<NestedKey>())
}
mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
return UnkeyedContainer()
}
mutating func superDecoder() throws -> Decoder {
return RandomDecoder()
}
}
struct SingleValueContainer: SingleValueDecodingContainer {
let codingPath: [CodingKey] = []
init() { }
func decodeNil() -> Bool { return Bool.random() }
func decode(_ type: Bool.Type) throws -> Bool { return Bool.random() }
func decode(_ type: String.Type) throws -> String { return String.random(length: Int.random(in: 0...50)) }
func decode(_ type: Double.Type) throws -> Double { return Double.random(in: 0...500) }
func decode(_ type: Float.Type) throws -> Float { return Float.random(in: 0...500) }
func decode(_ type: Int.Type) throws -> Int { return Int.random(in: 0...500) }
func decode(_ type: Int8.Type) throws -> Int8 { return Int8.random(in: 0...100) }
func decode(_ type: Int16.Type) throws -> Int16 { return Int16.random(in: 0...500) }
func decode(_ type: Int32.Type) throws -> Int32 { return Int32.random(in: 0...500) }
func decode(_ type: Int64.Type) throws -> Int64 { return Int64.random(in: 0...500) }
func decode(_ type: UInt.Type) throws -> UInt { return UInt.random(in: 0...500) }
func decode(_ type: UInt8.Type) throws -> UInt8 { return UInt8.random(in: 0...100) }
func decode(_ type: UInt16.Type) throws -> UInt16 { return UInt16.random(in: 0...500) }
func decode(_ type: UInt32.Type) throws -> UInt32 { return UInt32.random(in: 0...500) }
func decode(_ type: UInt64.Type) throws -> UInt64 { return UInt64.random(in: 0...500) }
func decode<T: Decodable>(_ type: T.Type) throws -> T {
return try T.randomInstance()
}
}
}
extension String {
private static let source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
static func random<G: RandomNumberGenerator>(length: Int, using generator: inout G) -> String {
let range = 0...length
return range
.compactMap { _ in String.source.randomElement() }
.map(String.init)
.joined()
}
static func random(length: Int) -> String {
var g = SystemRandomNumberGenerator()
return String.random(length: length, using: &g)
}
}
struct User: Decodable {
let string: String
let optional: String?
let integer: Int
let boolean: Bool
let array: [Int]
let nested: Pet
}
struct Pet: Decodable {
let name: String
}
let u = try User.randomInstance()
/* Example Output
User(string: "maeDILfJkgnoxubFJQZpb", optional: nil, integer: 94, boolean: true, array: [34], nested: __lldb_expr_78.Pet(name: "EwZolDJsseaLaahYCvdjy"))
User(string: "DzVphWEYBWHSAhuRrwvYN", optional: Optional("sKmTPmlbdBIgExiFnRmGl"), integer: 397, boolean: false, array: [], nested: __lldb_expr_78.Pet(name: "aMqWeAaPKMszPrLClqBNP"))
User(string: "GNOoLQLwCdGASCpcIijhh", optional: nil, integer: 237, boolean: true, array: [179, 76], nested: __lldb_expr_78.Pet(name: "HzHPqpscGwxxqrRdteaYi"))
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.