{- SPDX-FileCopyrightText: 2020 Serokell - - SPDX-License-Identifier: MPL-2.0 -} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} module Test.Utf8.ReadWrite where import Control.DeepSeq (force) import Control.Exception (IOException, evaluate) import Control.Exception.Safe (MonadMask, try) import Control.Monad ((>=>)) import Control.Monad.IO.Class (MonadIO, liftIO) import Data.Text (Text) import GHC.IO.Encoding (utf8) import System.IO (FilePath) import System.IO.Temp (withSystemTempFile) import Hedgehog (Property, (===), forAll, property) import Test.HUnit (Assertion, assertFailure) import qualified Data.Text.IO as T import qualified Data.Text.IO.Utf8 as Utf8 import qualified System.IO as IO import qualified System.IO.Utf8 as Utf8 import qualified Hedgehog.Gen as G import qualified Hedgehog.Range as R -- | Helper that writes Text to a temp file. withTestFile :: (MonadIO m, MonadMask m) => Text -> (FilePath -> m r) -> m r withTestFile t act = withSystemTempFile "utf8.txt" $ \fp h -> do liftIO $ IO.hSetEncoding h utf8 *> T.hPutStr h t *> IO.hClose h act fp -- | Sanity check. unit_standard_readFile_fails :: Assertion unit_standard_readFile_fails = withTestFile str $ \fp -> try (T.readFile fp) >>= \case Right _ -> assertFailure "Standard `readFile` should fail." Left (_ :: IOException) -> pure () where -- We use an escape here because otherwise _both_ tasty-discover -- and hedgehog fail when they are reading this file for their -- discovery or nice error reporting purposes... I know, right? str = "doma\285e" hprop_readFile :: Property hprop_readFile = property $ do str <- forAll $ G.text (R.linear 0 1000) G.unicode str' <- liftIO $ withTestFile str (Utf8.readFile >=> evaluate . force) str === str' hprop_writeFile :: Property hprop_writeFile = property $ do str <- forAll $ G.text (R.linear 0 1000) G.unicode liftIO $ withTestFile str (flip Utf8.writeFile str) hprop_openFile :: Property hprop_openFile = property $ do str <- forAll $ G.text (R.linear 0 1000) G.unicode str' <- liftIO $ withTestFile str $ \fp -> do h <- Utf8.openFile fp IO.ReadMode res <- T.hGetContents h res' <- evaluate . force $ res IO.hClose h pure res' str === str' hprop_withFile :: Property hprop_withFile = property $ do str <- forAll $ G.text (R.linear 0 1000) G.unicode str' <- liftIO $ withTestFile str $ \fp -> Utf8.withFile fp IO.ReadMode $ \h -> do res <- T.hGetContents h res' <- evaluate . force $ res pure res' str === str'