File: Tests.hs

package info (click to toggle)
haskell-map-syntax 0.3-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 116 kB
  • sloc: haskell: 326; sh: 20; makefile: 5
file content (220 lines) | stat: -rw-r--r-- 8,274 bytes parent folder | download | duplicates (5)
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}

module Data.Map.Syntax.Tests where

------------------------------------------------------------------------------
import qualified Data.List as L
import           Data.Function (on)
import qualified Data.Map as M
import           Data.Monoid (mempty, mappend)
import           Test.Hspec
import           Test.Hspec.QuickCheck
import           Test.HUnit (assertEqual)

import           Data.Map.Syntax
import           Data.Map.Syntax.Util (mkMapABC, mkMapDEF,mkMapAEF,
                                       ArbMapSyntax(..))
------------------------------------------------------------------------------


------------------------------------------------------------------------------
-- |Simple tests for not-nested maps
insTests :: Spec
insTests = do
  it "Insert overwrite" overDup
  it "Insert over fail" failDup
  it "Reject duplicate" skipDup
  it "Trying dupFunc" dupFunc
  prop "Insert overwrite from list" prop_syntaxMatchesNubOver
  prop "Insert conditional from list" prop_syntaxMatchesNubCond
  prop "Insert error on dup from list" prop_syntaxMatchesNubErr

monoidLaws :: Spec
monoidLaws = do
  prop "Left identity"  prop_leftId
  prop "Right identity" prop_rightId
  prop "Associativity"  prop_assoc

------------------------------------------------------------------------------
-- |Simple tests of ##, #!, #?
overDup :: IO ()
overDup = assertEqual "Failed to overwrite duplicate entry"
          (Right $ M.fromList [("firstName","Egon") :: (String,String)])
          (runMap $ mkDupMap (##))

failDup :: IO ()
failDup = assertEqual "Failed to error on duplicate entry"
          (Left [("firstName" :: String)])
          (runMap $ mkDupMap (#!))

skipDup :: IO ()
skipDup = assertEqual "Failed to reject duplicate entry"
          (Right $ M.fromList [("firstName","Peter")])
          (runMap $ mkDupMap (#?))

dupFunc :: IO ()
dupFunc = assertEqual "Failed use dupFunc"
          (Right $ M.fromList [("firstName","firstNamePeterEgon")
            :: (String,String)])
          (runMapSyntax' f M.lookup M.insert $ mkDupMap (#!))
  where
    f k v v1 = Just (k `mappend` v1 `mappend` v)

mkDupMap :: (String -> String -> MapSyntax String String)
            -> MapSyntax String String
mkDupMap strat = do
  "firstName" `strat` "Peter"
  "firstName" `strat` "Egon"


------------------------------------------------------------------------------
prop_syntaxMatchesNubOver :: [(String,Int)] -> Bool
prop_syntaxMatchesNubOver pairs = Right revNubMap == (runMap mSyntax)
  where mSyntax   = mapM_ (\(k,v) -> (k ## v)) pairs
        revNubMap = M.fromList . L.nubBy ((==) `on` fst) . L.reverse $ pairs
        -- Nub keeps the first of each unique entry, so reverse list to
        -- simulate keeping the last

prop_syntaxMatchesNubCond :: [(String,Int)] -> Bool
prop_syntaxMatchesNubCond pairs = Right nubMap == (runMap mSyntax)
  where mSyntax = mapM_ (\(k,v) -> (k #? v)) pairs
        nubMap  = M.fromList . L.nubBy ((==) `on` fst) $ pairs

prop_syntaxMatchesNubErr :: [(String,Int)] -> Bool
prop_syntaxMatchesNubErr pairs =
  let mMap = runMap $ mapM_ (\(k,v) -> (k #! v)) pairs
  in if   pairs == L.nubBy ((==) `on` fst) pairs
     then mMap == (Right . M.fromList $ pairs)
     else case mMap of
       Right _ -> False  -- We expected (Left dupKeys)
       Left  _ -> True   -- Wasn't sure about semantics here
                         -- runMap ... ("a" #! 1) >> ("a" #! 2) >> ("a" #! 3)
                         -- should be (Left ["a"]), or (Left ["a","a"])?


------------------------------------------------------------------------------
-- |Tests for #! when do blocks are nested
nestingTests :: Spec
nestingTests = do
  it "Nested error dups"          nestedErr
  it "Nested error dups mapK"     nestedErrMapK
  it "Nester error dups mapV"     nestedErrMapV
  it "Nested overwrite dups"      nestedOver
  it "Nested overwrite dups mapK" nestedOverMapK
  it "Nested overwrite dups mapV" nestedOverMapV
  it "Nested ignore dups mixed"   nestedIgnoreMix
  it "Nested complex pass"        nestedComplex
  it "Nested complex error"       nestedComplexErr


nestedErr :: IO ()
nestedErr = assertEqual "Failed to error on duplicates across do blocks"
            (Left ['E','F'])
            (runMap $ do {mkMapDEF (#!); mkMapAEF (#!)})

nestedErrMapK :: IO ()
nestedErrMapK = assertEqual "Failed to error on mapK'ed dups across blocks"
                (Left ['B'])
                (runMap $ do
                    mapK succ $ mkMapABC (#!)
                    mapK succ $ mkMapAEF (#!)
                )

nestedErrMapV :: IO ()
nestedErrMapV = assertEqual "Failed to error on mapV'ed dups across blocks"
                (Left ['A'])
                (runMap $ do
                    mapV succ $ mkMapABC (#!)
                    mapV succ $ mkMapAEF (#!)
                    )

nestedOver :: IO ()
nestedOver = assertEqual "Failed to overwrite dup entries across blocks"
             (Right $ M.fromList
              [('A',100),('B',2),('C',3),('E',200),('F',300)])
             (runMap $ do
                 mkMapABC (##)
                 mkMapAEF (##)
             )

nestedOverMapK :: IO ()
nestedOverMapK = assertEqual "Failed to mapK in nested blocks"
                 (Right $ M.fromList
                  [('A',100),('E',200),('F',300),('C',10),('D',20),('B',2)])
                 (runMap $ do
                     mkMapABC (##)
                     mapK pred $ mkMapDEF (##)
                     mkMapAEF (##)
                 )

nestedOverMapV :: IO ()
nestedOverMapV = assertEqual "Failed to mapV in nested blocks"
                 (Right $ M.fromList
                  [('A',99),('B',2),('C',3),('E',199),('F',299)])
                 (runMap $ do
                     mkMapABC (##)
                     mapV pred $ mkMapAEF (##)
                 )

nestedIgnoreMix :: IO ()
nestedIgnoreMix = assertEqual "Failed to mapK/mapV in 'Ignore' do blocks"
                 (Right $ M.fromList
                  [('B',0),('C',1),('D',2),('E',31),('@',101)])
                 (runMap $ do
                     mapV pred . mapK succ $ mkMapABC (#?)
                     mapV succ . mapK pred $ mkMapDEF (#?)
                     mapK pred . mapV succ $ mkMapAEF (#?)
                 )

nestedComplex :: IO ()
nestedComplex = assertEqual "Failed a mix of dup strategies in nested block"
                (Right $ M.fromList
                  [('@',1),('A',2),('B',1000),('C',1000),('D',10),('E',20),('F',30),('G',300),('H',199),('I',299)])
                (runMap $ do
                    mapK succ . mapK succ $ mkMapABC (##)
                    mapK succ . mapK succ . mapK succ . mapV pred $
                      mkMapAEF (#?)
                    mapK succ ((mapV (const 1000) $ mkMapABC (##)) >>
                               mkMapAEF (#?))
                    mkMapDEF (##)
                    mapK pred $ mkMapABC (#?)
                )

nestedComplexErr :: IO ()
nestedComplexErr = assertEqual
                   "Failed to detect dup in complex nested block"
                   (Left ['B'])
                   (runMap $ do
                       mapK succ . mapK succ $ mkMapABC (##)
                       mapK succ . mapK succ . mapK succ . mapV pred $
                         mkMapAEF (#?)
                       mapK succ ((mapV (const 1000) $ mkMapABC (##)) >>
                                  mkMapAEF (#?))
                       mapK pred $ mkMapABC (#!)
                       mkMapDEF (##)
                       mapK pred $ mkMapABC (#?)
                   )


------------------------------------------------------------------------------
-- |Monoid Laws
prop_leftId :: ArbMapSyntax String Int -> Bool
prop_leftId a = runMap (mempty `mappend` m) == runMap m
  where m = unArbSyntax a

prop_rightId :: ArbMapSyntax String Int -> Bool
prop_rightId a = runMap (m `mappend` mempty) == runMap m
  where m = unArbSyntax a

prop_assoc :: ArbMapSyntax String Int
              -> ArbMapSyntax String Int
              -> ArbMapSyntax String Int
              -> Bool
prop_assoc a' b' c' =
    runMap ((a `mappend` b) `mappend` c) ==
    runMap (a `mappend` (b `mappend` c))
  where a = unArbSyntax a'
        b = unArbSyntax b'
        c = unArbSyntax c'