packages feed

figment-0.2.0.0: test/Figment/Test/Arbitrary.hs

-- | Generators for configuration trees.
module Figment.Test.Arbitrary
  ( genValue
  , genDict
  , genSameShape
  , Shape (..)
  , genShape
  , fill
  ) where

import qualified Data.Map.Strict as Map
import qualified Data.Text as Text
import qualified Data.Vector as Vector
import Test.QuickCheck

import Figment

genKey :: Gen Text.Text
genKey = elements ["a", "b", "c", "d"]

genScalar :: Gen Node
genScalar =
  oneof
    [ pure Null
    , Bool <$> arbitrary
    , Num . Finite . fromIntegral <$> chooseInt (-3, 3)
    , String . Text.pack <$> elements ["x", "y", ""]
    ]

-- | Arbitrary values, with arbitrary (distinguishable) tags.
genValue :: Int -> Gen Value
genValue d = do
  tag <- genTag
  n <-
    if d <= 0
      then genScalar
      else
        frequency
          [ (2, genScalar)
          , (2, Array . Vector.fromList <$> (chooseInt (0, 3) >>= \k -> vectorOf k (genValue (d - 1))))
          , (3, Dict . Map.fromList <$> (chooseInt (0, 3) >>= \k -> vectorOf k ((,) <$> genKey <*> genValue (d - 1))))
          ]
  pure (Value tag n)

genTag :: Gen Tag
genTag = do
  i <- chooseInt (0, 5)
  pure (Tag Nothing Nothing (Just (Pos i i)) Nothing)

genDict :: Int -> Gen Value
genDict d = do
  tag <- genTag
  kvs <- chooseInt (0, 4) >>= \k -> vectorOf k ((,) <$> genKey <*> genValue (d - 1))
  pure (Value tag (Dict (Map.fromList kvs)))

data Shape = SScalar | SArr [Shape] | SDict [(Text.Text, Shape)]
  deriving stock (Show)

genShape :: Int -> Gen Shape
genShape 0 = pure SScalar
genShape d =
  frequency
    [ (2, pure SScalar)
    , (1, SArr <$> (chooseInt (0, 2) >>= \k -> vectorOf k (genShape (d - 1))))
    , (3, SDict . Map.toList . Map.fromList <$> (chooseInt (0, 3) >>= \k -> vectorOf k ((,) <$> genKey <*> genShape (d - 1))))
    ]

-- | A value of the given shape with arbitrary leaves and tags.
fill :: Shape -> Gen Value
fill sh = do
  tag <- genTag
  case sh of
    SScalar -> Value tag <$> genScalar
    SArr xs -> Value tag . Array . Vector.fromList <$> traverse fill xs
    SDict kvs -> Value tag . Dict . Map.fromList <$> traverse (\(k, s) -> (,) k <$> fill s) kvs

genSameShape :: Gen (Value, Value, Value)
genSameShape = do
  sh <- genShape 3
  (,,) <$> fill sh <*> fill sh <*> fill sh