packages feed

prune-juice-0.7: test/Data/Prune/Section/ParserSpec.hs

module Data.Prune.Section.ParserSpec where

import Prelude

import Data.Either (isLeft)
import System.FilePath.TH (fileRelativeToAbsolute)
import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)
import Text.Megaparsec (parse)

import Data.Prune.ApplyStrategy.Smart (stripSections)
import qualified Data.Prune.Section.Types as T
import qualified Data.Prune.Types as T

-- the module being tested
import Data.Prune.Section.Parser

buildDependsNestedSection, importNestedSection, otherNestedSection :: T.NestedSection
buildDependsNestedSection = T.BuildDependsNestedSection 2 ["", "    , base <5.0"]
importNestedSection = T.ImportNestedSection 2 [" foo, bar"]
otherNestedSection = T.OtherNestedSection 2 ["default-language: Haskell2010"]

librarySection, executableSection, commonSection, otherSection :: T.Section
librarySection = T.TargetSection T.CompilableTypeLibrary Nothing [importNestedSection, buildDependsNestedSection, otherNestedSection]
executableSection = T.TargetSection T.CompilableTypeExecutable (Just (T.CompilableName "prune-juice")) [buildDependsNestedSection, otherNestedSection]
commonSection = T.CommonSection (T.CommonName "foo") [buildDependsNestedSection, otherNestedSection]
otherSection = T.OtherSection ["name: prune-juice"]

buildDependsNestedExample, importNestedExample, otherNestedExample
  , libraryExample, executableExample, commonExample, otherExample :: String
buildDependsNestedExample = unlines
  [ "  build-depends:"
  , "    , base <5.0"
  ]
importNestedExample = unlines
  [ "  import: foo, bar"
  ]
otherNestedExample = unlines
  [ "  default-language: Haskell2010"
  ]
libraryExample = unlines
  [ "library"
  , "  import: foo, bar"
  , "  build-depends:"
  , "    , base <5.0"
  , "  default-language: Haskell2010"
  ]
executableExample = unlines
  [ "executable prune-juice"
  , "  build-depends:"
  , "    , base <5.0"
  , "  default-language: Haskell2010"
  ]
commonExample = unlines
  [ "common foo"
  , "  build-depends:"
  , "    , base <5.0"
  , "  default-language: Haskell2010"
  ]
otherExample = unlines
  [ "name: prune-juice"
  ]

spec :: Spec
spec = describe "Data.Prune.Section.Parser" $ do
  let cabalFile = $(fileRelativeToAbsolute "../../../../prune-juice.cabal")
      commonFile = $(fileRelativeToAbsolute "../../../fixtures/test.cabal")

  it "should parse a target name" $
    parse targetName "" "prune-juice" `shouldBe` Right (T.CompilableName "prune-juice")

  it "should parse the rest of the line" $
    parse restOfLine "" "foo\n" `shouldBe` Right "foo"

  it "should parse an indented line" $
    parse (indentedLine 0) "" " foo\n" `shouldBe` Right " foo"

  it "should not parse a non-indented line" $
    parse (indentedLine 0) "" "foo\n" `shouldSatisfy` isLeft

  it "should parse indented lines" $
    parse (indentedLines 0) "" "foo\n bar\nbaz\n" `shouldBe` Right ["foo", " bar"]

  it "should parse a build depends nested section" $
    parse nestedSection "" buildDependsNestedExample `shouldBe` Right buildDependsNestedSection

  it "should parse an import nested section" $
    parse nestedSection "" importNestedExample `shouldBe` Right importNestedSection

  it "should parse an other nested section" $
    parse nestedSection "" otherNestedExample `shouldBe` Right otherNestedSection

  it "should parse a library section" $
    parse section "" libraryExample `shouldBe` Right librarySection

  it "should parse an executable section" $
    parse section "" executableExample `shouldBe` Right executableSection

  it "should parse a common section" $
    parse section "" commonExample `shouldBe` Right commonSection

  it "should parse an other section" $
    parse section "" otherExample `shouldBe` Right otherSection

  it "should parse multiple sections" $
    parse sections "" (libraryExample <> executableExample <> commonExample <> otherExample) `shouldBe` Right [librarySection, executableSection, commonSection, otherSection]

  it "should parse and output the same thing" $ do
    input <- readFile cabalFile
    xs <- either fail pure $ parseCabalSections input
    xs `shouldSatisfy` not . null
    renderCabalSections xs `shouldBe` input

  it "should parse and output the same thing after applying a trivial change" $ do
    input <- readFile cabalFile
    xs <- either fail (\ys -> pure (stripSections ys mempty Nothing)) $ parseCabalSections input
    xs `shouldSatisfy` not . null
    renderCabalSections xs `shouldBe` input

  it "should parse a cabal file with common stanzas" $ do
    input <- readCabalSections commonFile
    input `shouldBe` Right
      [ T.CommonSection (T.CommonName "global-options")
          [ T.OtherNestedSection 2 ["default-language: Haskell2010", ""]
          ]
      , T.CommonSection (T.CommonName "options")
          [ T.ImportNestedSection 2 [" global-options"]
          , T.BuildDependsNestedSection 2 [" base", ""]
          ]
      , T.CommonSection (T.CommonName "global-exe-options")
          [ T.OtherNestedSection 2 ["ghc-options: -threaded", ""]
          ]
      , T.TargetSection T.CompilableTypeLibrary Nothing
          [ T.ImportNestedSection 2 [" options", ""]
          ]
      , T.TargetSection T.CompilableTypeExecutable (Just (T.CompilableName "exe"))
          [ T.ImportNestedSection 2 [" options, global-exe-options"]
          ]
      ]