packages feed

free-alacarte-1.0.0.7: test/Free/AlaCarte/Test.hs

module Free.AlaCarte.Test where

import Data.Text qualified as T
import Free.AlaCarte
import Relude
import Test.Hspec

data FileSystem a
  = MyReadFile FilePath (Either UnicodeException Text -> a)
  | MyWriteFile FilePath Text a
  deriving (Functor)

instance Exec FileSystem where
  execAlgebra (MyReadFile path next) = do
    rawFileContents <- readFileBS path
    next (decodeUtf8' rawFileContents)
  execAlgebra (MyWriteFile path fileContents next) = do
    _ <- writeFileText path fileContents
    next

myReadFile :: (FileSystem :<: f) => FilePath -> Free f (Either UnicodeException Text)
myReadFile path = injectFree (MyReadFile path Pure)

myWriteFile :: (FileSystem :<: f) => FilePath -> Text -> Free f ()
myWriteFile path fileContents = injectFree (MyWriteFile path fileContents (Pure ()))

data Logger a = LogInfo Text a deriving (Functor)

instance Exec Logger where
  execAlgebra (LogInfo message next) = putTextLn message >> next

logInfo :: (Logger :<: f) => Text -> Free f ()
logInfo message = injectFree (LogInfo message (Pure ()))

freealacarteSpec :: SpecWith ()
freealacarteSpec = do
  describe "Free a la Carte" $ do
    describe "using the FileSystem free monad" $ do
      it "can read from file successfully " $ do
        fileContents <- exec @FileSystem $ myReadFile "./resources/test/file-0.txt"
        second T.strip fileContents `shouldBe` Right "Free a la Carte"
      it "can write to file successfully" $ do
        exec @FileSystem $ myWriteFile "./resources/test/some-test-file.txt" "Free a la Carte"
    describe "using the Logger free monad" $ do
      it "can log to stdout" $ do
        exec @Logger $ logInfo "Free a la Carte"
    describe "using FileSystem :+: Logger monads" $ do
      it "can read a file's contents to stdout" $ do
        exec @(FileSystem :+: Logger) $ readFileContentsToStdout "./resources/test/file-0.txt"

readFileContentsToStdout :: (Logger :<: f, FileSystem :<: f) => FilePath -> Free f ()
readFileContentsToStdout path = do
  maybeFileContents <- myReadFile path
  either (logInfo . T.pack . show) logInfo maybeFileContents