packages feed

vinyl-0.14.3: tests/Test/ARec.hs

{-# LANGUAGE DataKinds, FlexibleContexts, GADTs,
             NoMonomorphismRestriction, OverloadedLabels,
             ScopedTypeVariables, TypeApplications, TypeOperators #-}
{-# OPTIONS_GHC -Wall -Wno-type-defaults #-}

module Test.ARec where

import Data.Vinyl.ARec
import Data.Vinyl
import Test.Hspec

import Data.Vinyl.Syntax ()

type FullARec = ARec ElField '[ "f0" ::: Int , "f1" ::: Bool , "f2" ::: String
                              , "f3" ::: Double, "f4" ::: Integer
                              , "f2" ::: Int -- intentionally duplicate field name
                              ]

type SubARecPre = ARec ElField '[ "f0" ::: Int , "f1" ::: Bool , "f2" ::: String ]

type SubARecDupes = ARec ElField '[ "f2" ::: String, "f2" ::: String
                                  , "f2" ::: Int, "f2" ::: String
                                  ]


fullARec :: FullARec
fullARec = toARec ( #f0 =: 1 :& #f1 =: False :& #f2 =: "field2"
                  :& #f3 =: 3.1415 :& #f4 =: 4444
                  :& #f2 =: 666
                  :& RNil
                  )

-- For arecGetSubset -----------------------------------------------------------

subARecPre :: SubARecPre
subARecPre = toARec ( #f0 =: 1 :& #f1 =: False :& #f2 =: "field2" :&  RNil)

subARecDupes :: SubARecDupes
subARecDupes = toARec ( #f2 =: "field2" :& #f2 =: "field2"
                        :& #f2 =: 666 :& #f2 =: "field2"
                        :& RNil
                      )

arecWithDupes :: ARec ElField '[ "f" ::: Int, "f" ::: Int]
arecWithDupes = toARec (#f =: 1 :& #f =: 2 :& RNil)

-- For arecSetSubset -----------------------------------------------------------

subARecPreSet :: SubARecPre
subARecPreSet = toARec ( #f0 =: 11 :& #f1 =: True :& #f2 =: "field2-updated" :&  RNil)

fullARecUpdated :: FullARec
fullARecUpdated = toARec ( #f0 =: 11 :& #f1 =: True :& #f2 =: "field2-updated"
                           :& #f3 =: 3.1415 :& #f4 =: 4444
                           :& #f2 =: 666
                           :& RNil
                         )

updateARecWithDupes :: ARec ElField '[ '("f0", Int), '("f0", Int), '("f0", Int)]
updateARecWithDupes = toARec (#f0 =: 3 :& #f0 =: 66 :& #f0 =: 1 :&RNil)

subARecDupesUpdated :: SubARecDupes
subARecDupesUpdated = toARec ( #f2 =: "updated" :& #f2 =: "field2"
                               :& #f2 =: 666 :& #f2 =: "field2"
                               :& RNil
                             )



spec :: SpecWith ()
spec = describe "ARec" $ do
  describe "arecGetSubset" $ do
    it "retrieves a prefix ARec" $
      -- The part to be retrieved is type-directed
      arecGetSubset fullARec `shouldBe` subARecPre
    it "retrieves the full ARec" $ do
      -- Should catch off-by-one errors that lead to overflow
      arecGetSubset fullARec `shouldBe` fullARec
    it "handles an empty subARec correctly" $
      arecGetSubset fullARec `shouldBe` toARec RNil
    it "handles duplicate field names correctly in the sub arec" $
      arecGetSubset fullARec `shouldBe` subARecDupes
    it "handles duplicate field names correctly in the source arec" $
      -- When both the name and the type of the field match we retrieve from the
      -- first field
      arecGetSubset arecWithDupes `shouldBe` toARec (#f =: (1 :: Int) :& RNil)
  describe "arecSetSubset" $ do
    it "sets a subset of fields" $ do
      arecSetSubset fullARec subARecPreSet `shouldBe` fullARecUpdated
    it "handles updates to every field" $ do
      -- Should catch off-by-one errors that lead to overflow
      arecSetSubset fullARec fullARec `shouldBe` fullARec
    it "handles an empty subset" $ do
      arecSetSubset fullARec (toARec RNil) `shouldBe` fullARec
    it "handles duplicates in the updating ARec" $ do
      -- The behaviour here should be that the _last_ updating field prevails
      arecSetSubset fullARec updateARecWithDupes `shouldBe` fullARec
    it "handles updatees with duplicate fields" $ do
      -- Here, only the _first_ field should be updated
      arecSetSubset subARecDupes (toARec (#f2 =: "updated" :& RNil))
        `shouldBe` subARecDupesUpdated