Fakery icon indicating copy to clipboard operation
Fakery copied to clipboard

Support seeded random number generators

Open julasamer opened this issue 4 years ago • 4 comments

Hi!

I've added support for seeded RNG by allowing the passing of any RandomNumberGenerator to Faker.

Caveats:

  • I ignored Swift <= 4.2. It might not compile with the older swift versions; if it does, it won't used the RNG that was passed in. Not sure if dropping support for 4.2 is an option at this point.
  • I didn't write a unit test (I'm not familiar with QuickSpec and don't have more time to spend on this right now).

That being said, you can use this like this:

let faker = Faker(randomNumberGenerator: SomeAdvancedRandomNumberGenerator())

Unfortunately, seeded RNG is somewhat hidden in iOS; my first idea was to use the RNG provided by GameKit:

 import GameKit

 extension GKMersenneTwisterRandomSource: RandomNumberGenerator {}
 let faker = Faker(randomNumberGenerator: GKMersenneTwisterRandomSource(seed: 42))

We need to make GKMersenneTwisterRandomSource conform to RandomNumberGenerator, which is fortunately quite easy. We can then use it as the seeded RNG.

However, this requires that GameKit is available. In the end, I didn't want introduce a GameKit dependency, and the whole thing is overkill anyway for my testing purposes, so I implemented a custom "RNG" which works fine for my case:

public class AdvancedRandomNumberGenerator: RandomNumberGenerator {
    var currentIndex = 0
    
    // chosen by fair dice roll
    // guaranteed to be random
    lazy var randomValues: [UInt64] = [4151371853236615391, 7134936793715064765, 8637388537612094686, ...]
    
    public func next() -> UInt64 {
        currentIndex += 1
        return randomValues[currentIndex % randomValues.count]
    }
}

julasamer avatar Jun 11 '21 09:06 julasamer

Isn't the Swift random API seedable, like UInt64.random(in:)

mrylmz avatar Jul 06 '21 12:07 mrylmz

@mrylmz: That's the API I used. You have to pass something to the in parameter though. That's where the GKMersenneTwisterRandomSource comes in: a seedable RNG. The Swift random API itself doesn't have a seedable RNG afaik, you can just specify some RNG to use.

julasamer avatar Jul 06 '21 13:07 julasamer

Would love to have this! Would be nice to have predictably random mock data for use in tests.

crayment avatar Nov 09 '23 23:11 crayment