module Test.Falsify.Internal.Generator.Shrinking (
shrinkToOneOf
, firstThen
, shrinkWith
, fromShrinkTree
, toShrinkTree
, toShrinkTreeWithContext
) where
import Prelude hiding (properFraction)
import Data.Word
import qualified Data.Tree as Rose
import Test.Falsify.Internal.Generator
import Test.Falsify.SampleTree (SampleTree(..), Sample(..))
import Test.Falsify.ShrinkTree (ShrinkTree(..))
import qualified Test.Falsify.Context as Context
import qualified Test.Falsify.ShrinkTree as ShrinkTree
shrinkToOneOf :: forall a. a -> [a] -> Gen a
shrinkToOneOf :: forall a. a -> [a] -> Gen a
shrinkToOneOf a
x [a]
xs =
Sample -> a
aux (Sample -> a) -> Gen Sample -> Gen a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Sample -> [Word64]) -> Gen Sample
primWith Sample -> [Word64]
shrinker
where
aux :: Sample -> a
aux :: Sample -> a
aux (NotShrunk Word64
_) = a
x
aux (Shrunk Word64
i) = Word64 -> [a] -> a
index Word64
i [a]
xs
shrinker :: Sample -> [Word64]
shrinker :: Sample -> [Word64]
shrinker (Shrunk Word64
_) = []
shrinker (NotShrunk Word64
_) = (Word64 -> a -> Word64) -> [Word64] -> [a] -> [Word64]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Word64 -> a -> Word64
forall a b. a -> b -> a
const [Word64
0..] [a]
xs
index :: Word64 -> [a] -> a
index :: Word64 -> [a] -> a
index Word64
_ [] = a
x
index Word64
_ [a
y] = a
y
index Word64
0 (a
y:[a]
_) = a
y
index Word64
n (a
_:[a]
ys) = Word64 -> [a] -> a
index (Word64
n Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
1) [a]
ys
firstThen :: forall a. a -> a -> Gen a
firstThen :: forall a. a -> a -> Gen a
firstThen a
x a
y = a
x a -> [a] -> Gen a
forall a. a -> [a] -> Gen a
`shrinkToOneOf` [a
y]
shrinkWith :: forall a. (a -> [a]) -> Gen a -> Gen a
shrinkWith :: forall a. (a -> [a]) -> Gen a -> Gen a
shrinkWith a -> [a]
f Gen a
gen = do
a
x <- Gen a -> Gen a
forall a. Gen a -> Gen a
withoutShrinking Gen a
gen
ShrinkTree a -> Gen a
forall a. ShrinkTree a -> Gen a
fromShrinkTree (ShrinkTree a -> Gen a) -> ShrinkTree a -> Gen a
forall a b. (a -> b) -> a -> b
$ a -> (a -> [a]) -> ShrinkTree a
forall a. a -> (a -> [a]) -> ShrinkTree a
ShrinkTree.unfold a
x a -> [a]
f
fromShrinkTree :: forall a. ShrinkTree a -> Gen a
fromShrinkTree :: forall a. ShrinkTree a -> Gen a
fromShrinkTree = Tree a -> Gen a
go (Tree a -> Gen a)
-> (ShrinkTree a -> Tree a) -> ShrinkTree a -> Gen a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShrinkTree a -> Tree a
forall a. ShrinkTree a -> Tree a
unwrapShrinkTree
where
go :: Rose.Tree a -> Gen a
go :: Tree a -> Gen a
go (Rose.Node a
x [Tree a]
xs) = do
Maybe (Tree a)
next <- Maybe (Tree a)
forall a. Maybe a
Nothing Maybe (Tree a) -> [Maybe (Tree a)] -> Gen (Maybe (Tree a))
forall a. a -> [a] -> Gen a
`shrinkToOneOf` (Tree a -> Maybe (Tree a)) -> [Tree a] -> [Maybe (Tree a)]
forall a b. (a -> b) -> [a] -> [b]
map Tree a -> Maybe (Tree a)
forall a. a -> Maybe a
Just [Tree a]
xs
case Maybe (Tree a)
next of
Maybe (Tree a)
Nothing -> a -> Gen a
forall a. a -> Gen a
forall (m :: * -> *) a. Monad m => a -> m a
return a
x
Just Tree a
x' -> Tree a -> Gen a
go Tree a
x'
toShrinkTree :: forall a. Gen a -> Gen (ShrinkTree a)
toShrinkTree :: forall a. Gen a -> Gen (ShrinkTree a)
toShrinkTree Gen a
gen = ((Execution, a) -> a) -> ShrinkTree (Execution, a) -> ShrinkTree a
forall a b. (a -> b) -> ShrinkTree a -> ShrinkTree b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Execution, a) -> a
forall a b. (a, b) -> b
snd (ShrinkTree (Execution, a) -> ShrinkTree a)
-> Gen (ShrinkTree (Execution, a)) -> Gen (ShrinkTree a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Bool -> (Execution -> Gen a) -> Gen (ShrinkTree (Execution, a))
forall a.
Bool -> (Execution -> Gen a) -> Gen (ShrinkTree (Execution, a))
toShrinkTreeWithContext Bool
False (Gen a -> Execution -> Gen a
forall a b. a -> b -> a
const Gen a
gen)
toShrinkTreeWithContext :: forall a.
Bool
-> (Context.Execution -> Gen a)
-> Gen (ShrinkTree (Context.Execution, a))
toShrinkTreeWithContext :: forall a.
Bool -> (Execution -> Gen a) -> Gen (ShrinkTree (Execution, a))
toShrinkTreeWithContext Bool
includeFinal Execution -> Gen a
gen = do
Seed
initSeed <- Execution -> SampleTree -> Seed
Seed Execution
Context.Initial (SampleTree -> Seed) -> Gen SampleTree -> Gen Seed
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen SampleTree
captureLocalTree
ShrinkTree (Execution, a) -> Gen (ShrinkTree (Execution, a))
forall a. a -> Gen a
forall (m :: * -> *) a. Monad m => a -> m a
return (ShrinkTree (Execution, a) -> Gen (ShrinkTree (Execution, a)))
-> ShrinkTree (Execution, a) -> Gen (ShrinkTree (Execution, a))
forall a b. (a -> b) -> a -> b
$ Tree (Execution, a) -> ShrinkTree (Execution, a)
forall a. Tree a -> ShrinkTree a
WrapShrinkTree (Tree (Execution, a) -> ShrinkTree (Execution, a))
-> Tree (Execution, a) -> ShrinkTree (Execution, a)
forall a b. (a -> b) -> a -> b
$ (Seed -> ((Execution, a), [Seed])) -> Seed -> Tree (Execution, a)
forall b a. (b -> (a, [b])) -> b -> Tree a
Rose.unfoldTree Seed -> ((Execution, a), [Seed])
aux Seed
initSeed
where
aux :: Seed -> ((Context.Execution, a), [Seed])
aux :: Seed -> ((Execution, a), [Seed])
aux seed :: Seed
seed@Seed{Execution
seedContext :: Execution
seedContext :: Seed -> Execution
seedContext, SampleTree
seedSampleTree :: SampleTree
seedSampleTree :: Seed -> SampleTree
seedSampleTree} =
case Gen a -> SampleTree -> (a, [SampleTree])
forall a. Gen a -> SampleTree -> (a, [SampleTree])
runGen (Execution -> Gen a
gen Execution
seedContext) SampleTree
seedSampleTree of
(a
a, [SampleTree]
shrunk) -> ((Execution
seedContext, a
a), Seed -> [SampleTree] -> [Seed]
nextSeed Seed
seed [SampleTree]
shrunk)
nextSeed :: Seed -> [SampleTree] -> [Seed]
nextSeed :: Seed -> [SampleTree] -> [Seed]
nextSeed Seed{Execution
seedContext :: Seed -> Execution
seedContext :: Execution
seedContext, SampleTree
seedSampleTree :: Seed -> SampleTree
seedSampleTree :: SampleTree
seedSampleTree} [SampleTree]
shrunk =
case Execution
seedContext of
Execution
Context.Initial ->
case [SampleTree]
shrunk of
[] | Bool
includeFinal -> [Execution -> SampleTree -> Seed
Seed (Word -> Execution
Context.Final Word
0) SampleTree
seedSampleTree]
[SampleTree]
_ -> (SampleTree -> Seed) -> [SampleTree] -> [Seed]
forall a b. (a -> b) -> [a] -> [b]
map (Execution -> SampleTree -> Seed
Seed (Execution -> SampleTree -> Seed)
-> Execution -> SampleTree -> Seed
forall a b. (a -> b) -> a -> b
$ Word -> Execution
Context.Shrinking Word
0) [SampleTree]
shrunk
Context.Shrinking Word
i ->
case [SampleTree]
shrunk of
[] | Bool
includeFinal -> [Execution -> SampleTree -> Seed
Seed (Word -> Execution
Context.Final (Word -> Execution) -> Word -> Execution
forall a b. (a -> b) -> a -> b
$ Word -> Word
forall a. Enum a => a -> a
succ Word
i) SampleTree
seedSampleTree]
[SampleTree]
_ -> (SampleTree -> Seed) -> [SampleTree] -> [Seed]
forall a b. (a -> b) -> [a] -> [b]
map (Execution -> SampleTree -> Seed
Seed (Execution -> SampleTree -> Seed)
-> Execution -> SampleTree -> Seed
forall a b. (a -> b) -> a -> b
$ Word -> Execution
Context.Shrinking (Word -> Execution) -> Word -> Execution
forall a b. (a -> b) -> a -> b
$ Word -> Word
forall a. Enum a => a -> a
succ Word
i) [SampleTree]
shrunk
Context.Final Word
_ ->
[]
data Seed = Seed{
Seed -> Execution
seedContext :: Context.Execution
, Seed -> SampleTree
seedSampleTree :: SampleTree
}