Skip to content

Instantly share code, notes, and snippets.

@hslatman
Forked from IanKeen/Decodable+Random.swift
Created October 6, 2018 15:57
Show Gist options
  • Save hslatman/f538c9594e1a0ba32d76d89efeb33a4d to your computer and use it in GitHub Desktop.
Save hslatman/f538c9594e1a0ba32d76d89efeb33a4d to your computer and use it in GitHub Desktop.
Custom Decoder that can be used to create Decodable instances that are populated with random values
public extension Decodable {
static func randomInstance() throws -> Self {
let decoder = _RandomDecoder()
return try Self(from: decoder)
}
}
public class RandomDecoder {
public func decode<T: Decodable>(_: T.Type) throws -> T {
let decoder = _RandomDecoder()
return try T(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 [true, false].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? = Int.random(min: 0, max: 5)
var isAtEnd: Bool { return currentIndex == (count ?? 0) }
private(set) var currentIndex = 0
init() { }
mutating func decodeNil() throws -> Bool {
return [true, false].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 [true, false].random()
}
func decode(_ type: Bool.Type) throws -> Bool {
return [true, false].random()
}
func decode(_ type: String.Type) throws -> String {
return String.random()
}
func decode(_ type: Double.Type) throws -> Double {
return Double(Int.random(min: 0, max: 500))
}
func decode(_ type: Float.Type) throws -> Float {
return Float(Int.random(min: 0, max: 500))
}
func decode(_ type: Int.Type) throws -> Int {
return Int.random(min: 0, max: 500)
}
func decode(_ type: Int8.Type) throws -> Int8 {
return Int8.random(min: 0, max: 100)
}
func decode(_ type: Int16.Type) throws -> Int16 {
return Int16.random(min: 0, max: 500)
}
func decode(_ type: Int32.Type) throws -> Int32 {
return Int32.random(min: 0, max: 500)
}
func decode(_ type: Int64.Type) throws -> Int64 {
return Int64.random(min: 0, max: 500)
}
func decode(_ type: UInt.Type) throws -> UInt {
return UInt.random(min: 0, max: 500)
}
func decode(_ type: UInt8.Type) throws -> UInt8 {
return UInt8.random(min: 0, max: 100)
}
func decode(_ type: UInt16.Type) throws -> UInt16 {
return UInt16.random(min: 0, max: 500)
}
func decode(_ type: UInt32.Type) throws -> UInt32 {
return UInt32.random(min: 0, max: 500)
}
func decode(_ type: UInt64.Type) throws -> UInt64 {
return UInt64.random(min: 0, max: 500)
}
func decode<T: Decodable>(_ type: T.Type) throws -> T {
return try T.randomInstance()
}
}
}
extension FixedWidthInteger {
static func random(min: Self = .min, max: Self = .max) -> Self {
let random = Self(clamping: arc4random())
return (random / 2 % max) + min
}
}
extension RandomAccessCollection where Index: Numeric {
func random() -> Element {
let index = Index(exactly: arc4random() % UInt32(count))!
return self[index]
}
}
extension String {
static func random() -> String {
return String((0...20).map({ _ in Array("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").random() }))
}
}
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