packages feed

hi-1.2.0.2: test/FeatureSpec.hs

{-# LANGUAGE ScopedTypeVariables #-}

module FeatureSpec where

import qualified Hi.Cli              as Cli
import           Hi.Directory        (inDirectory)

import           Control.Applicative
import           Control.Exception   (catch, throwIO)
import           Data.Time.Calendar  (toGregorian)
import           Data.Time.Clock     (getCurrentTime, utctDay)
import           Data.Version        (showVersion)
import           SpecHelper
import           System.Directory    (doesDirectoryExist, doesFileExist,
                                      getCurrentDirectory)
import           System.Exit         (ExitCode (..))
import           System.FilePath     (joinPath, (</>))
import           System.IO           (stdout)
import           System.IO.Silently  (capture, hSilence)
import           System.Process      (readProcess, system)
import           Test.Hspec

import           Paths_hi            (version)

main :: IO ()
main = hspec spec

spec :: Spec
spec = do
    describe "with command line options" $ do
      let cmd = runWithCommandLineOptions [ "-p", packageName , "-m", moduleName ]
      around_ cmd features

    describe "with custom git config" $ do
      let cmd = runWithLocalGitConfig [ "-p", packageName , "-m", moduleName ]
      around_ cmd features

    describe "with config file" $ do
      let cmd = runWithConfigurationFile [ "-p", packageName , "-m", moduleName ]
      around_ cmd features

    describe "Only package name was given" $ do
      let cmd = runWithCommandLineOptions ["-p", "something-weird"]

      around_ cmd $ do
        it "should use Capitalized package name as module name" $ do
          doesDirectoryExist "something-weird/src/Something/Weird" `shouldReturn` True

    describe "Package name was given as an argument" $ do
      let cmd = runWithCommandLineOptions ["something-weird"]

      around_ cmd $ do
        it "should use Capitalized package name as module name" $ do
          doesDirectoryExist "something-weird/src/Something/Weird" `shouldReturn` True

    describe "Directory name was given" $ do
      let cmd = runWithCommandLineOptions ["abc", "-d", "efg"]

      around_ cmd $ do
        it "should create file in given directory" $ do
          doesDirectoryExist "efg/src/Abc" `shouldReturn` True

   -- https://github.com/fujimura/hi/issues/48
    describe "with --module-name, not --moduleName" $ do
      let cmd = runWithConfigurationFile [ "-p", packageName , "--module-name", moduleName ]
      around_ cmd features

    describe "with --initialize-git-repository" $ do
      let cmd = runWithCommandLineOptions [ "--initialize-git-repository"
                                          , "-p"
                                          , packageName
                                          , "-m"
                                          , moduleName ]
      around_ cmd $ do
        it "should initialize it as git repository and make first commit" $ do
          inDirectory "./testapp" $ do
            readProcess "git" ["log", "-1", "--pretty=%s"] [] `shouldReturn` "Initial commit\n"

    describe "with --after-command='touch a" $ do
      let cmd = runWithCommandLineOptions [ "--after-command"
                                          , "touch a"
                                          , "-p"
                                          , packageName
                                          ]
      around_ cmd $ do
        it "should initialize it as git repository and make file named a" $ do
          doesFileExist "testapp/a" `shouldReturn` True

    describe "-v" $ do
      it "should show version number" $ do
        let handle ExitSuccess   = return ()
            handle e             = throwIO e

        (res,_) <- capture $ Cli.run ["-v"] `catch` handle
        res `shouldBe` (showVersion version) ++ "\n"

packageName, moduleName, author, email :: String
packageName = "testapp"
moduleName  = "System.Awesome.Library"
author      = "Fujimura Daisuke"
email       = "me@fujimuradaisuke.com"

features :: Spec
features = do

  describe "LICENSE" $ do
    it "should include author" $  do
      compiled <- readFile "testapp/LICENSE"
      compiled `shouldContain` "Fujimura Daisuke"

    it "should include year" $  do
      (year,_,_) <- (toGregorian . utctDay) <$> getCurrentTime
      compiled   <- readFile "testapp/LICENSE"
      compiled `shouldContain` show year

  describe "README.md" $ do
    it "should include name" $  do
      compiled <- readFile "testapp/README.md"
      compiled `shouldContain` "testapp"

  describe "module-name.cabal" $ do
    it "should include name" $  do
      compiled <- readFile "testapp/testapp.cabal"
      compiled `shouldContain` "testapp"

    it "should include author" $  do
      compiled <- readFile "testapp/testapp.cabal"
      compiled `shouldContain` "Fujimura Daisuke"

    it "should include email" $  do
      compiled <- readFile "testapp/testapp.cabal"
      compiled `shouldContain` "me@fujimuradaisuke.com"

    it "should include exposed-modules" $  do
      compiled <- readFile "testapp/testapp.cabal"
      compiled `shouldContain` "Exposed-Modules:      System.Awesome.Library"

    it "should include other-modules" $  do
      compiled <- readFile "testapp/testapp.cabal"
      compiled `shouldContain` "Other-Modules:        System.Awesome.Library.Internal"

  describe "directory" $ do
    it "should be made according to given module name" $  do
      doesDirectoryExist "testapp/src/System/Awesome/Library" `shouldReturn` True

  describe "Main module" $ do
    it "should be made" $  do
      doesFileExist "testapp/src/System/Awesome/Library.hs" `shouldReturn` True

    it "should include proper module name" $  do
      compiled <- readFile "testapp/src/System/Awesome/Library.hs"
      compiled `shouldContain` "module System.Awesome.Library"

  describe "Internal module" $ do
    it "should be made" $  do
      doesFileExist "testapp/src/System/Awesome/Library/Internal.hs" `shouldReturn` True

    it "should include proper module name" $  do
      compiled <- readFile "testapp/src/System/Awesome/Library/Internal.hs"
      compiled `shouldContain` "module System.Awesome.Library.Internal"

  describe "Spec.hs" $ do
    it "should be made" $  do
      doesFileExist "testapp/test/Spec.hs" `shouldReturn` True

    it "should include proper content" $  do
      compiled <- readFile "testapp/test/Spec.hs"
      compiled `shouldContain` "{-# OPTIONS_GHC -F -pgmF hspec-discover #-}"

  describe "Main spec" $ do
    it "should be made" $  do
      doesFileExist "testapp/test/System/Awesome/LibrarySpec.hs" `shouldReturn` True

    it "should include proper content" $  do
      compiled <- readFile "testapp/test/System/Awesome/LibrarySpec.hs"
      compiled `shouldContain` "module System.Awesome.LibrarySpec (main, spec) where"

  describe ".gitignore" $ do
    it "should be made" $  do
      doesFileExist "testapp/.gitignore" `shouldReturn` True

runWithCommandLineOptions :: [String] -> IO () -> IO ()
runWithCommandLineOptions opts action = do
    root <- getCurrentDirectory
    inTestDirectory $ hSilence [stdout] $ do
      Cli.run $ opts ++ [ "-a", quote author
                        , "-e", quote email
                        , "-r", (root </> "test" </> "template")
                        ]
      action

runWithLocalGitConfig :: [String] -> IO () -> IO ()
runWithLocalGitConfig opts action = do
    root <- getCurrentDirectory
    inTestDirectory $ hSilence [stdout] $ do
        _ <- system $ "git init"
        _ <- system $ "git config user.name" ++ " " ++ quote author
        _ <- system $ "git config user.email" ++ " " ++ quote email
        Cli.run $ opts ++ [ "-r", (root </> "test" </> "template") ]
        action

runWithConfigurationFile :: [String] -> IO () -> IO ()
runWithConfigurationFile opts action = do
    root <- getCurrentDirectory
    inTestDirectory $ hSilence [stdout] $ do
        writeFile ".hirc" $ concatLines
            [ "author: " ++ author
            , "email: " ++ email
            ]
        pwd' <- getCurrentDirectory
        withEnv "HOME" pwd' $ do
          Cli.run $ opts ++ [ "--configuration-file", (joinPath [pwd', ".hirc"])
                            , "-r", (root </> "test" </> "template")
                            ]
          action

{-# ANN module "HLint: Redundant do" #-}