packages feed

large-records-0.1.0.0: test/Test/Record/Sanity/RecordConstruction.hs

{-# LANGUAGE ConstraintKinds       #-}
{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE QuasiQuotes           #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE UndecidableInstances  #-}

{-# OPTIONS_GHC -F -pgmF=record-dot-preprocessor #-}
-- {-# OPTIONS_GHC -ddump-splices #-}
{-# OPTIONS_GHC -Wwarn #-}

module Test.Record.Sanity.RecordConstruction (tests) where

import Data.Record.TH

import Test.Tasty
import Test.Tasty.HUnit

-- Test that this works if we don't generate field accessors
-- See <https://gitlab.haskell.org/ghc/ghc/-/issues/19312>
--
-- Use lazy fields so that we can test values with missing fields.
--
-- Test both the case where the name of the type and the name of the constructor
-- are the same and where they are different.
largeRecord (defaultPureScript {allFieldsStrict = False}) [d|
    data R a = MkR { x :: Int, y :: [a] } deriving (Eq, Show)
    data S a = S   { x :: Int, y :: [a] } deriving (Eq, Show)
  |]

inOrder :: R Bool
inOrder = [lr| MkR { x = 1234, y = [True] } |]

outOfOrder :: R Bool
outOfOrder = [lr| MkR { y = [True], x = 1234 } |]

-- | Constructor application
--
-- Occassionally we cannot use the quasi-quoter (for instance, in an
-- applicative context).
constructorApp :: R Bool
constructorApp = [lr| MkR |] 1234 [True]

valueOfS :: S Bool
valueOfS = [lr| S { x = 1234, y = [True] } |]

{-------------------------------------------------------------------------------
  Nested records
-------------------------------------------------------------------------------}

data RegularRecord = RR { a :: Int }
  deriving (Show, Eq)

largeRecord defaultPureScript [d|
    data T = T { x :: Int, y :: S Bool, z :: RegularRecord }
  |]

valueOfT :: T
valueOfT = [lr| T { x = 5
                  , y = S { x = 1234, y = [True] }
                  , z = RR { a = 5 }
                  }
              |]

{-------------------------------------------------------------------------------
  Sanity check
-------------------------------------------------------------------------------}

tests :: TestTree
tests = testGroup "Test.Record.Sanity.RecordConstruction" [
      testCase "allEqual" testAllEqual
    ]

testAllEqual :: Assertion
testAllEqual = do
    assertEqual "inOrder/outOfOrder" inOrder.x  outOfOrder.x
    assertEqual "inOrder/withoutQQ"  inOrder.x  constructorApp.x
    assertEqual "R/S"                inOrder.x  valueOfS.x
    assertEqual "T/S"                valueOfT.y valueOfS
    assertEqual "T/R"                valueOfT.z (RR 5)