{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Test.Cardano.Ledger.Conway.GovActionReorderSpec (spec) where

import Cardano.Ledger.Conway (Conway)
import Cardano.Ledger.Conway.Governance (
  GovActionState (..),
  actionPriority,
  gasAction,
  reorderActions,
 )
import Data.Foldable (Foldable (..))
import Data.List (sort)
import qualified Data.Sequence.Strict as Seq
import Test.Cardano.Ledger.Binary.Arbitrary ()
import Test.Cardano.Ledger.Common
import Test.Cardano.Ledger.Conway.Arbitrary (ShuffledGovActionStates (..))

spec :: Spec
spec :: Spec
spec =
  forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"Conway governance actions reordering" forall a b. (a -> b) -> a -> b
$ do
    forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"preserves length when reordered" forall a b. (a -> b) -> a -> b
$
      \(StrictSeq (GovActionState Conway)
actions :: Seq.StrictSeq (GovActionState Conway)) ->
        forall a. StrictSeq a -> Int
Seq.length StrictSeq (GovActionState Conway)
actions forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
`shouldBe` forall a. StrictSeq a -> Int
Seq.length (forall era.
StrictSeq (GovActionState era) -> StrictSeq (GovActionState era)
reorderActions @Conway StrictSeq (GovActionState Conway)
actions)
    forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"sorts by priority" forall a b. (a -> b) -> a -> b
$
      \(StrictSeq (GovActionState Conway)
actions :: Seq.StrictSeq (GovActionState Conway)) ->
        forall a. Ord a => [a] -> [a]
sort (forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (forall era. GovAction era -> Int
actionPriority forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall era. GovActionState era -> GovAction era
gasAction @Conway forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StrictSeq (GovActionState Conway)
actions))
          forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
`shouldBe` forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (forall era. GovAction era -> Int
actionPriority forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall era. GovActionState era -> GovAction era
gasAction forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall era.
StrictSeq (GovActionState era) -> StrictSeq (GovActionState era)
reorderActions StrictSeq (GovActionState Conway)
actions)
    forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"same priority actions are not rearranged" forall a b. (a -> b) -> a -> b
$
      \(GovActionState Conway
a :: GovActionState Conway) (StrictSeq (GovActionState Conway)
as :: Seq.StrictSeq (GovActionState Conway)) ->
        let filterPrio :: GovActionState era -> Bool
filterPrio GovActionState era
b = forall era. GovAction era -> Int
actionPriority (forall era. GovActionState era -> GovAction era
gasAction GovActionState Conway
a) forall a. Eq a => a -> a -> Bool
== forall era. GovAction era -> Int
actionPriority (forall era. GovActionState era -> GovAction era
gasAction GovActionState era
b)
         in forall a. (a -> Bool) -> [a] -> [a]
filter forall {era}. GovActionState era -> Bool
filterPrio (forall (t :: * -> *) a. Foldable t => t a -> [a]
toList forall a b. (a -> b) -> a -> b
$ forall era.
StrictSeq (GovActionState era) -> StrictSeq (GovActionState era)
reorderActions @Conway (GovActionState Conway
a forall a. a -> StrictSeq a -> StrictSeq a
Seq.:<| StrictSeq (GovActionState Conway)
as))
              forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
`shouldBe` forall a. (a -> Bool) -> [a] -> [a]
filter forall {era}. GovActionState era -> Bool
filterPrio (forall (t :: * -> *) a. Foldable t => t a -> [a]
toList forall a b. (a -> b) -> a -> b
$ forall era.
StrictSeq (GovActionState era) -> StrictSeq (GovActionState era)
reorderActions (GovActionState Conway
a forall a. a -> StrictSeq a -> StrictSeq a
Seq.:<| StrictSeq (GovActionState Conway)
as))
    forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"orders actions correctly with shuffles" forall a b. (a -> b) -> a -> b
$
      \(ShuffledGovActionStates [GovActionState Conway]
gass [GovActionState Conway]
shuffledGass :: ShuffledGovActionStates Conway) -> do
        forall era.
StrictSeq (GovActionState era) -> StrictSeq (GovActionState era)
reorderActions (forall a. [a] -> StrictSeq a
Seq.fromList [GovActionState Conway]
gass) forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
`shouldBe` forall era.
StrictSeq (GovActionState era) -> StrictSeq (GovActionState era)
reorderActions (forall a. [a] -> StrictSeq a
Seq.fromList [GovActionState Conway]
shuffledGass)