content: {-# LANGUAGE ConstraintKinds            #-}
  {-# LANGUAGE DataKinds                  #-}
  {-# LANGUAGE FlexibleContexts           #-}
  {-# LANGUAGE FlexibleInstances          #-}
  {-# LANGUAGE GADTs                      #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE PolyKinds                  #-}
  {-# LANGUAGE RankNTypes                 #-}
  {-# LANGUAGE RebindableSyntax           #-}
  {-# LANGUAGE StandaloneDeriving         #-}
  {-# LANGUAGE TemplateHaskell            #-}
  {-# LANGUAGE TypeFamilies               #-}
  {-# LANGUAGE TypeOperators              #-}
  module Motor.FSM.ReflectionSpec where
  
  import           Prelude
  
  import           Data.Row.Records
  import           Test.Hspec
  
  import           Motor.FSM                  hiding (Add, Delete)
  import           Motor.FSM.Reflection
  import           Motor.FSM.Reflection.Event (Event)
  
  -- * Game Protocol/Machine
  
  data Standing
  data Jumping
  
  class MonadFSM m => Game (m :: Row * -> Row * -> * -> *) where
    type State m :: * -> *
    spawn
      :: Name n
      -> Actions m '[n !+ State m Standing] r ()
    jump
      :: Name n
      -> Actions m '[n := State m Standing !--> State m Jumping] r ()
    land
      :: Name n
      -> Actions m '[n := State m Jumping !--> State m Standing] r ()
    perish
      :: Name n
      -> Actions m '[n !- State m Standing] r ()
  
  reflectEvents ''Game "gameEvents"
  
  spec :: Spec
  spec =
    it "reflects events when using Actions" $
      gameEvents `shouldBe` [ Event "spawn" (Add "Standing")
                            , Event "jump" (Transition "Standing" "Jumping")
                            , Event "land" (Transition "Jumping" "Standing")
                            , Event "perish" (Delete "Standing")
                            ]
  