diff --git a/hcat.cabal b/hcat.cabal index 5c52af3..5a28798 100644 --- a/hcat.cabal +++ b/hcat.cabal @@ -6,7 +6,7 @@ cabal-version: 1.12 name: hcat version: 0.0.1.0 -description: Hcat example from the book 'Effective Haskell' +description: HCat example from the book 'Effective Haskell' author: Alexander Kobjolke maintainer: alex@jakalx.net copyright: Alexander Kobjolke 2023 @@ -18,11 +18,16 @@ extra-source-files: library exposed-modules: HCat + HCat.Internal other-modules: Paths_hcat hs-source-dirs: src - ghc-options: -Wall -Wunused-packages + default-extensions: + GHC2021 + BlockArguments + OverloadedStrings + ghc-options: -Wall -Wunused-packages -fdefer-typed-holes build-depends: base >=4.13 && <5 , text @@ -34,9 +39,39 @@ executable hcat Paths_hcat hs-source-dirs: app - ghc-options: -Wall -Wunused-packages + default-extensions: + GHC2021 + BlockArguments + OverloadedStrings + ghc-options: -Wall -Wunused-packages -fdefer-typed-holes build-depends: base >=4.13 && <5 , hcat , text default-language: GHC2021 + +test-suite spec + type: exitcode-stdio-1.0 + main-is: Spec.hs + other-modules: + HCatSpec + Paths_hcat + hs-source-dirs: + test + default-extensions: + GHC2021 + BlockArguments + OverloadedStrings + ghc-options: -Wall -Wunused-packages -fdefer-typed-holes + cpp-options: -DTEST + build-tool-depends: + hspec-discover:hspec-discover + build-depends: + QuickCheck + , base >=4.13 && <5 + , hcat + , hspec + , quickcheck-instances + , quickcheck-text + , text + default-language: Haskell2010 diff --git a/package.yaml b/package.yaml index fa4c58c..cbf8e8f 100644 --- a/package.yaml +++ b/package.yaml @@ -4,7 +4,7 @@ license: MIT author: "Alexander Kobjolke" maintainer: "alex@jakalx.net" copyright: "Alexander Kobjolke 2023" -description: "Hcat example from the book 'Effective Haskell'" +description: "HCat example from the book 'Effective Haskell'" extra-source-files: - README.org @@ -20,6 +20,12 @@ dependencies: ghc-options: - -Wall - -Wunused-packages + - -fdefer-typed-holes + +default-extensions: + - GHC2021 + - BlockArguments + - OverloadedStrings library: source-dirs: src @@ -34,3 +40,17 @@ executables: - hcat verbatim: default-language: GHC2021 + +tests: + spec: + cpp-options: -DTEST + main: Spec.hs + source-dirs: + - test + dependencies: + - hcat + - hspec + - QuickCheck + - quickcheck-instances + - quickcheck-text + build-tools: hspec-discover diff --git a/src/HCat.hs b/src/HCat.hs index 6c44c9b..bdf9251 100644 --- a/src/HCat.hs +++ b/src/HCat.hs @@ -9,27 +9,22 @@ import System.IO (hPutStrLn, stderr) import Control.Exception qualified as Exception import System.IO.Error qualified as IOError -import Data.Text qualified as Text import Data.Text.IO qualified as TextIO -parseArgs :: [String] -> Either String FilePath -parseArgs args = case args of - [] -> Left "No filename given!" - [arg] -> Right arg - _ -> Left "Only a single file is supported" +import HCat.Internal (parseArgs) runHCat :: IO () runHCat = do - fileNameOrError <- parseArgs <$> Env.getArgs - fileName <- eitherToError fileNameOrError - TextIO.readFile fileName >>= TextIO.putStr + fileNameOrError <- parseArgs <$> Env.getArgs + fileName <- eitherToError fileNameOrError + TextIO.readFile fileName >>= TextIO.putStr eitherToError :: Show a => Either a b -> IO b eitherToError = either (Exception.throwIO . IOError.userError . show) return handleError :: IOError -> IO () handleError e = do - hPutStrLn stderr $ "I ran into an issue: " <> show e - + hPutStrLn stderr $ "I ran into an issue: " <> show e + defaultMain :: IO () defaultMain = Exception.catch runHCat handleError diff --git a/src/HCat/Internal.hs b/src/HCat/Internal.hs new file mode 100644 index 0000000..4661a89 --- /dev/null +++ b/src/HCat/Internal.hs @@ -0,0 +1,8 @@ +-- | Internal module in order to facilitate testability. +module HCat.Internal where + +parseArgs :: [String] -> Either String FilePath +parseArgs args = case args of + [] -> Left "No filename given!" + [arg] -> Right arg + _ -> Left "Only a single file is supported" diff --git a/test/HCatSpec.hs b/test/HCatSpec.hs new file mode 100644 index 0000000..82f487b --- /dev/null +++ b/test/HCatSpec.hs @@ -0,0 +1,15 @@ +{-# LANGUAGE GHC2021 #-} + +module HCatSpec (spec) where + +import HCat.Internal (parseArgs) + +import Test.Hspec + +spec :: Spec +spec = do + describe "parseArgs" do + it "returns the filename if given a single argument" do + parseArgs ["foo"] `shouldBe` Right "foo" + parseArgs [] `shouldBe` Left "No filename given!" + parseArgs ["foo", "bar"] `shouldBe` Left "Only a single file is supported" diff --git a/test/Spec.hs b/test/Spec.hs new file mode 100644 index 0000000..a824f8c --- /dev/null +++ b/test/Spec.hs @@ -0,0 +1 @@ +{-# OPTIONS_GHC -F -pgmF hspec-discover #-}