To facilitate testing, I've made a custom Decoder
called RandomDecoder
which implements all the various decode(_ type:)
methods by returning random numbers, strings and bools. Its UnkeyedContainer
also returns a random count, and decodeNil
randomly makes sure that nullable values are sometimes actually nil.
I works like so:
struct Foo: Codable {
var bar: String
var quz: Double
var fiz: [String]
var lax: Bool?
}
let foos = try [Foo](from: RandomDecoder())
let json = try JSONEncoder().encode(foos)
print(String(data: json, encoding: .utf8)!)
// [{"bar":"O9pjMIz3itWo","quz":101.11795860911604,"fiz":["1hBKQ14WfDF67yy","CGoPftgVIQ8BCDZ","XhLQelYzYHXxji5d","Wdp69iIgpnOv03","1gY7Qq19j"],"lax":true},{"bar":"F9vkgbsB2EJjf3ip","quz":108.47102159207577,"fiz":["QgzzuUu"],"lax":false}]
However, when "decoding" e.g URL
s, I don't want to generate a random string and parse it as a URL, since that almost certainly will generate a non-valid URL. I'd rather provide a hook for types to generate their own random instances, by e.g. conforming to a protocol like RandomInstantiable
. Then URL
could eg. generate randoms paths and add it to "example.com" or something to generate true random URLs.
However, how do I implement the following in a way that works?
func decode<T: Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
if T is RandomInstatiable { // this doesn't work
return T.randomInstance() // T is just Decodable here
else {
return try T(from: RandomDecoder(using: &generator))
}
}