content: {-# LANGUAGE OverloadedStrings #-}
  module HpackSpec (spec) where
  
  import           Helper
  
  import           Prelude hiding (readFile)
  import qualified Prelude as Prelude
  import           System.Exit (die)
  
  import           Control.DeepSeq
  
  import           Hpack.Config
  import           Hpack.CabalFile
  import           Hpack.Error (formatHpackError)
  import           Hpack
  
  readFile :: FilePath -> IO String
  readFile name = Prelude.readFile name >>= (return $!!)
  
  spec :: Spec
  spec = do
    describe "header" $ do
      it "generates header" $ do
        header "foo.yaml" Nothing Nothing `shouldBe` [
            "-- This file has been generated from foo.yaml by hpack."
          , "--"
          , "-- see: https://github.com/sol/hpack"
          , ""
          ]
  
      context "with hpack version" $ do
        it "includes hpack version" $ do
          header "foo.yaml" (Just $ makeVersion [0,34,0]) Nothing `shouldBe` [
              "-- This file has been generated from foo.yaml by hpack version 0.34.0."
            , "--"
            , "-- see: https://github.com/sol/hpack"
            , ""
            ]
  
      context "with hash" $ do
        it "includes hash" $ do
          header "foo.yaml" Nothing (Just "some-hash") `shouldBe` [
              "-- This file has been generated from foo.yaml by hpack."
            , "--"
            , "-- see: https://github.com/sol/hpack"
            , "--"
            , "-- hash: some-hash"
            , ""
            ]
  
    describe "renderCabalFile" $ do
      it "is inverse to readCabalFile" $ do
        expected <- lines <$> readFile "resources/test/hpack.cabal"
        Just c <- readCabalFile "resources/test/hpack.cabal"
        renderCabalFile "package.yaml" c {cabalFileGitConflictMarkers = ()} `shouldBe` expected
  
    describe "hpackResult" $ around_ inTempDirectory $ before_ (writeFile packageConfig "name: foo") $ do
      let
        file = "foo.cabal"
  
        hpackWithVersion v = hpackResultWithVersion (makeVersion v) defaultOptions >>= either (die . formatHpackError "hpack") return
        hpackWithStrategy strategy = hpackResult defaultOptions { optionsGenerateHashStrategy = strategy }
        hpackForce = hpackResult defaultOptions {optionsForce = Force}
  
        generated = Result [] file Generated
        modifiedManually = Result [] file ExistingCabalFileWasModifiedManually
        outputUnchanged = Result [] file OutputUnchanged
        alreadyGeneratedByNewerHpack = Result [] file AlreadyGeneratedByNewerHpack
  
        modifyPackageConfig = writeFile packageConfig $ unlines [
            "name: foo"
          , "version: 0.1.0"
          ]
  
        modifyCabalFile = do
          xs <- readFile file
          writeFile file $ xs ++ "foo\n"
  
        manuallyCreateCabalFile = do
          writeFile file "some existing cabal file"
  
        doesNotGenerateHash :: HasCallStack => GenerateHashStrategy -> Spec
        doesNotGenerateHash strategy = do
          it "does not generate hash" $ do
            hpackWithStrategy strategy `shouldReturn` generated
            readFile file >>= (`shouldNotContain` "hash")
  
        generatesHash :: HasCallStack => GenerateHashStrategy -> Spec
        generatesHash strategy = do
          it "generates hash" $ do
            hpackWithStrategy strategy `shouldReturn` generated
            readFile file >>= (`shouldContain` "hash")
  
        doesNotOverwrite :: HasCallStack => GenerateHashStrategy -> Spec
        doesNotOverwrite strategy = do
          it "does not overwrite cabal file" $ do
            existing <- readFile file
            hpackWithStrategy strategy `shouldReturn` modifiedManually
            readFile file `shouldReturn` existing
  
        with strategy item = context ("with " ++ show strategy) $ item strategy
  
      context "without an existing cabal file" $ do
        with ForceHash generatesHash
        with PreferHash generatesHash
        with ForceNoHash doesNotGenerateHash
        with PreferNoHash doesNotGenerateHash
  
      context "with an existing cabal file" $ do
        context "without a hash" $ before_ (hpackWithStrategy ForceNoHash >> modifyPackageConfig) $ do
          with ForceHash generatesHash
          with PreferHash doesNotGenerateHash
          with ForceNoHash doesNotGenerateHash
          with PreferNoHash doesNotGenerateHash
  
        context "with a hash" $ before_ (hpackWithStrategy ForceHash >> modifyPackageConfig) $ do
          with ForceHash generatesHash
          with PreferHash generatesHash
          with ForceNoHash doesNotGenerateHash
          with PreferNoHash generatesHash
  
          context "with manual modifications" $ before_ modifyCabalFile $ do
            with ForceHash doesNotOverwrite
            with PreferHash doesNotOverwrite
            with ForceNoHash doesNotGenerateHash
            with PreferNoHash doesNotOverwrite
  
        context "when created manually" $ before_ manuallyCreateCabalFile $ do
          with ForceHash doesNotOverwrite
          with PreferHash doesNotOverwrite
          with ForceNoHash doesNotOverwrite
          with PreferNoHash doesNotOverwrite
  
          context "with --force" $ do
            it "overwrites cabal file" $ do
              hpackForce `shouldReturn` generated
  
        context "when generated with a newer version of hpack" $ do
          it "does not overwrite cabal file" $ do
            _ <- hpackWithVersion [0,22,0]
            old <- readFile file
            modifyPackageConfig
            hpackWithVersion [0,20,0] `shouldReturn` alreadyGeneratedByNewerHpack
            readFile file `shouldReturn` old
  
        context "when only the hpack version in the cabal file header changed" $ do
          it "does not overwrite cabal file" $ do
            _ <- hpackWithVersion [0,22,0]
            old <- readFile file
            hpackWithVersion [0,30,0] `shouldReturn` outputUnchanged
            readFile file `shouldReturn` old
  
          it "does not complain if it's newer" $ do
            _ <- hpackWithVersion [0,22,0]
            old <- readFile file
            hpackWithVersion [0,20,0] `shouldReturn` outputUnchanged
            readFile file `shouldReturn` old
  
        context "with git conflict markers" $ do
          context "when the new and the existing .cabal file are essentially the same" $ do
            it "still removes the conflict markers" $ do
              writeFile file $ unlines [
                  "--"
                , "name: foo"
                ]
              hpack NoVerbose defaultOptions {optionsForce = Force}
              old <- readFile file
              let
                modified :: String
                modified = unlines $ case break (== "version: 0.0.0") $ lines old of
                  (xs, v : ys)  -> xs ++
                    "<<<<<<< ours" :
                    v :
                    "=======" :
                    "version: 0.1.0" :
                    ">>>>>>> theirs" : ys
                  _ -> undefined
              writeFile file modified
              hpack NoVerbose defaultOptions
              readFile file `shouldReturn` old
  