packages feed

staversion-0.2.1.0: test/Staversion/Internal/FormatSpec.hs

module Staversion.Internal.FormatSpec (main,spec) where

import Data.Monoid ((<>))
import Data.Text (pack)
import qualified Data.Text.Lazy as TL
import Test.Hspec

import Staversion.Internal.Aggregate (aggOr, Aggregator, aggregateResults)
import Staversion.Internal.Format
  ( formatAggregatedResults,
    FormatConfig(..),
    formatVersionCabal,
    formatVersionCabalCaret,
  )
import Staversion.Internal.Log (LogEntry)
import Staversion.Internal.Query
  ( PackageSource(..), Query(..),
    Resolver, PackageName
  )
import Staversion.Internal.Result
  ( Result(..), ResultBody, ResultBody'(..), ResultSource(..),
    singletonResult
  )
import Staversion.Internal.Cabal (Target(..))

import Staversion.Internal.TestUtil
  ( ver, simpleResultBody, verPairs,
    vthis, vors', vint
  )
       


main :: IO ()
main = hspec spec

spec :: Spec
spec = do
  spec_simple
  spec_aggregate
  spec_formatVersionCabalCaret

-- | for backward-compatibility.
formatResultsCabal :: [Result] -> TL.Text
formatResultsCabal =  formatAggregatedResults fconf . map singletonResult where
  fconf = FormatConfig { fconfFormatVersion = formatVersionCabal
                       }

-- | for backward-compatibility.
formatResultsCabalAggregated :: Aggregator -> [Result] -> (TL.Text, [LogEntry])
formatResultsCabalAggregated agg = mapFirst (formatAggregatedResults fconf) . aggregateResults agg where
  fconf = FormatConfig { fconfFormatVersion = formatVersionCabal
                       }
  mapFirst f (a, b) = (f a, b)

spec_simple :: Spec
spec_simple = describe "formatAggregatedResults" $ do
  it "should return empty text for empty list" $ do
    formatResultsCabal [] `shouldBe` ""
  it "should format a Result in a Cabal way" $ do
    let input = [ Result { resultIn = ResultSource (SourceStackage "lts-6.10") (Just $ SourceStackage "lts-6.10"),
                           resultFor = QueryName "hoge",
                           resultBody = Right $ simpleResultBody "hoge" [3,4,5]
                         }
                ]
        expected = ( "------ lts-6.10\n"
                     <> "hoge ==3.4.5\n"
                     <> "\n"
                   )
    formatResultsCabal input `shouldBe` expected
  
  it "should group Results by PackageSource with preserved order" $ do
    let input = [ simpleResult "source_c" "hoge" [0,5,7],
                  simpleResult "source_a" "hoge" [1,0,0],
                  simpleResult "source_b" "foobar" [0,2,5,3],
                  simpleResult "source_b" "hoge" [1,2,0],
                  simpleResult "source_a" "quux" [300,5],
                  simpleResult "source_a" "foobar" [0,3,2],
                  simpleResult "source_b" "quux" [299,10]
                ]
        expected = ( "------ source_c\n"
                     <> "hoge ==0.5.7\n"
                     <> "\n"
                     <> "------ source_a\n"
                     <> "hoge ==1.0.0,\n"
                     <> "quux ==300.5,\n"
                     <> "foobar ==0.3.2\n"
                     <> "\n"
                     <> "------ source_b\n"
                     <> "foobar ==0.2.5.3,\n"
                     <> "hoge ==1.2.0,\n"
                     <> "quux ==299.10\n"
                     <> "\n"
                   )
    formatResultsCabal input `shouldBe` expected
  it "should group Results by PackageSource with preserved order (2)" $ do
    let input = [ simpleResult "lts-5.0" "pack-A" [1,0],
                  simpleResult "lts-5.0" "pack-A" [2,0],
                  simpleResult "lts-6.6" "pack-A" [3,0],
                  simpleResult "lts-6.6" "pack-A" [4,0],
                  simpleResult "lts-8.0" "pack-A" [5,0],
                  simpleResult "lts-6.6" "pack-A" [6,0],
                  simpleResult "lts-6.6" "pack-A" [7,0]
                ]
        expected = ( "------ lts-5.0\n"
                     <> "pack-A ==1.0,\n"
                     <> "pack-A ==2.0\n"
                     <> "\n"
                     <> "------ lts-6.6\n"
                     <> "pack-A ==3.0,\n"
                     <> "pack-A ==4.0,\n"
                     <> "pack-A ==6.0,\n"
                     <> "pack-A ==7.0\n"
                     <> "\n"
                     <> "------ lts-8.0\n"
                     <> "pack-A ==5.0\n"
                     <> "\n"
                   )
    formatResultsCabal input `shouldBe` expected
  it "should not put comma at the last non-N/A entry even if it is followed by N/A entries"  $ do
    let input = [ simpleResult "s" "hoge" [1,0,0],
                  simpleResult "s" "not-found-1" [],
                  simpleResult "s" "foobar" [2,0,0],
                  simpleResult "s" "not-found-2" [],
                  simpleResult "s" "not-found-3" []
                ]
        expected = ( "------ s\n"
                     <> "hoge ==1.0.0,\n"
                     <> "-- not-found-1 N/A,\n"
                     <> "foobar ==2.0.0\n"
                     <> "-- not-found-2 N/A,\n"
                     <> "-- not-found-3 N/A\n"
                     <> "\n"
                   )
    formatResultsCabal input `shouldBe` expected
  it "should output resultReallyIn field" $ do
    let input = [ Result { resultIn = ResultSource (SourceStackage "lts") (Just $ SourceStackage "lts-7.4"),
                           resultFor = QueryName "foobar",
                           resultBody = Right $ simpleResultBody "foobar" [3,4,5]
                         } ]
        expected = ( "------ lts (lts-7.4)\n"
                     <> "foobar ==3.4.5\n"
                     <> "\n"
                   )
    formatResultsCabal input `shouldBe` expected
  it "should show ERROR if resultBody is Left, resultFor is QueryName" $ do
    let input = [ Result { resultIn = ResultSource (SourceStackage "lts-4.2") Nothing,
                           resultFor = QueryName "hogehoge",
                           resultBody = Left "some error"
                         } ]
        expected = ( "------ lts-4.2\n"
                     <> "-- hogehoge ERROR\n"
                     <> "\n"
                   )
    formatResultsCabal input `shouldBe` expected
  it "should show ERROR if resultBody is Left, resultFor is QueryCabalFile" $ do
    let input = [ Result { resultIn = ResultSource (SourceStackage "lts-5.3") (Just $ SourceStackage "lts-5.3"),
                           resultFor = QueryCabalFile "foobar.cabal",
                           resultBody = Left "some error"
                         },
                  Result { resultIn = ResultSource (SourceStackage "lts-5.3") (Just $ SourceStackage "lts-5.3"),
                           resultFor = QueryName "hoge",
                           resultBody = Right $ simpleResultBody "hoge" [5,5]
                         }
                ]
        expected = ( "------ lts-5.3\n"
                     <> "-- foobar.cabal ERROR\n"
                     <> "\n"
                     <> "hoge ==5.5\n"
                     <> "\n"
                   )
    formatResultsCabal input `shouldBe` expected
  it "should show build-depends blocks for CabalResultBody" $ do
    let mkRet = cabalResult "lts-7.0" "hoge.cabal"
        input = [ mkRet TargetLibrary [ ("base", [4,6,0,0]),
                                        ("foobar", [5,7])
                                      ],
                  mkRet (TargetExecutable "hoge-exe") [ ("bytestring", [1,9]) ],
                  mkRet (TargetTestSuite "hoge-test") [ ("hspec", [10,8,9]),
                                                        ("QuickCheck", [5,4,2]),
                                                        ("unknown", [])
                                                      ],
                  mkRet (TargetBenchmark "hoge-bench") [ ("base", [4,8,0,4]),
                                                         ("quux", []),
                                                         ("parsec", [3,0,2])
                                                       ]
                ]
        expected = ( "------ lts-7.0\n"
                     <> "-- hoge.cabal - library\n"
                     <> "base ==4.6.0.0,\n"
                     <> "foobar ==5.7\n"
                     <> "\n"
                     <> "-- hoge.cabal - executable hoge-exe\n"
                     <> "bytestring ==1.9\n"
                     <> "\n"
                     <> "-- hoge.cabal - test-suite hoge-test\n"
                     <> "hspec ==10.8.9,\n"
                     <> "QuickCheck ==5.4.2\n"
                     <> "-- unknown N/A\n"
                     <> "\n"
                     <> "-- hoge.cabal - benchmark hoge-bench\n"
                     <> "base ==4.8.0.4,\n"
                     <> "-- quux N/A,\n"
                     <> "parsec ==3.0.2\n"
                     <> "\n"
                   )
    formatResultsCabal input `shouldBe` expected
  it "should show mixed blocks and lines" $ do
    let input = [ simpleResult "lts-5.0" "pack-A" [4,5],
                  simpleResult "lts-5.0" "pack-B" [7,7],
                  cabalResult "lts-5.0" "X.cabal" TargetLibrary [("pack-A", [4,5,1]), ("pack-B", [6,0])],
                  cabalResult "lts-5.0" "X.cabal" (TargetExecutable "X-exe") [("pack-A", []), ("pack-B", [6,6]), ("pack-C", [0,10])],
                  cabalResult "lts-6.6" "Y.cabal" TargetLibrary [("pack-C", [9,99,0])],
                  simpleResult "lts-6.6" "pack-A" [],
                  simpleResult "lts-7.2" "pack-B" [8,4],
                  cabalResult "lts-6.6" "Y.cabal" (TargetTestSuite "X-test") [("pack-D", [1,0]), ("pack-A", [5,0]), ("pack-C", []), ("pack-B", [6,5])]
                ]
        expected = ( "------ lts-5.0\n"
                     <> "pack-A ==4.5,\n"
                     <> "pack-B ==7.7\n"
                     <> "\n"
                     <> "-- X.cabal - library\n"
                     <> "pack-A ==4.5.1,\n"
                     <> "pack-B ==6.0\n"
                     <> "\n"
                     <> "-- X.cabal - executable X-exe\n"
                     <> "-- pack-A N/A,\n"
                     <> "pack-B ==6.6,\n"
                     <> "pack-C ==0.10\n"
                     <> "\n"
                     <> "------ lts-6.6\n"
                     <> "-- Y.cabal - library\n"
                     <> "pack-C ==9.99.0\n"
                     <> "\n"
                     <> "-- pack-A N/A\n"
                     <> "\n"
                     <> "-- Y.cabal - test-suite X-test\n"
                     <> "pack-D ==1.0,\n"
                     <> "pack-A ==5.0,\n"
                     <> "-- pack-C N/A,\n"
                     <> "pack-B ==6.5\n"
                     <> "\n"
                     <> "------ lts-7.2\n"
                     <> "pack-B ==8.4\n"
                     <> "\n"
                   )
    formatResultsCabal input `shouldBe` expected

spec_aggregate :: Spec
spec_aggregate = describe "formatAggregatedResults" $ do
  it "should aggregate Results over multiple package sources" $ do
    let input = [ simpleResult "lts-4.2" "hoge" [1,2,3],
                  simpleResult "lts-5.0" "hoge" [1,5]
                ]
        expected = ( "------ lts-4.2, lts-5.0\n"
                     <> "hoge ==1.2.3 || ==1.5\n"
                     <> "\n"
                   )
    formatResultsCabalAggregated aggOr input `shouldBe` (expected, [])
  it "should show resultReallyIn in the header" $ do
    let input = [ setRealSource "lts-4.22" $ simpleResult "lts-4" "foobar" [2,3],
                  hackageResult "foobar" [2,3,10],
                  simpleResult "lts-5.3" "foobar" [2,3,4]
                ]
        expected = ( "------ lts-4 (lts-4.22), latest in hackage, lts-5.3\n"
                     <> "foobar ==2.3 || ==2.3.4 || ==2.3.10\n"
                     <> "\n"
                   )
    formatResultsCabalAggregated aggOr input `shouldBe` (expected, [])

simpleResult :: Resolver -> PackageName -> [Int] -> Result
simpleResult res name vs = Result { resultIn = ResultSource (SourceStackage res) (Just $ SourceStackage res),
                                    resultFor = QueryName name,
                                    resultBody = Right $ simpleResultBody name vs
                                  }

hackageResult :: PackageName -> [Int] -> Result
hackageResult name vs = Result { resultIn = ResultSource SourceHackage (Just SourceHackage),
                                 resultFor = QueryName name,
                                 resultBody = Right $ simpleResultBody name vs
                               }

cabalResult :: Resolver -> FilePath -> Target -> [(PackageName, [Int])] -> Result
cabalResult res file target vps =
  Result { resultIn = ResultSource (SourceStackage res) (Just $ SourceStackage res),
           resultFor = QueryCabalFile file,
           resultBody = Right $ CabalResultBody file target $ verPairs vps
         }

setRealSource :: Resolver -> Result -> Result
setRealSource resolver ret = ret { resultIn = rin { resultSourceReal = Just $ SourceStackage resolver } } where
  rin = resultIn ret

spec_formatVersionCabalCaret :: Spec
spec_formatVersionCabalCaret = describe "formatVersionCabalCaret" $ do
  specify "single" $ do
    formatVersionCabalCaret (vthis [1,0,0]) `shouldBe` "==1.0.0"
  specify "or equals" $ do
    formatVersionCabalCaret (vors' [vthis [1,0,0], vthis [1,0,5,6]]) `shouldBe` "==1.0.0 || ==1.0.5.6"
  specify "caret" $ do
    formatVersionCabalCaret (vint [1,2,3,4] [1,3]) `shouldBe` "^>=1.2.3.4"
  specify "caret or" $ do
    formatVersionCabalCaret (vors' [vint [1] [1,1], vint [2,0,3] [2,1]]) `shouldBe` "^>=1 || ^>=2.0.3"
  specify "mixed" $ do
    formatVersionCabalCaret (vors' [vint [1,2,0,4] [1,2,3], vint [2,0] [2,1], vint [3,0,4,5] [3,1]])
      `shouldBe` ">=1.2.0.4 && <1.2.3 || ^>=2.0 || ^>=3.0.4.5"