{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BinaryLiterals #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}

module Test.Cardano.Ledger.PlutusSpec (spec) where

import Cardano.Ledger.BaseTypes (
  EpochInterval (..),
  NonNegativeInterval,
  ProtVer (..),
  UnitInterval,
 )
import Cardano.Ledger.Binary.Version (Version)
import Cardano.Ledger.Coin (Coin, CompactForm)
import Cardano.Ledger.Plutus
import Data.Map.Strict (Map)
import Data.Word
import Numeric.Natural (Natural)
import Test.Cardano.Ledger.Common
import Test.Cardano.Ledger.Core.Arbitrary ()
import Test.Cardano.Ledger.Plutus.ExUnits qualified as ExUnits
import Test.Cardano.Ledger.Plutus.ToPlutusData (roundTripPlutusDataSpec)

spec :: Spec
spec :: Spec
spec = do
  Spec
costModelsSpec
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"RoundTrip ToPlutusData" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @Version
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @Word
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @Word8
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @Word16
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @Word32
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @[Word]
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @[Word8]
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @(Map Word Version)
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @Coin
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @(CompactForm Coin)
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @ExUnits
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @Prices
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @Natural
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @UnitInterval
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @EpochInterval
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @NonNegativeInterval
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @ProtVer
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @CostModels
    forall x.
(HasCallStack, Typeable x, Show x, Eq x, Arbitrary x,
 ToPlutusData x) =>
Spec
roundTripPlutusDataSpec @Integer
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"ExUnits" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    Spec
ExUnits.spec

costModelsSpec :: Spec
costModelsSpec :: Spec
costModelsSpec = do
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"CostModels" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> (CostModels -> Map Word8 [Int64] -> IO ()) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"flattenCostModels . mkCostModelsLenient" ((CostModels -> Map Word8 [Int64] -> IO ()) -> Spec)
-> (CostModels -> Map Word8 [Int64] -> IO ()) -> Spec
forall a b. (a -> b) -> a -> b
$ \CostModels
valid Map Word8 [Int64]
unknown -> do
      let cms1Flat :: Map Word8 [Int64]
cms1Flat = CostModels -> Map Word8 [Int64]
flattenCostModels CostModels
valid Map Word8 [Int64] -> Map Word8 [Int64] -> Map Word8 [Int64]
forall a. Semigroup a => a -> a -> a
<> Map Word8 [Int64]
unknown
          cms2Flat :: Map Word8 [Int64]
cms2Flat = Map Word8 [Int64]
unknown Map Word8 [Int64] -> Map Word8 [Int64] -> Map Word8 [Int64]
forall a. Semigroup a => a -> a -> a
<> CostModels -> Map Word8 [Int64]
flattenCostModels CostModels
valid
      CostModels
cms1 <- Map Word8 [Int64] -> IO CostModels
forall (m :: * -> *).
MonadFail m =>
Map Word8 [Int64] -> m CostModels
mkCostModelsLenient Map Word8 [Int64]
cms1Flat
      CostModels
cms2 <- Map Word8 [Int64] -> IO CostModels
forall (m :: * -> *).
MonadFail m =>
Map Word8 [Int64] -> m CostModels
mkCostModelsLenient Map Word8 [Int64]
cms2Flat
      CostModels -> Map Word8 [Int64]
flattenCostModels CostModels
cms1 Map Word8 [Int64] -> Map Word8 [Int64] -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldBe` Map Word8 [Int64]
cms1Flat
      CostModels -> Map Word8 [Int64]
flattenCostModels CostModels
cms2 Map Word8 [Int64] -> Map Word8 [Int64] -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldBe` Map Word8 [Int64]
cms2Flat