content: {-# 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
  