Skip to content

justeattakeaway/Genything

Repository files navigation

Genything

Genything

Swift: 5.0 Platforms: iOS – tvOS – watchOS – macOS Cocoapods Compatible Swift Package Manager Compatible

Genything - Generate Anything

Genything is a library dedicated to easy and composable generation of random data, no matter how complex.

Genything can be combined with Trickery which provides a growing library of pre-made generators which mock real-world information.

Both of these libraries may be used for code testing, rapid prototyping, demo applications, ui testing, and much more. Be creative!

Why use Genything?

  • We do not include a dependency on XCTest
  • Controllable randomness that's deterministic by default
    • Produce the same results on CI, your colleagues machine, and your own
  • You can use these generators for anything!
    • Create dummy data for your example apps or to rapidly prototype features
    • Use them in your SwiftUI previews to rapidly discover edge cases
    • Run your screenshot tests with easy-to-use and predictable data
    • Use your generators to unit test with Property Based Testing
  • High test coverage
  • 100% Documented

Generator

The Generator is the core of Genything.

public protocol Generator {
    associatedtype T
    func next(_ randomSource: RandomSource) -> T
}

It defines a type with a function capable of generating values using a RandomSource. The RandomSource is used to track and mutate any RandomNumberGenerator instance, allowing you to control just how much random you would like.

A generator of bools might look like this:

struct BoolGenerator: Generator {
    func next(_ randomSource: RandomSource) -> T {
        Bool.random(using: &randomSource.rng)
    }
}

or

AnyGenerator<Bool> { randomSource in
    Bool.random(using: &randomSource.rng)
}

Or, we can take advantage of Genything's arbitrary conformance for most standard Swift types (including Bool)

Bool.arbitrary

Genything provides numerous ways to create your own Generators under the Generators namespace, and the Generator type is extended by many operators which you can use to further mutate and control the resulting generator.

Arbitrary

The Arbitary protocol allows a Type to define a generator suitable for generating all of it's values.

Take Swift's Bool as example, it's Arbitrary is defined as:

extension Bool: Arbitrary {
    public static var arbitrary: AnyGenerator<Bool> {
        [true, false].arbitrary
    }
}

We can now use this definition automatically when we are composing a more complex arbitrary type:

struct Foo {
  let bar: Bool
  // ...
}

extension Transaction: Arbitrary {
    public static var arbitrary: AnyGenerator<Bool> {
        Gen.compose { generate in
          Foo(
            bar: generate(), // Will return true/false like a coin-flip for each generated value
            //...
          )
        }
    }
}

These can then be used for invariant tests, to stub an API response, as preview data, etc...

Trickery

Genything comes together with Trickery, a collection of generators suitable for producing pseudo-realistic data according to real-world-conditions rather than those enforced only by the type.

Consider a phone number. A phone number of type String has rules about length, formatting, allowable characters. Whereas the arbitrary type String contains contains at most a definition of it's length

GenythingTest

Genything provides two extensions for XCTestCase which we suggest that you use as your primary method for property testing.

  • testAll(generator:config:file:line:body)
  • testAllSatisfy(generator:config:file:line:predicate)

Examples

Checkout out our Playground guide

Mixins

Genything is happy when combined with other open source libraries!

Generate arbitrary SFSymbols with SFSafeSymbols

Generate any SF Symbol

import SFSafeSymbols

let sfSymbolGen: AnyGenerator<SFSymbol> = SFSymbol.arbitrary.map { $0.rawValue }

Installation

Cocoapods

pod 'Genything'
pod 'Trickery' # Optional library of realistic fake data (Fake)
pod 'GenythingTest' # Optional extensions for property testing (testAll, testAllSatisfy)

Swift Package Manager

Create a Package.swift file in your root directory and add:

dependencies: [
    .package(url: "https://github.com/justeattakeaway/genything.git", .upToNextMajor(from: "1.0.0"))
]

Then add the packages you want to:

  • General -> "Frameworks and Libraries", for an application of framework target
  • Build Phases -> "Link Binary With Libraries", for a test target

Credits

The Genything project is owned and maintained by SkipTheDishes, a Just Eat Takeaway.com subsidiary.

Contributing

Please read the Contribution Guide

Inspiration

Genything stands on the shoulder of giants. Please check out these other libraries and resources!

License

See: License

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/