higgledy-0.3.0.0: test/Main.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Main where
import Control.Lens (Lens', (.~), (^.))
import Data.Barbie
import Data.Barbie.Constraints (Dict)
import Data.Function ((&), on)
import Data.Functor.Identity (Identity (..))
import Data.Functor.Product (Product (..))
import Data.Generic.HKD
import Data.Monoid (Last (..))
import GHC.Generics
import Test.DocTest
import Test.Hspec
import Test.QuickCheck
type Partial a = HKD a Last
type WTF a = HKD a []
main :: IO ()
main = do
doctest ["src", "test"]
hspec do
describe "Unnamed" do
eq @(Partial Triple)
ord @(Partial Triple)
semigroup @(Partial Triple)
idempotent @(Partial Triple)
monoid @(Partial Triple)
eq @(WTF Triple)
ord @(WTF Triple)
semigroup @(WTF Triple)
monoid @(WTF Triple)
lens @(Partial Triple) (position @1)
lens @(Partial Triple) (position @2)
lens @(Partial Triple) (position @3)
lens @(WTF Triple) (position @1)
lens @(WTF Triple) (position @2)
lens @(WTF Triple) (position @3)
describe "Named" do
eq @(Partial Person)
ord @(Partial Person)
semigroup @(Partial Person)
idempotent @(Partial Person)
monoid @(Partial Person)
eq @(WTF Person)
ord @(WTF Person)
semigroup @(WTF Person)
monoid @(WTF Person)
lens @(WTF Person) (position @1)
lens @(WTF Person) (position @2)
lens @(WTF Person) (position @3)
lens @(Partial Person) (field @"name")
lens @(Partial Person) (field @"age")
lens @(Partial Person) (field @"likesDogs")
lens @(WTF Person) (field @"name")
lens @(WTF Person) (field @"age")
lens @(WTF Person) (field @"likesDogs")
-------------------------------------------------------------------------------
data Person
= Person
{ name :: String
, age :: Int
, likesDogs :: Bool
}
deriving (Eq, Generic, Ord, Show)
data Triple
= Triple String Bool ()
deriving (Eq, Generic, Ord, Show)
instance Arbitrary Person where
arbitrary = Person <$> arbitrary <*> arbitrary <*> arbitrary
instance CoArbitrary Person
instance Function Person
instance Arbitrary Triple where
arbitrary = Triple <$> arbitrary <*> arbitrary <*> arbitrary
instance CoArbitrary Triple
instance Function Triple
-------------------------------------------------------------------------------
eq
:: forall a. (Arbitrary a, CoArbitrary a, Eq a, Function a, Show a)
=> SpecWith ()
eq = describe "Eq" do
it "is reflexive" $ property \(x :: a) ->
x == x
it "is symmetric" $ property \(x :: a) y ->
(x == y) == (y == x)
it "is transitive" $ property \(x :: a) y z ->
not (x == y && y == z) || (x == z)
it "substitutes" $ property \(x :: a) y (Fun _ f :: Fun a Int) ->
not (x == y) || (f x == f y)
ord :: forall a. (Arbitrary a, Ord a, Show a) => SpecWith ()
ord = describe "Ord" do
it "is transitive" $ property \(x :: a) y z ->
not (x <= y && y <= z) || (x <= z)
it "is reflexive" $ property \(x :: a) ->
x <= x
it "is antisymmetric" $ property \(x :: a) y ->
not (x <= y && y <= x) || (x == y)
semigroup :: forall a. (Arbitrary a, Eq a, Semigroup a, Show a) => SpecWith ()
semigroup = describe "Semigroup" do
it "is associative" $ property \(x :: a) y z ->
x <> (y <> z) == (x <> y) <> z
idempotent :: forall a. (Arbitrary a, Eq a, Semigroup a, Show a) => SpecWith ()
idempotent = describe "Idempotence" do
it "has right idempotence" $ property \(x :: a) y ->
x <> y <> y == x <> y
monoid :: forall a. (Arbitrary a, Eq a, Monoid a, Show a) => SpecWith ()
monoid = describe "Monoid" do
it "has left identity" $ property \(x :: a) -> mempty <> x == x
it "has right identity" $ property \(x :: a) -> x <> mempty == x
lens
:: forall s a
. ( Arbitrary s, Arbitrary a
, Show s, Show a
, Eq a, Eq s
)
=> Lens' s a
-> SpecWith ()
lens l = describe "Lens laws" do
it "- get l . set l x == x" $ property \(s :: s) (a :: a) ->
(s & l .~ a) ^. l == a
it "- set l (get l s) == s" $ property \(s :: s) ->
(s & l .~ (s ^. l)) == s
it "- set l b . set l a == set l b" $ property \(s :: s) (a :: a) (b :: a) ->
(s & l .~ a & l .~ b) == (s & l .~ b)
-------------------------------------------------------------------------------
partials
:: forall a
. ( Arbitrary a
, Show a
, Ord a
, Generic a
, Construct Last a
, Construct [] a
, Ord (Partial a)
, Ord (WTF a)
)
=> SpecWith ()
partials = describe "HKD" do
describe "Eq" do
it "is monotonic with respect to ordering (Partial)" $ property \(x :: a) y ->
(x <= y) == ((<=) `on` deconstruct @Last) x y
it "is monotonic with respect to ordering (WTF)" $ property \(x :: a) y ->
(x <= y) == ((<=) `on` deconstruct @[]) x y
it "round-trips" $ property \(x :: a) ->
construct (deconstruct @Last x) == pure x
it "round-trips" $ property \(x :: a) ->
construct (deconstruct @[] x) == pure x
-- Just to test that `baddDicts` does what it's told.
data Y = Y { getY :: Int } deriving (Generic, Show)
test :: HKD Y (Product (Dict Num) Identity)
test = baddDicts test
where
test :: HKD Y Identity
test = deconstruct @Identity (Y 10)