@@ -9,8 +9,8 @@ import Data.Set qualified as Set
9
9
import Hydra.Cardano.Api (AssetId (.. ), AssetName , Coin (.. ), PolicyAssets (.. ), PolicyId , Quantity (.. ), UTxO , selectLovelace , txOutValue , valueToPolicyAssets )
10
10
import Hydra.Tx.Deposit (capUTxO , pickTokensToDeposit , splitTokens )
11
11
import Test.Hydra.Tx.Fixture (testPolicyId )
12
- import Test.Hydra.Tx.Gen (genUTxOSized )
13
- import Test.QuickCheck (Property , chooseInteger , counterexample , (===) , (==>) )
12
+ import Test.Hydra.Tx.Gen (genUTxOSized , genUTxOWithAssetsSized )
13
+ import Test.QuickCheck (Property , chooseInteger , counterexample , cover , elements , forAll , frequency , listOf , oneof , property , (===) , (==>) )
14
14
15
15
spec :: Spec
16
16
spec =
@@ -171,6 +171,10 @@ spec =
171
171
let (valid, invalid) = splitTokens testUTxO tokens
172
172
valid `shouldBe` mempty -- All assets in policy must be valid for policy to be valid
173
173
invalid `shouldBe` tokens
174
+ it " splits multiassets correctly" $
175
+ forAll (genUTxOWithAssetsSized 5 ) $ \ utxo ->
176
+ forAll (prepareAssetMap utxo) $ \ assets ->
177
+ property $ propSplitMultiAssetCorrectly utxo assets
174
178
175
179
describe " property tests" $ do
176
180
prop " preserves all input tokens (completeness)" propPreservesAllTokens
@@ -412,3 +416,58 @@ propMonotonicUTxOAdditions utxo1 utxo2 specifiedTokens =
412
416
in valid1Policies `Set.isSubsetOf` validCombinedPolicies
413
417
& counterexample (" Valid policies in UTxO1: " <> show valid1Policies)
414
418
& counterexample (" Valid policies in combined UTxO: " <> show validCombinedPolicies)
419
+
420
+ propSplitMultiAssetCorrectly :: UTxO -> Map PolicyId PolicyAssets -> Property
421
+ propSplitMultiAssetCorrectly utxo specifiedTokens =
422
+ let toDeposit = pickTokensToDeposit utxo specifiedTokens
423
+ utxoValue = UTxO. totalValue utxo
424
+ utxoPolicyAssets = valueToPolicyAssets utxoValue
425
+ depositAssets = valueToPolicyAssets $ UTxO. totalValue toDeposit
426
+ in all (checkValidTokenInUTxO utxoPolicyAssets) (Map. toList depositAssets)
427
+ & cover 10 (containsPolicies utxoPolicyAssets specifiedTokens) " PolicyId's are completely present in the UTxO"
428
+ & cover 10 (containsAssets utxoPolicyAssets specifiedTokens) " Assets are completely present in the UTxO"
429
+ & cover 1 (Map. null specifiedTokens) " Empty Assets"
430
+ & cover 1 (Map. size specifiedTokens > 5 ) " Assets size > 5"
431
+ & counterexample (" Valid tokens: " <> show toDeposit)
432
+ & counterexample (" UTxO policy assets: " <> show utxoPolicyAssets)
433
+ where
434
+ containsPolicies :: Map PolicyId PolicyAssets -> Map PolicyId PolicyAssets -> Bool
435
+ containsPolicies utxoAssets depositAssets = sort (Map. keys utxoAssets) == sort (Map. keys depositAssets)
436
+
437
+ containsAssets :: Map PolicyId PolicyAssets -> Map PolicyId PolicyAssets -> Bool
438
+ containsAssets utxoAssets depositAssets =
439
+ let deposits = Map. elems depositAssets
440
+ in all (`elem` deposits) (Map. elems utxoAssets)
441
+
442
+ checkValidTokenInUTxO :: Map PolicyId PolicyAssets -> (PolicyId , PolicyAssets ) -> Bool
443
+ checkValidTokenInUTxO utxoAssets (policyId, PolicyAssets requiredAssets) =
444
+ case Map. lookup policyId utxoAssets of
445
+ Nothing -> False
446
+ Just (PolicyAssets availableAssets) ->
447
+ all
448
+ ( \ (assetName, requiredQty) ->
449
+ case Map. lookup assetName availableAssets of
450
+ Nothing -> False
451
+ Just availableQty -> availableQty >= requiredQty
452
+ )
453
+ (Map. toList requiredAssets)
454
+
455
+ prepareAssetMap :: UTxO -> Gen (Map PolicyId PolicyAssets )
456
+ prepareAssetMap utxo = do
457
+ let utxoAssets = valueToPolicyAssets $ UTxO. totalValue utxo
458
+ n <- elements [1 .. Map. size utxoAssets]
459
+ frequency [(1 , randomAssets n utxoAssets), (8 , addRandomAssets), (1 , pure utxoAssets)]
460
+ where
461
+ addRandomAssets :: Gen (Map PolicyId PolicyAssets )
462
+ addRandomAssets = oneof [addRandomAsset, foldr Map. union mempty <$> listOf addRandomAsset]
463
+
464
+ addRandomAsset :: Gen (Map PolicyId PolicyAssets )
465
+ addRandomAsset = do
466
+ policy <- arbitrary
467
+ Map. singleton policy <$> arbitrary
468
+
469
+ randomAssets :: Int -> Map PolicyId PolicyAssets -> Gen (Map PolicyId PolicyAssets )
470
+ randomAssets n assets =
471
+ let assets' = Map. toList assets
472
+ (x, y) = splitAt n assets'
473
+ in oneof [pure $ Map. fromList x, pure $ Map. fromList y, pure $ Map. fromList $ drop n assets', pure $ Map. fromList $ take n assets']
0 commit comments