File: DotSpec.hs

package info (click to toggle)
haskell-stack 3.7.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,144 kB
  • sloc: haskell: 38,070; makefile: 6; ansic: 5
file content (135 lines) | stat: -rw-r--r-- 5,948 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}

-- | Test suite for Stack.Dot
module Stack.DotSpec
  ( dummyPayload
  , spec
  , sublistOf
  , pkgName
  , stubLoader
  ) where

import           Data.List ((\\))
import qualified Data.Map as Map
import qualified Data.Set as Set
import           Distribution.License ( License (BSD3) )
import qualified RIO.Text as T
import           Stack.DependencyGraph ( pruneGraph, resolveDependencies )
import           Stack.Prelude hiding ( pkgName )
import           Stack.Types.DependencyTree ( DotPayload (..) )
import           Test.Hspec ( Spec, describe, it, shouldBe )
import           Test.Hspec.QuickCheck ( prop )
import           Test.QuickCheck ( Gen, choose, forAll )

dummyPayload :: DotPayload
dummyPayload = DotPayload (parseVersion "0.0.0.0") (Just (Right BSD3)) Nothing

spec :: Spec
spec = do
  let graph =
         Map.mapKeys pkgName
       . fmap (\p -> (Set.map pkgName p, dummyPayload))
       . Map.fromList $ [("one",Set.fromList ["base","free"])
                        ,("two",Set.fromList ["base","free","mtl","transformers","one"])
                        ]
  describe "Stack.Dot" $ do
    it "does nothing if depth is 0" $
      resolveDependencies (Just 0) graph stubLoader `shouldBe` pure graph

    it "with depth 1, more dependencies are resolved" $ do
      let graph' = Map.insert (pkgName "cycle")
                              (Set.singleton (pkgName "cycle"), dummyPayload)
                              graph
          resultGraph = runIdentity (resolveDependencies (Just 0) graph stubLoader)
          resultGraph' = runIdentity (resolveDependencies (Just 1) graph' stubLoader)
      Map.size resultGraph < Map.size resultGraph' `shouldBe` True

    it "cycles are ignored" $ do
       let graph' = Map.insert (pkgName "cycle")
                               (Set.singleton (pkgName "cycle"), dummyPayload)
                                graph
           resultGraph = resolveDependencies Nothing graph stubLoader
           resultGraph' = resolveDependencies Nothing graph' stubLoader
       fmap Map.size resultGraph' `shouldBe` fmap ((+1) . Map.size) resultGraph

    let graphElem e = Set.member e . Set.unions . Map.elems

    prop "requested packages are pruned" $ do
      let resolvedGraph = runIdentity (resolveDependencies Nothing graph stubLoader)
          allPackages g = Map.keysSet g `Set.union` foldMap fst g
      forAll (sublistOf (Set.toList (allPackages resolvedGraph))) $ \toPrune ->
        let pruned = pruneGraph [pkgName "one", pkgName "two"] toPrune resolvedGraph
        in  Set.null (allPackages pruned `Set.intersection` Set.fromList toPrune)

    prop "pruning removes orphans" $ do
      let resolvedGraph = runIdentity (resolveDependencies Nothing graph stubLoader)
          allPackages g = Map.keysSet g `Set.union` foldMap fst g
          orphans g = Map.filterWithKey (\k _ -> not (graphElem k g)) g
      forAll (sublistOf (Set.toList (allPackages resolvedGraph))) $ \toPrune ->
        let pruned = pruneGraph [pkgName "one", pkgName "two"] toPrune resolvedGraph
        in  null (Map.keys (orphans (fmap fst pruned)) \\ [pkgName "one", pkgName "two"])

{- Helper functions below -}
-- Backport from QuickCheck 2.8 to 2.7.6
sublistOf :: [a] -> Gen [a]
sublistOf = filterM (\_ -> choose (False, True))

-- Unsafe internal helper to create a package name
pkgName :: Text -> PackageName
pkgName = fromMaybe failure . parsePackageName . T.unpack
  where
   failure = error "Internal error during package name creation in DotSpec.pkgName"

-- Stub, simulates the function to load package dependencies
stubLoader :: PackageName -> Identity (Set PackageName, DotPayload)
stubLoader name = pure $ (, dummyPayload) . Set.fromList . map pkgName $
  case show name of
    "StateVar" -> ["stm", "transformers"]
    "array" -> []
    "bifunctors" -> ["semigroupoids", "semigroups", "tagged"]
    "binary" -> ["array", "bytestring", "containers"]
    "bytestring" -> ["deepseq", "ghc-prim", "integer-gmp"]
    "comonad" -> [ "containers", "contravariant", "distributive", "semigroups"
                 , "tagged","transformers","transformers-compat"
                 ]
    "cont" -> [ "StateVar", "semigroups", "transformers", "transformers-compat"
              , "void"
              ]
    "containers" -> ["array", "deepseq", "ghc-prim"]
    "deepseq" -> ["array"]
    "distributive" -> [ "ghc-prim", "tagged", "transformers"
                      , "transformers-compat"
                      ]
    "free" -> [ "bifunctors", "comonad", "distributive", "mtl", "prelude-extras"
              , "profunctors", "semigroupoids", "semigroups", "template-haskell"
              , "transformers"
              ]
    "ghc" -> []
    "hashable" -> ["bytestring", "ghc-prim", "integer-gmp", "text"]
    "integer" -> []
    "mtl" -> ["transformers"]
    "nats" -> []
    "one" -> ["free"]
    "prelude" -> []
    "profunctors" -> [ "comonad", "distributive", "semigroupoids", "tagged"
                     , "transformers"
                     ]
    "semigroupoids" -> [ "comonad", "containers", "contravariant"
                       , "distributive", "semigroups", "transformers"
                       , "transformers-compat"
                       ]
    "semigroups" -> [ "bytestring", "containers", "deepseq", "hashable", "nats"
                    , "text", "unordered-containers"
                    ]
    "stm" -> ["array"]
    "tagged" -> ["template-haskell"]
    "template" -> []
    "text" -> [ "array", "binary", "bytestring", "deepseq", "ghc-prim"
              , "integer-gmp"
              ]
    "transformers" -> []
    "two" -> ["free", "mtl", "one", "transformers"]
    "unordered" -> ["deepseq", "hashable"]
    "void" -> ["ghc-prim", "hashable", "semigroups"]
    _ -> []