packages feed

cuddle-0.5.0.0: test/Test/Codec/CBOR/Cuddle/CDDL/Pretty.hs

{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Test.Codec.CBOR.Cuddle.CDDL.Pretty (
  spec,
) where

import Codec.CBOR.Cuddle.CDDL (
  Assign (..),
  CDDL,
  Group (Group),
  GroupEntry (..),
  GroupEntryVariant (..),
  GrpChoice (..),
  Name (..),
  Rule (..),
  Type0 (..),
  Type1 (..),
  Type2 (..),
  TypeOrGroup (..),
  ValueVariant (..),
  value,
 )
import Codec.CBOR.Cuddle.Pretty ()
import Data.List.NonEmpty (NonEmpty (..))
import Data.Text qualified as T
import Data.TreeDiff (ToExpr (..), prettyExpr)
import Prettyprinter (Pretty (..), defaultLayoutOptions, layoutPretty)
import Prettyprinter.Render.String (renderString)
import Test.Codec.CBOR.Cuddle.CDDL.Gen ()
import Test.HUnit (assertEqual)
import Test.Hspec (Expectation, Spec, describe, it, shouldBe, xit)
import Test.Hspec.QuickCheck (xprop)
import Test.QuickCheck (counterexample)
import Prelude hiding ((/))

prettyPrintsTo :: (Pretty a, ToExpr a) => a -> String -> Expectation
prettyPrintsTo x s = assertEqual (show . prettyExpr $ toExpr x) s rendered
  where
    rendered = renderString (layoutPretty defaultLayoutOptions (pretty x))

t2Name :: Type2
t2Name = T2Name (Name "a" mempty) mempty

t1Name :: Type1
t1Name = Type1 t2Name Nothing mempty

mkType0 :: Type2 -> Type0
mkType0 t2 = Type0 $ Type1 t2 Nothing mempty :| []

spec :: Spec
spec = describe "Pretty printer" $ do
  unitSpec
  qcSpec

qcSpec :: Spec
qcSpec = describe "QuickCheck" $ do
  xprop "CDDL prettyprinter leaves no trailing spaces" $ \(cddl :: CDDL) -> do
    let
      prettyStr = T.pack . renderString . layoutPretty defaultLayoutOptions $ pretty cddl
      stripLines = T.unlines . fmap T.stripEnd . T.lines
    counterexample (show . prettyExpr $ toExpr cddl) $
      prettyStr `shouldBe` stripLines prettyStr

drep :: Rule
drep =
  Rule
    "drep"
    Nothing
    AssignEq
    ( TOGType
        ( Type0
            ( Type1
                ( T2Array
                    ( Group
                        ( GrpChoice
                            [ GroupEntry
                                Nothing
                                mempty
                                (GEType Nothing (Type0 $ Type1 (T2Value . value $ VUInt 0) Nothing mempty :| []))
                            , GroupEntry
                                Nothing
                                mempty
                                (GEType Nothing (Type0 $ Type1 (T2Name "addr_keyhash" Nothing) Nothing mempty :| []))
                            ]
                            mempty
                            :| [ GrpChoice
                                   [ GroupEntry
                                       Nothing
                                       mempty
                                       (GEType Nothing (Type0 $ Type1 (T2Value . value $ VUInt 1) Nothing mempty :| []))
                                   , GroupEntry
                                       Nothing
                                       mempty
                                       (GEType Nothing (Type0 $ Type1 (T2Name "script_hash" Nothing) Nothing mempty :| []))
                                   ]
                                   mempty
                               , GrpChoice
                                   [ GroupEntry
                                       Nothing
                                       mempty
                                       (GEType Nothing (Type0 $ Type1 (T2Value . value $ VUInt 2) Nothing mempty :| []))
                                   ]
                                   mempty
                               , GrpChoice
                                   [ GroupEntry
                                       Nothing
                                       mempty
                                       (GEType Nothing (Type0 $ Type1 (T2Value . value $ VUInt 3) Nothing mempty :| []))
                                   ]
                                   mempty
                               ]
                        )
                    )
                )
                Nothing
                mempty
                :| []
            )
        )
    )
    mempty

unitSpec :: Spec
unitSpec = describe "HUnit" $ do
  describe "Name" $ do
    it "names" $ Name "a" mempty `prettyPrintsTo` "a"
  describe "Type0" $ do
    it "name" $ Type0 (t1Name :| []) `prettyPrintsTo` "a"
  describe "Type1" $ do
    it "name" $ t1Name `prettyPrintsTo` "a"
  describe "Type2" $ do
    it "T2Name" $ t2Name `prettyPrintsTo` "a"
    describe "T2Array" $ do
      let groupEntryName = GroupEntry Nothing mempty $ GERef (Name "a" mempty) Nothing
      it "one element" $
        T2Array (Group (GrpChoice [groupEntryName] mempty :| [])) `prettyPrintsTo` "[a]"
      it "two elements" $
        T2Array
          ( Group
              ( GrpChoice
                  [ GroupEntry Nothing mempty $ GEType Nothing (mkType0 . T2Value . value $ VUInt 1)
                  , groupEntryName
                  ]
                  mempty
                  :| []
              )
          )
          `prettyPrintsTo` "[1, a]"
      it "two elements with comments" $
        T2Array
          ( Group
              ( GrpChoice
                  [ GroupEntry Nothing "one" $ GEType Nothing (mkType0 . T2Value . value $ VUInt 1)
                  , GroupEntry Nothing "two" $ GEType Nothing (mkType0 . T2Value . value $ VUInt 2)
                  ]
                  mempty
                  :| []
              )
          )
          `prettyPrintsTo` "[ 1 ; one\n, 2 ; two\n]"
      it "two elements with multiline comments" $
        T2Array
          ( Group
              ( GrpChoice
                  [ GroupEntry Nothing "first\nmultiline comment" $ GEType Nothing (mkType0 . T2Value . value $ VUInt 1)
                  , GroupEntry Nothing "second\nmultiline comment" $
                      GEType Nothing (mkType0 . T2Value . value $ VUInt 2)
                  ]
                  mempty
                  :| []
              )
          )
          `prettyPrintsTo` "[ 1 ; first\n    ; multiline comment\n, 2 ; second\n    ; multiline comment\n]"
  describe "Rule" $ do
    it "simple assignment" $
      Rule
        (Name "a" mempty)
        Nothing
        AssignEq
        (TOGType (Type0 (Type1 (T2Name (Name "b" mempty) mempty) Nothing mempty :| [])))
        mempty
        `prettyPrintsTo` "a = b"
    xit "drep" $
      drep
        `prettyPrintsTo` "drep = [0, addr_keyhash // 1, script_hash // 2 // 3]"