Skip to content

Commit

Permalink
test CIP-25 parsing of token names
Browse files Browse the repository at this point in the history
  • Loading branch information
bjornkihlberg committed Mar 21, 2023
1 parent c8f4889 commit a2408f2
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 5 deletions.
1 change: 1 addition & 0 deletions marlowe-runtime/marlowe-runtime.cabal
Expand Up @@ -572,6 +572,7 @@ test-suite marlowe-runtime-test
, time
, tx-api
, typed-protocols
, vector
build-tool-depends: hspec-discover:hspec-discover
ghc-options: -threaded

Expand Down
Expand Up @@ -6,18 +6,22 @@ module Language.Marlowe.Runtime.Transaction.ApiSpec
( spec
) where

import Language.Marlowe.Runtime.Transaction.Api (CIP25Metadata(..), CIP25MetadataLabel(..))
import Language.Marlowe.Runtime.Transaction.Api (CIP25Metadata(..), CIP25MetadataDetails(..), CIP25MetadataLabel(..))

import Control.Arrow ((&&&))
import Control.Arrow (Arrow(second), (&&&))
import qualified Data.Aeson as Aeson
import qualified Data.Aeson.Key as Aeson.Key
import qualified Data.Aeson.KeyMap as Aeson.KeyMap
import qualified Data.ByteString.Lazy.Char8 as BL
import Data.Coerce (coerce)
import Data.Map (Map)
import qualified Data.Map as Map
import qualified Data.Maybe as Maybe
import Data.String (fromString)
import Data.Text (Text)
import qualified Data.Text.Encoding as Text.Encoding
import Language.Marlowe.Runtime.ChainSync.Api (PolicyId(PolicyId))
import qualified Data.Vector as Vector
import Language.Marlowe.Runtime.ChainSync.Api (PolicyId(PolicyId), TokenName(TokenName))
import Test.Hspec (Spec, it, shouldBe, shouldThrow)
import qualified Test.Hspec as Hspec
import Test.Hspec.QuickCheck (prop)
Expand All @@ -39,12 +43,57 @@ TODO CIP25Metadata -> Metadata procedure
mkPolicyId :: Text -> PolicyId
mkPolicyId = coerce Text.Encoding.encodeUtf8

mkTokenName :: Text -> TokenName
mkTokenName = coerce Text.Encoding.encodeUtf8

mkKey :: Text -> Aeson.Key
mkKey = Aeson.Key.fromText

base16EncodedTextGen :: Int -> Gen Text
base16EncodedTextGen n = fromString <$> Gen.vectorOf n (Gen.elements $ ['0' .. '9'] <> ['a' .. 'f'])

tokenNameJSONRelationGen :: Gen (TokenName, Aeson.Key)
tokenNameJSONRelationGen = do
((*2) -> n) <- Gen.chooseInt (0, 32)
(mkTokenName &&& mkKey) <$> base16EncodedTextGen n

cddlStringGen :: Gen Text
cddlStringGen = do
n <- Gen.chooseInt (0, 64)
fromString <$> Gen.vectorOf n Gen.arbitrary

metadataDetailsJSONRelationGen :: Gen (CIP25MetadataDetails, Aeson.Value)
metadataDetailsJSONRelationGen = do
name :: Text <- fromString <$> Gen.arbitrary
let nameJSON = Aeson.String name
(image, imageJSON) <- Gen.oneof [image0JSONRelationGen, image1JSONRelationGen, imagemJSONRelationGen]
let mediaType = Nothing
description = []
files = []
json = Aeson.Object
[ ("name", nameJSON)
, ("image", imageJSON)
]
pure (CIP25MetadataDetails {..}, json)
where
image0JSONRelationGen :: Gen ([Text], Aeson.Value)
image0JSONRelationGen = pure ([], Aeson.Array [])
image1JSONRelationGen :: Gen ([Text], Aeson.Value)
image1JSONRelationGen = ((:[]) &&& Aeson.String) <$> cddlStringGen
imagemJSONRelationGen :: Gen ([Text], Aeson.Value)
imagemJSONRelationGen = do
n <- Gen.chooseInt (2, 100)
second (Aeson.Array . Vector.fromList) . unzip <$> Gen.vectorOf n
((id &&& Aeson.String) <$> cddlStringGen)

tokenDetailsJSONRelationGen :: Gen (Map TokenName CIP25MetadataDetails, Aeson.Value)
tokenDetailsJSONRelationGen = do
(tokenDetails, tokenDetailsJSON) <- unzip <$> Gen.listOf do
(tokenName, tokenNameJSON) <- tokenNameJSONRelationGen
(metadataDetails, metadataDetailsJSON) <- metadataDetailsJSONRelationGen
pure ((tokenName, metadataDetails), (tokenNameJSON, metadataDetailsJSON))
pure (Map.fromList tokenDetails, Aeson.Object $ Aeson.KeyMap.fromList tokenDetailsJSON)

spec :: Spec
spec = do
Hspec.fdescribe "CIP-25 Metadata" do
Expand Down Expand Up @@ -102,15 +151,30 @@ spec = do
, ("version", Aeson.Number 2)
])]
pure $ actual `shouldBe` expected
it "Parses TokenName as raw byte string" Hspec.pending
prop "Parses TokenName as raw byte string" do
((* 2) -> n) <- Gen.chooseInt (0, 32)
(policyIdKey, policyId) <- (mkKey &&& mkPolicyId) <$> base16EncodedTextGen n
(tokenDetails, tokenDetailsJSON) <- tokenDetailsJSONRelationGen
let actual :: Either String CIP25Metadata
actual = Aeson.eitherDecode' $ Aeson.encode $
Aeson.Object [("721", Aeson.Object
[ (policyIdKey, tokenDetailsJSON)
, ("version", Aeson.Number 2)
])]
expected :: Either String CIP25Metadata
expected = Right $ CIP25Metadata $ CIP25MetadataLabel
[(policyId, tokenDetails)] (Just 2)
pure $ actual `shouldBe` expected
it "Serializes TokenName as raw byte string" Hspec.pending
it "Interprets version 2 as version 2" Hspec.pending
it "Rejects PolicyId longer than 64 bytes" Hspec.pending
it "Rejects TokenName longer than 64 bytes" Hspec.pending
Hspec.describe "version 1 & 2 common" do
it "rejects invalid image identifiers" Hspec.pending
it "Ignores <other_properties>" Hspec.pending
it "Reorganizes strings into maximum 64 length strings" Hspec.pending
it "Rejects invalid version values" Hspec.pending
it "Rejects when missing meta_details properties" Hspec.pending
it "Rejects when missing files_details properties" Hspec.pending
it "Serializes 0 files_details.src into [] representation" Hspec.pending
it "Serializes 1 files_details.src into 1 representation" Hspec.pending
it "Serializes * files_details.src into [*] representation" Hspec.pending
Expand Down

0 comments on commit a2408f2

Please sign in to comment.