packages feed

generic-case-0.1.0.0: test/Generics/Case/Custom/NoParamTypeSpec.hs

{-# LANGUAGE DeriveGeneric #-}

module Generics.Case.Custom.NoParamTypeSpec (spec) where

import qualified GHC.Generics as G
import Generics.Case
import Generics.Chain
import qualified Generics.SOP as SOP
import qualified Test.Hspec as H
import qualified Test.QuickCheck as Q
import Test.QuickCheck.Function
import Util

data NoParamType
  = NPT1
  | NPT2 Int
  | NPT3 String Char
  deriving (Show, Eq, G.Generic)

instance SOP.Generic NoParamType

instance Q.Arbitrary NoParamType where
  arbitrary =
    Q.oneof
      [ pure NPT1
      , NPT2 <$> Q.arbitrary
      , NPT3 <$> Q.arbitrary <*> Q.arbitrary
      ]
  shrink = Q.genericShrink

type NPTFn r = NoParamType -> r -> (Int -> r) -> (String -> Char -> r) -> r

type FunArgs r = '[NoParamType, r, Fun Int r, Fun String (Fun Char r)]

type NPTFun r = Chain (FunArgs r) r

manual :: NPTFn r
manual npt r fromInt fromStringChar = case npt of
  NPT1 -> r
  NPT2 int -> fromInt int
  NPT3 string char -> fromStringChar string char

nptL :: NPTFn r
nptL = gcase @NoParamType

specNPT ::
  forall r.
  ( Q.Arbitrary r
  , Show r
  , Eq r
  ) =>
  String ->
  NPTFn r ->
  H.Spec
specNPT name f =
  specG @(FunArgs r)
    ("manual", mkFn manual)
    (name, mkFn f)

mkFn ::
  NPTFn r ->
  NPTFun r
mkFn f npt' r f1 f2 = f npt' r (applyFun f1) (applyFun <$> applyFun f2)

spec :: H.Spec
spec = do
  H.describe "()" $ do
    specNPT @() "nptL" nptL
  H.describe "Char" $ do
    specNPT @Char "nptL" nptL
  H.describe "String" $ do
    specNPT @String "nptL" nptL
  H.describe "[Maybe (Int, String)]" $ do
    specNPT @[Maybe (Int, String)] "nptL" nptL