{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

module Test.Sandwich.Contexts.Files.Types (
  askFile
  , askFile'

  , EnvironmentFile(..)
  , HasFile
  , mkFileLabel

  , FileValue
  ) where

import GHC.TypeLits
import Relude
import Test.Sandwich


-- | Retrieve a file context.
askFile :: forall a context m. (MonadReader context m, HasFile context a) => m FilePath
askFile :: forall (a :: Symbol) context (m :: * -> *).
(MonadReader context m, HasFile context a) =>
m FilePath
askFile = Proxy a -> m FilePath
forall (a :: Symbol) context (m :: * -> *).
(MonadReader context m, HasFile context a) =>
Proxy a -> m FilePath
askFile' (forall {k} (t :: k). Proxy t
forall (t :: Symbol). Proxy t
Proxy @a)

-- | Variant of 'askFile' that you can use with a 'Proxy' rather than a type application.
askFile' :: forall a context m. (MonadReader context m, HasFile context a) => Proxy a -> m FilePath
askFile' :: forall (a :: Symbol) context (m :: * -> *).
(MonadReader context m, HasFile context a) =>
Proxy a -> m FilePath
askFile' Proxy a
_ = EnvironmentFile a -> FilePath
forall {k} (a :: k). EnvironmentFile a -> FilePath
unEnvironmentFile (EnvironmentFile a -> FilePath)
-> m (EnvironmentFile a) -> m FilePath
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Label (AppendSymbol "file-" a) (EnvironmentFile a)
-> m (EnvironmentFile a)
forall context (l :: Symbol) a (m :: * -> *).
(HasLabel context l a, MonadReader context m) =>
Label l a -> m a
getContext (forall (a :: Symbol).
Label (AppendSymbol "file-" a) (EnvironmentFile a)
mkFileLabel @a)

-- | A file path to make available to tests.
-- For example, this can be an external binary like "minikube" if a given test context wants
-- to use it to start a Minikube cluster.
-- But you can use this for any kind of file you want to inject into tests.
data EnvironmentFile a = EnvironmentFile { forall {k} (a :: k). EnvironmentFile a -> FilePath
unEnvironmentFile :: FilePath }

-- | Has-* class for asserting a given file is available.
type HasFile context a = HasLabel context (AppendSymbol "file-" a) (EnvironmentFile a)

mkFileLabel :: Label (AppendSymbol "file-" a) (EnvironmentFile a)
mkFileLabel :: forall (a :: Symbol).
Label (AppendSymbol "file-" a) (EnvironmentFile a)
mkFileLabel = Label (AppendSymbol "file-" a) (EnvironmentFile a)
forall {k} (l :: Symbol) (a :: k). Label l a
Label

-- | Shorthand for 'LabelValue's containing 'EnvironmentFile's.
type FileValue file = LabelValue (AppendSymbol "file-" file) (EnvironmentFile file)