module Cardano.Wallet.CoinSelection.Gen
    ( coarbitraryWalletUTxO
    , genWalletUTxO
    , genWalletUTxOFunction
    , genWalletUTxOLargeRange
    , shrinkWalletUTxO
    )
    where

import Prelude

import Cardano.Wallet.CoinSelection
    ( WalletUTxO (..) )
import Cardano.Wallet.Primitive.Types.Address.Gen
    ( genAddress, shrinkAddress )
import Cardano.Wallet.Primitive.Types.Tx.Gen
    ( genTxIn, genTxInLargeRange, shrinkTxIn )
import Generics.SOP
    ( NP (..) )
import Test.QuickCheck
    ( Gen, coarbitrary )
import Test.QuickCheck.Extra
    ( genFunction, genSized2, genericRoundRobinShrink, (<:>), (<@>) )

--------------------------------------------------------------------------------
-- Wallet UTxO identifiers chosen according to the size parameter
--------------------------------------------------------------------------------

coarbitraryWalletUTxO :: WalletUTxO -> Gen a -> Gen a
coarbitraryWalletUTxO :: WalletUTxO -> Gen a -> Gen a
coarbitraryWalletUTxO = String -> Gen a -> Gen a
forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary (String -> Gen a -> Gen a)
-> (WalletUTxO -> String) -> WalletUTxO -> Gen a -> Gen a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WalletUTxO -> String
forall a. Show a => a -> String
show

genWalletUTxO :: Gen WalletUTxO
genWalletUTxO :: Gen WalletUTxO
genWalletUTxO = (TxIn -> Address -> WalletUTxO) -> (TxIn, Address) -> WalletUTxO
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry TxIn -> Address -> WalletUTxO
WalletUTxO ((TxIn, Address) -> WalletUTxO)
-> Gen (TxIn, Address) -> Gen WalletUTxO
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen TxIn -> Gen Address -> Gen (TxIn, Address)
forall a b. Gen a -> Gen b -> Gen (a, b)
genSized2 Gen TxIn
genTxIn Gen Address
genAddress

shrinkWalletUTxO :: WalletUTxO -> [WalletUTxO]
shrinkWalletUTxO :: WalletUTxO -> [WalletUTxO]
shrinkWalletUTxO = NP (I -.-> []) '[TxIn, Address] -> WalletUTxO -> [WalletUTxO]
forall a (xs :: [*]).
(Generic a, GFrom a, GTo a, GCode a ~ '[xs]) =>
NP (I -.-> []) xs -> a -> [a]
genericRoundRobinShrink
    (NP (I -.-> []) '[TxIn, Address] -> WalletUTxO -> [WalletUTxO])
-> NP (I -.-> []) '[TxIn, Address] -> WalletUTxO -> [WalletUTxO]
forall a b. (a -> b) -> a -> b
<@> TxIn -> [TxIn]
shrinkTxIn
    (TxIn -> [TxIn])
-> NP (I -.-> []) '[Address] -> NP (I -.-> []) '[TxIn, Address]
forall x (xs :: [*]).
(x -> [x]) -> NP (I -.-> []) xs -> NP (I -.-> []) (x : xs)
<:> Address -> [Address]
shrinkAddress
    (Address -> [Address])
-> NP (I -.-> []) '[] -> NP (I -.-> []) '[Address]
forall x (xs :: [*]).
(x -> [x]) -> NP (I -.-> []) xs -> NP (I -.-> []) (x : xs)
<:> NP (I -.-> []) '[]
forall k (a :: k -> *). NP a '[]
Nil

genWalletUTxOFunction :: Gen a -> Gen (WalletUTxO -> a)
genWalletUTxOFunction :: Gen a -> Gen (WalletUTxO -> a)
genWalletUTxOFunction = (WalletUTxO -> Gen a -> Gen a) -> Gen a -> Gen (WalletUTxO -> a)
forall a b. (a -> Gen b -> Gen b) -> Gen b -> Gen (a -> b)
genFunction WalletUTxO -> Gen a -> Gen a
forall a. WalletUTxO -> Gen a -> Gen a
coarbitraryWalletUTxO

--------------------------------------------------------------------------------
-- Wallet UTxO identifiers chosen from a large range
--------------------------------------------------------------------------------

genWalletUTxOLargeRange :: Gen WalletUTxO
genWalletUTxOLargeRange :: Gen WalletUTxO
genWalletUTxOLargeRange = TxIn -> Address -> WalletUTxO
WalletUTxO (TxIn -> Address -> WalletUTxO)
-> Gen TxIn -> Gen (Address -> WalletUTxO)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen TxIn
genTxInLargeRange Gen (Address -> WalletUTxO) -> Gen Address -> Gen WalletUTxO
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Address
genAddress