{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} module Cardano.Address.Script.ParserSpec ( spec ) where import Prelude import Cardano.Address.KeyHash ( KeyHash (..), KeyRole (..) ) import Cardano.Address.Script ( Cosigner (..), Script (..) ) import Cardano.Address.Script.Parser ( requireAllOfParser , requireAnyOfParser , requireAtLeastOfParser , requireCosignerOfParser , requireCosignerOfParser , requireSignatureOfParser , scriptParser ) import Data.ByteString ( ByteString ) import Data.Text ( Text ) import Test.Hspec ( Spec, SpecWith, describe, it, shouldBe ) import Text.ParserCombinators.ReadP ( ReadP, readP_to_S ) import qualified Codec.Binary.Encoding as E import qualified Data.Text as T import qualified Data.Text.Encoding as T spec :: Spec spec = do requireOfParserTests @KeyHash requireSignatureOfParser (kh1,verKeyH1) "requireSignatureOfParser" requireOfParserTests @Cosigner requireCosignerOfParser (cosigner0,cosigner0Txt) "requireCosignerOfParser" requireAllOfParserTests @KeyHash requireSignatureOfParser [(kh1,verKeyH1), (kh2,verKeyH2), (kh3,verKeyH3)] requireAllOfParserTests @Cosigner requireCosignerOfParser [(cosigner0,cosigner0Txt), (cosigner1,cosigner1Txt), (cosigner2,cosigner2Txt)] requireAnyOfParserTests @KeyHash requireSignatureOfParser [(kh1,verKeyH1), (kh2,verKeyH2), (kh3,verKeyH3)] requireAnyOfParserTests @Cosigner requireCosignerOfParser [(cosigner0,cosigner0Txt), (cosigner1,cosigner1Txt), (cosigner2,cosigner2Txt)] requireAtLeastOfParserTests @KeyHash requireSignatureOfParser [(kh1,verKeyH1), (kh2,verKeyH2), (kh3,verKeyH3)] requireAtLeastOfParserTests @Cosigner requireCosignerOfParser [(cosigner0,cosigner0Txt), (cosigner1,cosigner1Txt), (cosigner2,cosigner2Txt)] timelockParserTests @KeyHash requireSignatureOfParser (kh1,verKeyH1) timelockParserTests @Cosigner requireCosignerOfParser (cosigner0,cosigner0Txt) where verKeyH1 = "addr_shared_vkh1zxt0uvrza94h3hv4jpv0ttddgnwkvdgeyq8jf9w30mcs6y8w3nq" :: Text kh1 = KeyHash Payment (unBech32 verKeyH1) verKeyH2 = "addr_shared_vkh1y3zl4nqgm96ankt96dsdhc86vd5geny0wr7hu8cpzdfcqskq2cp" :: Text kh2 = KeyHash Payment (unBech32 verKeyH2) verKeyH3 = "addr_shared_vkh175wsm9ckhm3snwcsn72543yguxeuqm7v9r6kl6gx57h8gdydcd9" :: Text kh3 = KeyHash Payment (unBech32 verKeyH3) script1 txt = "all ["<>txt<>"]" script2 txt = " all [ "<>txt<>" ] " script3 txt1 txt2 = "all ["<>txt1<>", "<>txt2<>"]" script4 txt1 txt2 txt3 = "all ["<>txt1<>", "<>txt2<>","<>txt3<>"]" script5 txt = "any ["<>txt<>"]" script6 txt = " any [ "<>txt<>" ] " script7 txt1 txt2 = "any ["<>txt1<>", "<>txt2<>"]" script8 txt1 txt2 txt3 = "any ["<>txt1<>", "<>txt2<>","<>txt3<>"]" script9 txt1 txt2 txt3 = "any ["<>txt1<>", all ["<>txt2<>","<>txt3<>"]]" script10 txt1 txt2 txt3 = "at_least 1 ["<>txt1<>", "<>txt2<>","<>txt3<>"]" script11 txt1 txt2 txt3 = "at_least 1 ["<>txt1<>", all ["<>txt2<>","<>txt3<>"]]" script12 = "all []" script13 txt = "any ["<>txt<>", all [ ]]" script14 txt = "all ["<>txt<>", active_from 120]" script15 txt = "all ["<>txt<>", active_until 150]" script16 txt = "all ["<>txt<>", active_from 120, active_until 125]" cosigner0Txt = "cosigner#0" :: Text cosigner0 = Cosigner 0 cosigner1Txt = "cosigner#1" :: Text cosigner1 = Cosigner 1 cosigner2Txt = "cosigner#2" :: Text cosigner2 = Cosigner 2 requireOfParserTests :: (Eq a, Show a) => ReadP (Script a) -> (a, Text) -> String -> SpecWith () requireOfParserTests parser (obj, txt) descr = describe (descr <> " : unit tests") $ do valuesParserUnitTest parser txt (RequireSignatureOf obj) valuesParserUnitTest parser (txt <> " ") (RequireSignatureOf obj) valuesParserUnitTest parser (txt <>", ") (RequireSignatureOf obj) valuesParserUnitTest parser (" " <> txt <>", ") (RequireSignatureOf obj) requireAllOfParserTests :: (Eq a, Show a) => ReadP (Script a) -> [(a, Text)] -> SpecWith () requireAllOfParserTests parser objTxts = do let [(obj1, txt1),(obj2, txt2),(obj3, txt3)] = objTxts describe "requireAllOfParser : unit tests" $ do let expected1 = RequireAllOf [ RequireSignatureOf obj1 ] valuesParserUnitTest (requireAllOfParser parser) (script1 txt1) expected1 valuesParserUnitTest (scriptParser parser) (script1 txt1) expected1 valuesParserUnitTest (requireAllOfParser parser) (script2 txt1) expected1 valuesParserUnitTest (scriptParser parser) (script2 txt1) expected1 let expected2 = RequireAllOf [ RequireSignatureOf obj1 , RequireSignatureOf obj2 ] valuesParserUnitTest (requireAllOfParser parser) (script3 txt1 txt2) expected2 valuesParserUnitTest (scriptParser parser) (script3 txt1 txt2) expected2 let expected3 = RequireAllOf [ RequireSignatureOf obj1 , RequireSignatureOf obj2 , RequireSignatureOf obj3 ] valuesParserUnitTest (requireAllOfParser parser) (script4 txt1 txt2 txt3) expected3 valuesParserUnitTest (scriptParser parser) (script4 txt1 txt2 txt3) expected3 let expected4 = RequireAllOf [] valuesParserUnitTest (requireAllOfParser parser) script12 expected4 valuesParserUnitTest (scriptParser parser) script12 expected4 requireAnyOfParserTests :: (Eq a, Show a) => ReadP (Script a) -> [(a, Text)] -> SpecWith () requireAnyOfParserTests parser objTxts = do let [(obj1, txt1),(obj2, txt2),(obj3, txt3)] = objTxts describe "requireAnyOfParser : unit tests" $ do let expected1 = RequireAnyOf [ RequireSignatureOf obj1 ] valuesParserUnitTest (requireAnyOfParser parser) (script5 txt1) expected1 valuesParserUnitTest (scriptParser parser) (script5 txt1) expected1 valuesParserUnitTest (requireAnyOfParser parser) (script6 txt1) expected1 valuesParserUnitTest (scriptParser parser) (script6 txt1) expected1 let expected2 = RequireAnyOf [ RequireSignatureOf obj1 , RequireSignatureOf obj2 ] valuesParserUnitTest (requireAnyOfParser parser) (script7 txt1 txt2) expected2 valuesParserUnitTest (scriptParser parser) (script7 txt1 txt2) expected2 let expected3 = RequireAnyOf [ RequireSignatureOf obj1 , RequireSignatureOf obj2 , RequireSignatureOf obj3 ] valuesParserUnitTest (requireAnyOfParser parser) (script8 txt1 txt2 txt3) expected3 valuesParserUnitTest (scriptParser parser) (script8 txt1 txt2 txt3) expected3 let expected4 = RequireAnyOf [ RequireSignatureOf obj1 , RequireAllOf [ RequireSignatureOf obj2 , RequireSignatureOf obj3 ] ] valuesParserUnitTest (requireAnyOfParser parser) (script9 txt1 txt2 txt3) expected4 valuesParserUnitTest (scriptParser parser) (script9 txt1 txt2 txt3) expected4 let expected5 = RequireAnyOf [ RequireSignatureOf obj1 , RequireAllOf [] ] valuesParserUnitTest (requireAnyOfParser parser) (script13 txt1) expected5 valuesParserUnitTest (scriptParser parser) (script13 txt1) expected5 requireAtLeastOfParserTests :: (Eq a, Show a) => ReadP (Script a) -> [(a, Text)] -> SpecWith () requireAtLeastOfParserTests parser objTxts = do let [(obj1, txt1),(obj2, txt2),(obj3, txt3)] = objTxts describe "requireAtLeastOfParser : unit tests" $ do let expected1 = RequireSomeOf 1 [ RequireSignatureOf obj1 , RequireSignatureOf obj2 , RequireSignatureOf obj3 ] valuesParserUnitTest (requireAtLeastOfParser parser) (script10 txt1 txt2 txt3) expected1 valuesParserUnitTest (scriptParser parser) (script10 txt1 txt2 txt3) expected1 let expected2 = RequireSomeOf 1 [ RequireSignatureOf obj1 , RequireAllOf [ RequireSignatureOf obj2 , RequireSignatureOf obj3 ] ] valuesParserUnitTest (requireAtLeastOfParser parser) (script11 txt1 txt2 txt3) expected2 valuesParserUnitTest (scriptParser parser) (script11 txt1 txt2 txt3) expected2 timelockParserTests :: (Eq a, Show a) => ReadP (Script a) -> (a, Text) -> SpecWith () timelockParserTests parser (obj,txt) = do describe "validFromSlot unit test" $ do let expected = RequireAllOf [ RequireSignatureOf obj , ActiveFromSlot 120 ] valuesParserUnitTest (scriptParser parser) (script14 txt) expected describe "validUntilSlot unit test" $ do let expected = RequireAllOf [ RequireSignatureOf obj , ActiveUntilSlot 150 ] valuesParserUnitTest (scriptParser parser) (script15 txt) expected describe "validUntilSlot and validFromSlot unit test" $ do let expected = RequireAllOf [ RequireSignatureOf obj , ActiveFromSlot 120 , ActiveUntilSlot 125 ] valuesParserUnitTest (scriptParser parser) (script16 txt) expected valuesParserUnitTest :: (Eq s, Show s) => ReadP s -> Text -> s -> SpecWith() valuesParserUnitTest parser inp expected = it title $ do res <- case take 1 $ reverse $ readP_to_S parser (T.unpack inp) of [(res,_rest)] -> pure res err -> error $ "valuesParserUnitTest : "<>show err res `shouldBe` expected where title :: String title = mempty <> " input=" <> show inp -- | Unsafe function to get bech32 data part from test data. unBech32 :: Text -> ByteString unBech32 = either (error "Incorrect bech32 in test data") snd . E.fromBech32 (const id) . T.encodeUtf8