{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- |
-- Copyright: © 2018-2020 IOHK
-- License: Apache-2.0
--
-- Utility function for making test suites pass on Windows.

module Test.Utils.Windows
    ( skipOnWindows
    , pendingOnWindows
    , pendingOnWine
    , whenWindows
    , isWindows
    , nullFileName
    , getIsWine
    ) where

import Prelude

import Control.Exception
    ( IOException, handle, throwIO )
import Control.Monad
    ( when )
import System.Exit
    ( ExitCode (..) )
import System.Info
    ( os )
import System.Process
    ( readProcessWithExitCode )
import Test.Hspec.Core.Spec
    ( ResultStatus (..), pendingWith )
import Test.Hspec.Expectations
    ( Expectation, HasCallStack )

skipOnWindows :: HasCallStack => String -> Expectation
skipOnWindows :: String -> Expectation
skipOnWindows String
_reason = Expectation -> Expectation
whenWindows (Expectation -> Expectation) -> Expectation -> Expectation
forall a b. (a -> b) -> a -> b
$ ResultStatus -> Expectation
forall e a. Exception e => e -> IO a
throwIO ResultStatus
Success

pendingOnWindows :: HasCallStack => String -> Expectation
pendingOnWindows :: String -> Expectation
pendingOnWindows String
reason = Expectation -> Expectation
whenWindows (Expectation -> Expectation) -> Expectation -> Expectation
forall a b. (a -> b) -> a -> b
$ HasCallStack => String -> Expectation
String -> Expectation
pendingWith String
reason

pendingOnWine :: HasCallStack => String -> Expectation
pendingOnWine :: String -> Expectation
pendingOnWine String
reason = Expectation -> Expectation
whenWindows (Expectation -> Expectation) -> Expectation -> Expectation
forall a b. (a -> b) -> a -> b
$ do
    Bool
wine <- IO Bool
getIsWine
    Bool -> Expectation -> Expectation
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
wine (Expectation -> Expectation) -> Expectation -> Expectation
forall a b. (a -> b) -> a -> b
$ HasCallStack => String -> Expectation
String -> Expectation
pendingWith String
reason

whenWindows :: IO () -> IO ()
whenWindows :: Expectation -> Expectation
whenWindows = Bool -> Expectation -> Expectation
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
isWindows

isWindows :: Bool
isWindows :: Bool
isWindows = String
os String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"mingw32"

-- | Use the presence of @winepath.exe@ to detect when running tests under Wine.
getIsWine :: IO Bool
getIsWine :: IO Bool
getIsWine = (IOException -> IO Bool) -> IO Bool -> IO Bool
forall e a. Exception e => (e -> IO a) -> IO a -> IO a
handle (\(IOException
_ :: IOException) -> Bool -> IO Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False) (IO Bool -> IO Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ do
    (ExitCode
code, String
_, String
_) <- String -> [String] -> String -> IO (ExitCode, String, String)
readProcessWithExitCode String
"winepath" [String
"--version"] String
forall a. Monoid a => a
mempty
    Bool -> IO Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExitCode
code ExitCode -> ExitCode -> Bool
forall a. Eq a => a -> a -> Bool
== ExitCode
ExitSuccess)

nullFileName :: FilePath
nullFileName :: String
nullFileName = if Bool
isWindows then String
"NUL" else String
"/dev/null"