cleveland-0.1.1: morley-test/Test/Printer/Michelson.hs
-- SPDX-FileCopyrightText: 2021 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA
-- TODO [#712]: Remove this next major release
{-# OPTIONS_GHC -Wno-deprecations #-}
module Test.Printer.Michelson
( unit_Roundtrip
, unit_let_macro
, unit_PrettyPrint
, unit_PrintTypedNotes
, unit_PrintSmartParens
, unit_PrintBigDipN
, unit_Views
) where
import Data.Text.IO.Utf8 qualified as Utf8 (readFile)
import Data.Text.Lazy (strip)
import Fmt (pretty)
import Generics.SYB (everywhere, mkT)
import Test.HUnit (Assertion, assertEqual, assertFailure, (@?=))
import Morley.Michelson.Parser (MichelsonSource(..))
import Morley.Michelson.Printer (printSomeContract, printUntypedContract)
import Morley.Michelson.Runtime (parseExpandContractExt)
import Morley.Michelson.Runtime.Import (importUsing, readUntypedContractExt)
import Morley.Michelson.Untyped qualified as U
import Morley.Michelson.Untyped.Instr (ExpandedOp(..))
import Test.Cleveland.Michelson (importSomeContract, importUntypedContract)
import Test.Util.Contracts
import Test.Util.HUnit
-- | Check that contract under the first given file, when parsed and printed
-- back, produces the contract under the second file.
printerTest :: (FilePath, FilePath) -> Assertion
printerTest (srcPath, refPath) = do
checkedContract <- importSomeContract srcPath
targetSrc <- strip . fromStrict <$> Utf8.readFile refPath
assertEqualBuild
("Prettifying " <> srcPath <> " does not match the expected format")
targetSrc
(printSomeContract False checkedContract)
unit_PrintTypedNotes :: Assertion
unit_PrintTypedNotes = do
contracts <- getContractsWithReferences ".tz" (inContractsDir "notes-in-typed-contracts") "ref"
mapM_ printerTest contracts
unit_PrintSmartParens :: Assertion
unit_PrintSmartParens = do
contracts <- getContractsWithReferences ".tz" (inContractsDir "smart-parens") "ref"
mapM_ printerTest contracts
unit_PrintBigDipN :: Assertion
unit_PrintBigDipN = do
contracts <- getContractsWithReferences ".tz" (inContractsDir "big-dip") "ref"
mapM_ printerTest contracts
unit_Views :: Assertion
unit_Views = do
contracts <- getContractsWithReferences ".tz" (inContractsDir "views") "ref"
mapM_ printerTest contracts
unit_PrettyPrint :: Assertion
unit_PrettyPrint = do
contracts <- getContractsWithReferences ".tz" (inContractsDir "pretty") "pretty"
mapM_ prettyTest contracts
where
prettyTest :: (FilePath, FilePath) -> Assertion
prettyTest (srcPath, refPath) = do
contract <- importUntypedContract srcPath
targetSrc <- strip . fromStrict <$> Utf8.readFile refPath
assertEqual
("Prettifying " <> srcPath <> " does not match the expected format")
(printUntypedContract False contract)
targetSrc
assertEqual
("Single line pretty printer output "
<> srcPath <> " contain new lines.")
(find (=='\n') $ printUntypedContract True contract) Nothing
unit_Roundtrip :: Assertion
unit_Roundtrip = do
morleyContractFiles <- getWellTypedMorleyContracts
mapM_ morleyRoundtripPrintTest morleyContractFiles
michelsonContractFiles <- getWellTypedMichelsonContracts
mapM_ michelsonRoundtripPrintTest michelsonContractFiles
where
morleyRoundtripPrintTest :: FilePath -> Assertion
morleyRoundtripPrintTest filePath = do
contract1 <- importUsing readUntypedContractExt filePath
contract2 <- printAndParse filePath contract1
-- We don't expect that `contract1` equals `contract2`,
-- because during printing we lose extra instructions.
assertEqual ("After printing and parsing " <> filePath <>
" is printed differently")
(printUntypedContract True contract1) -- using single line output here
(printUntypedContract True contract2)
michelsonRoundtripPrintTest :: FilePath -> Assertion
michelsonRoundtripPrintTest filePath = do
contract1 <- importUntypedContract filePath
contract2 <- printAndParse filePath contract1
-- We expect `contract1` equals `contract2`.
assertEqual ("After printing and parsing " <> filePath <>
" contracts are different")
(transformContract contract1) (transformContract contract2)
unit_let_macro :: Assertion
unit_let_macro = do
let filePath = inContractsDir "ill-typed/letblock_trivial.mtz"
contract <- printAndParse filePath =<< importUsing readUntypedContractExt filePath
let ops = concatMap U.flattenExpandedOp (U.contractCode contract)
ops @?= [U.CDR U.noAnn U.noAnn, U.UNIT U.noAnn U.noAnn, U.DROP]
printAndParse :: FilePath -> U.Contract -> IO U.Contract
printAndParse fp contract1 =
case parseExpandContractExt (MSFile fp) (toText $ printUntypedContract True contract1) of
Left err ->
assertFailure ("Failed to parse printed " <> fp <> ": " <> pretty err)
Right contract2 -> pure contract2
-- | Remove all `WithSrcEx` from contract code because `SrcPos`es
-- and such stuff can change during printing and parsing
transformContract :: U.Contract -> U.Contract
transformContract = U.mapContractCode transform
where
transform :: ExpandedOp -> ExpandedOp
transform = everywhere $ mkT removeWithSrcEx
removeWithSrcEx :: ExpandedOp -> ExpandedOp
removeWithSrcEx (WithSrcEx _ op) = op
removeWithSrcEx op = op