add tests for governor mutation

This commit is contained in:
Hongrui Fang 2022-07-20 20:44:20 +08:00
parent c450e1252d
commit eb407b98c4
No known key found for this signature in database
GPG key ID: 1E0454204FC7D755
6 changed files with 329 additions and 64 deletions

View file

@ -0,0 +1,264 @@
module Sample.Governor.Mutate (
-- * Testing Utilities
GovernorOutputDatumValidity (..),
GATValidity (..),
GovernorParameters (..),
MockEffectParameters (..),
ParameterBundle (..),
-- * Testing Utilities
Validity (..),
mutate,
mkTestCase,
-- * Parameters Bundles
totallyValidBundle,
invalidBundles,
) where
import Agora.Effect.NoOp (noOpValidator)
import Agora.Governor (GovernorDatum (..), GovernorRedeemer (MutateGovernor))
import Agora.Governor.Scripts (governorValidator)
import Agora.Proposal (ProposalId (ProposalId), ProposalThresholds (..))
import Agora.Utils (validatorHashToTokenName)
import Data.Default (def)
import Plutarch.Api.V1 (PValidator, mkValidator, validatorHash)
import Plutarch.Context (
BaseBuilder,
buildTxInfoUnsafe,
input,
mint,
output,
pubKey,
script,
withDatum,
withOutRef,
withValue,
)
import PlutusLedgerApi.V1 (
Data,
ScriptContext (ScriptContext),
ScriptPurpose (Spending),
TxInfo,
TxOutRef (TxOutRef),
ValidatorHash,
Value,
toData,
)
import PlutusLedgerApi.V1.Value qualified as Value
import Sample.Shared (
authorityTokenSymbol,
govAssetClass,
govValidatorHash,
governor,
minAda,
)
import Test.Specification (SpecificationTree, testValidator)
import Test.Util (pubKeyHashes, sortValue, validatorHashes, withOptional)
--------------------------------------------------------------------------------
data GovernorOutputDatumValidity
= DatumValid
| ValueInvalid
| WrongType
| NoDatum
deriving stock (Bounded, Enum)
data GATValidity
= GATValid
| WrongTag
| NoGAT
deriving stock (Bounded, Enum)
data GovernorParameters = GovernorParameters
{ governorOutputDatumValidity :: GovernorOutputDatumValidity
, stealGST :: Bool
}
data MockEffectParameters = MockEffectParameters
{ gatValidity :: GATValidity
, burnGAT :: Bool
}
data ParameterBundle = ParameterBundle
{ governorParameters :: GovernorParameters
, mockEffectParameters :: MockEffectParameters
}
newtype Validity = Validity {forGovernorValidator :: Bool}
--------------------------------------------------------------------------------
governorInputDatum :: GovernorDatum
governorInputDatum =
GovernorDatum
{ proposalThresholds = def
, nextProposalId = ProposalId 0
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
, maximumProposalsPerStake = 3
}
mkGovernorOutputDatum ::
GovernorOutputDatumValidity ->
Maybe Data
mkGovernorOutputDatum DatumValid =
Just $
toData $
governorInputDatum
{ maximumProposalsPerStake = 4
}
mkGovernorOutputDatum ValueInvalid =
let invalidProposalThresholds =
ProposalThresholds
{ execute = -1
, create = -1
, vote = -1
}
in Just $
toData $
governorInputDatum
{ proposalThresholds =
invalidProposalThresholds
}
mkGovernorOutputDatum WrongType = Just $ toData ()
mkGovernorOutputDatum NoDatum = Nothing
governorRef :: TxOutRef
governorRef =
TxOutRef
"6cce6dfbb697f9e2c4fe9786bb576eb7bd6cbcf7801a4ba13d596006c2d5b957"
1
governorScriptPurpose :: ScriptPurpose
governorScriptPurpose = Spending governorRef
governorRedeemer :: GovernorRedeemer
governorRedeemer = MutateGovernor
mkGovernorBuilder :: GovernorParameters -> BaseBuilder
mkGovernorBuilder ps =
let gst = Value.assetClassValue govAssetClass 1
value = sortValue $ gst <> minAda
gstOutput =
if ps.stealGST
then pubKey $ head pubKeyHashes
else script govValidatorHash
withGSTDatum =
withOptional withDatum $
mkGovernorOutputDatum ps.governorOutputDatumValidity
in mconcat
[ input $
script govValidatorHash
. withDatum governorInputDatum
. withValue value
. withOutRef governorRef
, output $
gstOutput
. withGSTDatum
. withValue value
]
--------------------------------------------------------------------------------
mockEffectValidator :: ClosedTerm PValidator
mockEffectValidator = noOpValidator authorityTokenSymbol
mockEffectValidatorHash :: ValidatorHash
mockEffectValidatorHash = validatorHash $ mkValidator mockEffectValidator
mkGATValue :: GATValidity -> Integer -> Value
mkGATValue NoGAT _ = mempty
mkGATValue v q =
let gatOwner = case v of
GATValid -> mockEffectValidatorHash
WrongTag -> head validatorHashes
in Value.singleton
authorityTokenSymbol
(validatorHashToTokenName gatOwner)
q
mkMockEffectBuilder :: MockEffectParameters -> BaseBuilder
mkMockEffectBuilder ps =
let mkGATValue' = mkGATValue ps.gatValidity
inputValue = mkGATValue' 1
outputValue = inputValue <> burnt
burnt =
if ps.burnGAT
then mkGATValue' (-1)
else mempty
in mconcat
[ mint burnt
, input $
script mockEffectValidatorHash
. withValue inputValue
, output $
script mockEffectValidatorHash
. withValue outputValue
]
--------------------------------------------------------------------------------
mutate :: ParameterBundle -> TxInfo
mutate pb =
buildTxInfoUnsafe $
mconcat
[ mkGovernorBuilder pb.governorParameters
, mkMockEffectBuilder pb.mockEffectParameters
]
--------------------------------------------------------------------------------
mkTestCase :: String -> ParameterBundle -> Validity -> SpecificationTree
mkTestCase name pb (Validity forGov) =
testValidator
forGov
name
(governorValidator governor)
governorInputDatum
governorRedeemer
( ScriptContext
(mutate pb)
governorScriptPurpose
)
--------------------------------------------------------------------------------
totallyValidBundle :: ParameterBundle
totallyValidBundle =
ParameterBundle
{ governorParameters =
GovernorParameters
{ governorOutputDatumValidity = DatumValid
, stealGST = False
}
, mockEffectParameters =
MockEffectParameters
{ gatValidity = GATValid
, burnGAT = True
}
}
--------------------------------------------------------------------------------
invalidBundles :: [ParameterBundle]
invalidBundles = do
gdv <- enumFrom ValueInvalid
sg <- [True, False]
gtv <- enumFrom WrongTag
bgt <- [True, False]
pure $
ParameterBundle
{ governorParameters =
GovernorParameters
{ governorOutputDatumValidity = gdv
, stealGST = sg
}
, mockEffectParameters =
MockEffectParameters
{ gatValidity = gtv
, burnGAT = bgt
}
}

View file

@ -13,17 +13,11 @@ TODO: Add negative test cases, see [#76](https://github.com/Liqwid-Labs/agora/is
-}
module Spec.Governor (specs) where
import Agora.Governor (GovernorDatum (..), GovernorRedeemer (..))
import Agora.Governor.Scripts (governorValidator)
import Agora.Proposal (ProposalId (..))
import Data.Default.Class (Default (def))
import Sample.Governor (mintGATs, mutateState)
import Sample.Governor.Initialize qualified as GST
import Sample.Shared qualified as Shared
import Sample.Governor.Mutate qualified as Mutate
import Test.Specification (
SpecificationTree,
group,
validatorSucceedsWith,
)
-- | The SpecificationTree exported by this module.
@ -48,29 +42,21 @@ specs =
]
, group
"validator"
[ validatorSucceedsWith
"GATs minting"
(governorValidator Shared.governor)
( GovernorDatum
def
(ProposalId 5)
def
def
3
)
MintGATs
mintGATs
, validatorSucceedsWith
"mutate governor state"
(governorValidator Shared.governor)
( GovernorDatum
def
(ProposalId 5)
def
def
3
)
MutateGovernor
mutateState
[ group
"mutate"
[ Mutate.mkTestCase
"legal"
Mutate.totallyValidBundle
(Mutate.Validity True)
, group "illegal" $
map
( \b ->
Mutate.mkTestCase
"(negative test)"
b
(Mutate.Validity False)
)
Mutate.invalidBundles
]
]
]