Factories using QuickCheck

You can use derive package to automatically derive QuickCheck's Arbitrary instances.

As this snippet also shows, it may be a wise idea to incorporate some Positive type to not have to re-write positive int generation for every field that's actually positive.

{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}

{-# OPTIONS_GHC -F -pgmFderive -optF-F #-}

import Control.Applicative
import Test.QuickCheck
import Test.QuickCheck (Positive(..))
import Test.QuickCheck.Gen (unGen)
import Data.Text (Text)
import Data.String (fromString, IsString)
import System.Random (getStdGen, StdGen)
import qualified Data.Text as T

data User = User { username :: Text
                 , age :: Int
                 , gender :: Maybe Gender
                 , email :: String
                 , balance :: Balance
                 , workAddress :: Maybe Text
                 , country :: Maybe Country
                 }
          deriving (Eq, Show)

data Gender = Male | Female
            deriving (Eq, Show)

data Balance = Balance Integer Currency
             deriving (Eq, Show)

data Currency = USFishes | BitBones | GoldenIPhones
              deriving (Eq, Show)

data Country = NowhereLand | SomewhereLand
             deriving (Eq, Show)

main :: IO ()
main = do
    g <- getStdGen
    -- let user = unGen userGen g 10
    let user = buildUser g
    putStrLn $ "User is: " ++ (show user)

buildUser :: StdGen -> User
buildUser g = unGen userGen g 20

userGen :: Gen User
userGen = do
    u <- arbitrary :: Gen User
    uid <- positiveIntGen
    age <- positiveIntGen
    return $ u { username = T.append "user_" $ strPositive uid
               , email = buildEmail $ getPositive uid
               , age = getPositive age }

buildEmail :: Int -> String
buildEmail uid = "email_" ++ (show uid) ++ "@example.com"

-- utilities

positiveIntGen :: Gen (Positive Int)
positiveIntGen = arbitrary

strPositive :: (Integral i, IsString s, Show i) => Positive i -> s
strPositive i = fromString . show $ getPositive i

-- I couldn't find this
instance Arbitrary Text where
    arbitrary = fromString <$> (arbitrary :: Gen String)

{-!
deriving instance Arbitrary User
deriving instance Arbitrary Gender
deriving instance Arbitrary Country
deriving instance Arbitrary Currency
deriving instance Arbitrary Balance
!-}