module Test.Hspec.Discover.RunSpec (spec) where

import           Helper
import           Test.Mockery.Directory

import           Test.Hspec.Discover.Run hiding (Spec)
import qualified Test.Hspec.Discover.Run as Run

spec :: Spec
spec = do
  describe "run" $ around_ inTempDirectory $ do
    it "generates a test driver" $ do
      touch "test/FooSpec.hs"
      touch "test/Foo/Bar/BazSpec.hs"
      touch "test/Foo/BarSpec.hs"
      run ["test/Spec.hs", "", "out"]
      readFile "out" `shouldReturn` unlines [
          "{-# LINE 1 \"test/Spec.hs\" #-}"
        , "{-# LANGUAGE NoImplicitPrelude #-}"
        , "{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}"
        , "module Main where"
        , "import qualified FooSpec"
        , "import qualified Foo.BarSpec"
        , "import qualified Foo.Bar.BazSpec"
        , "import Test.Hspec.Discover"
        , "main :: IO ()"
        , "main = hspec spec"
        , "spec :: Spec"
        , "spec = " ++ unwords [
               "describe \"Foo\" FooSpec.spec"
          , ">> describe \"Foo.Bar\" Foo.BarSpec.spec"
          , ">> describe \"Foo.Bar.Baz\" Foo.Bar.BazSpec.spec"
          ]
        ]

    it "generates a test driver with hooks" $ do
      touch "test/FooSpec.hs"
      touch "test/Foo/Bar/BazSpec.hs"
      touch "test/Foo/BarSpec.hs"
      touch "test/Foo/SpecHook.hs"
      touch "test/SpecHook.hs"
      run ["test/Spec.hs", "", "out"]
      readFile "out" `shouldReturn` unlines [
          "{-# LINE 1 \"test/Spec.hs\" #-}"
        , "{-# LANGUAGE NoImplicitPrelude #-}"
        , "{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}"
        , "module Main where"
        , "import qualified SpecHook"
        , "import qualified FooSpec"
        , "import qualified Foo.SpecHook"
        , "import qualified Foo.BarSpec"
        , "import qualified Foo.Bar.BazSpec"
        , "import Test.Hspec.Discover"
        , "main :: IO ()"
        , "main = hspec spec"
        , "spec :: Spec"
        , "spec = " ++ unwords [
               "(SpecHook.hook $ describe \"Foo\" FooSpec.spec"
          , ">> (Foo.SpecHook.hook $ describe \"Foo.Bar\" Foo.BarSpec.spec"
          , ">> describe \"Foo.Bar.Baz\" Foo.Bar.BazSpec.spec))"
          ]
        ]

    it "generates a test driver for an empty directory" $ do
      touch "test/Foo/Bar/Baz/.placeholder"
      run ["test/Spec.hs", "", "out"]
      readFile "out" `shouldReturn` unlines [
          "{-# LINE 1 \"test/Spec.hs\" #-}"
        , "{-# LANGUAGE NoImplicitPrelude #-}"
        , "{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}"
        , "module Main where"
        , "import Test.Hspec.Discover"
        , "main :: IO ()"
        , "main = hspec spec"
        , "spec :: Spec"
        , "spec = return ()"
        ]

  describe "pathToModule" $ do
    it "derives module name from a given path" $ do
      pathToModule "test/Spec.hs" `shouldBe` "Spec"

  describe "driverWithFormatter" $ do
    it "generates a test driver that uses a custom formatter" $ do
      driverWithFormatter "Some.Module.formatter" "" `shouldBe` unlines [
          "import qualified Some.Module"
        , "main :: IO ()"
        , "main = hspecWithFormatter Some.Module.formatter spec"
        ]

  describe "moduleNameFromId" $ do
    it "returns the module name of a fully qualified identifier" $ do
      moduleNameFromId "Some.Module.someId" `shouldBe` "Some.Module"

  describe "importList" $ do
    it "generates imports for a list of specs" $ do
      importList (Just [Run.Spec "Foo", Run.Spec "Bar"]) "" `shouldBe` unlines [
          "import qualified FooSpec"
        , "import qualified BarSpec"
        ]

  describe "discover" $ do
    it "discovers spec files" $ do
      inTempDirectory $ do
        touch "test/Spec.hs"
        touch "test/FooSpec.hs"
        touch "test/BarSpec.hs"
        discover "test/Spec.hs" `shouldReturn` Just (Forest WithoutHook [Leaf "Bar", Leaf "Foo"])

    it "discovers nested spec files" $ do
      inTempDirectory $ do
        touch "test/Spec.hs"
        touch "test/Foo/BarSpec.hs"
        touch "test/Foo/BazSpec.hs"
        discover "test/Spec.hs" `shouldReturn` Just (Forest WithoutHook [Node "Foo" (Forest WithoutHook [Leaf "Bar", Leaf "Baz"])])

    it "discovers hooks" $ do
      inTempDirectory $ do
        touch "test/Spec.hs"
        touch "test/FooSpec.hs"
        touch "test/BarSpec.hs"
        touch "test/SpecHook.hs"
        discover "test/Spec.hs" `shouldReturn` Just (Forest WithHook [Leaf "Bar", Leaf "Foo"])

    it "discovers nested hooks" $ do
      inTempDirectory $ do
        touch "test/Spec.hs"
        touch "test/Foo/BarSpec.hs"
        touch "test/Foo/BazSpec.hs"
        touch "test/Foo/SpecHook.hs"
        discover "test/Spec.hs" `shouldReturn` Just (Forest WithoutHook [Node "Foo" (Forest WithHook [Leaf "Bar", Leaf "Baz"])])

    it "ignores invalid module names" $ do
      inTempDirectory $ do
        touch "test/Spec.hs"
        touch "test/barSpec.hs"
        discover "test/Spec.hs" `shouldReturn` Nothing

    it "ignores empty directories" $ do
      inTempDirectory $ do
        touch "test/Spec.hs"
        touch "test/Foo/.keep"
        discover "test/Spec.hs" `shouldReturn` Nothing

    it "ignores directories with extension" $ do
      inTempDirectory $ do
        touch "test/Spec.hs"
        touch "test/Foo.hs/BarSpec.hs"
        discover "test/Spec.hs" `shouldReturn` Nothing
