Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add property tests for the Validation type #216

Merged
merged 3 commits into from
Oct 25, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion relude.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ test-suite relude-test
main-is: Spec.hs

other-modules: Test.Relude.Property

, Test.Relude.Extra.Validation.Property
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commas are redundant in module definitions

Suggested change
, Test.Relude.Extra.Validation.Property
Test.Relude.Extra.Validation.Property

build-depends: relude
, bytestring
, text
Expand Down
170 changes: 170 additions & 0 deletions test/Test/Relude/Extra/Validation/Property.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
{-
Copyright: (c) 2016 Stephen Diehl
(c) 2016-2018 Serokell
(c) 2018-2019 Kowainik
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe there's no need to specify everyone here, since it's a brand new module. So this can be just:

Copyright:  (c) 2019 Kowainik

SPDX-License-Identifier: MIT
Maintainer: Kowainik <xrom.xkov@gmail.com>
-}

module Test.Relude.Extra.Validation.Property
( validationTestList
) where

import Relude
import Relude.Extra.Validation

import Hedgehog (Gen, Group (..), Property, forAll, forAllWith, property, (===))

import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range

validationTestList :: [Group]
validationTestList =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rename List suffix to Laws or Group to have better semantics

[ validationSemigroupProps
, validationMonoidProps
, validationApplicativeProps
, validationAlternativeProps
]

----------------------------------------------------------------------------
-- Generators
----------------------------------------------------------------------------

genFunction :: Gen (Int -> Int)
genFunction = Gen.element [(+), (*), const] <*> genSmallInt

genSmallInt :: Gen Int
genSmallInt = Gen.int (Range.linear (-10) 10)

genSmallText :: Gen Text
genSmallText = Gen.text (Range.linear 3 10) Gen.unicode

asValidation :: Gen a -> Gen (Validation [Text] a)
asValidation gen = Gen.choice
[ Success <$> gen
, Failure <$> Gen.list (Range.linear 1 5) genSmallText
]

----------------------------------------------------------------------------
-- Property helpers
----------------------------------------------------------------------------

checkAssotiativityFor
:: (Show a, Eq a) => Gen a -> (a -> a -> a) -> Property
checkAssotiativityFor gen op = property $ do
a <- forAll gen
b <- forAll gen
c <- forAll gen
a `op` (b `op` c) === (a `op` b) `op` c

----------------------------------------------------------------------------
-- Semogroup instance properties
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor typo 🙂

Suggested change
-- Semogroup instance properties
-- Semigroup instance properties

----------------------------------------------------------------------------

validationSemigroupProps :: Group
validationSemigroupProps =
Group "Semigroup instance for Validation property tests"
[ ("associativity:", prop_semigroupAssociativity)
]

prop_semigroupAssociativity :: Property
prop_semigroupAssociativity =
checkAssotiativityFor (asValidation genSmallText) (<>)

----------------------------------------------------------------------------
-- Monoid instance properties
----------------------------------------------------------------------------

validationMonoidProps :: Group
validationMonoidProps =
Group "Monoid instance for Validation property tests"
[ ("right identity:", prop_monoidRightIdentity)
, ("left identity:", prop_monoidLeftIdentity)
]

prop_monoidRightIdentity :: Property
prop_monoidRightIdentity = property $ do
x <- forAll $ asValidation genSmallText
x <> mempty === x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning: Monoid law, right identity

Suggested change
x <> mempty === x
x === x


prop_monoidLeftIdentity :: Property
prop_monoidLeftIdentity = property $ do
x <- forAll $ asValidation genSmallText
mempty <> x === x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning: Monoid law, left identity

Suggested change
mempty <> x === x
x === x


----------------------------------------------------------------------------
-- Applicative instance properties
----------------------------------------------------------------------------

validationApplicativeProps :: Group
validationApplicativeProps =
Group "Applicative instance for Validation property tests"
[ ("identity:", prop_applicativeIdentity)
, ("composition:", prop_applicativeComposition)
, ("homomorphism:", prop_applicativeHomomorphism)
, ("interchange:", prop_applicativeInterchange)
, ("u *> v == (id <$ u) <*> v", prop_applicativeApplyRight)
, ("u <* v == liftA2 const u v", prop_applicativeApplyLeft)
]

prop_applicativeIdentity :: Property
prop_applicativeIdentity = property $ do
vx <- forAll $ asValidation genSmallText
(pure id <*> vx) === vx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Use <$>

Suggested change
(pure id <*> vx) === vx
(id <$> vx) === vx


prop_applicativeComposition :: Property
prop_applicativeComposition = property $ do
vf <- forAllWith (const "f") $ asValidation genFunction
vg <- forAllWith (const "g") $ asValidation genFunction
vx <- forAll $ asValidation genSmallInt
(pure (.) <*> vf <*> vg <*> vx) === (vf <*> (vg <*> vx))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Use <$>

Suggested change
(pure (.) <*> vf <*> vg <*> vx) === (vf <*> (vg <*> vx))
(((.) <$> vf) <*> vg <*> vx) === (vf <*> (vg <*> vx))


prop_applicativeHomomorphism :: Property
prop_applicativeHomomorphism = property $ do
f <- forAllWith (const "f") genFunction
x <- forAll genSmallInt
(pure f <*> (pure x :: Validation [Text] Int)) === pure (f x)
chshersh marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be written a bit cleaner with type applications

Suggested change
(pure f <*> (pure x :: Validation [Text] Int)) === pure (f x)
(pure f <*> pure x) === pure @(Validation [Text]) (f x)


prop_applicativeInterchange :: Property
prop_applicativeInterchange = property $ do
vf <- forAllWith (const "f") $ asValidation genFunction
x <- forAll genSmallInt
(vf <*> pure x) === (pure ($ x) <*> vf)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Use <$>

Suggested change
(vf <*> pure x) === (pure ($ x) <*> vf)
(vf <*> pure x) === (($ x) <$> vf)


prop_applicativeApplyRight :: Property
prop_applicativeApplyRight = property $ do
vy <- forAll $ asValidation genSmallInt
vx <- forAll $ asValidation genSmallInt
(vy *> vx) === ((id <$ vy) <*> vx)

prop_applicativeApplyLeft :: Property
prop_applicativeApplyLeft = property $ do
vy <- forAll $ asValidation genSmallInt
vx <- forAll $ asValidation genSmallInt
(vy <* vx) === liftA2 const vy vx

----------------------------------------------------------------------------
-- Alternative instance properties
----------------------------------------------------------------------------

validationAlternativeProps :: Group
validationAlternativeProps =
Group "Alternative instance for Validation property tests"
[ ("associativity:", prop_alternativeAssociativity)
, ("right identity:", prop_alternativeRightIdentity)
, ("left identity:", prop_alternativeLeftIdentity)
]

prop_alternativeAssociativity :: Property
prop_alternativeAssociativity =
checkAssotiativityFor (asValidation genSmallText) (<|>)

prop_alternativeRightIdentity :: Property
prop_alternativeRightIdentity = property $ do
x <- forAll $ asValidation genSmallText
(x <|> empty) === x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning: Alternative law, right identity

Suggested change
(x <|> empty) === x
(x) === x


prop_alternativeLeftIdentity :: Property
prop_alternativeLeftIdentity = property $ do
x <- forAll $ asValidation genSmallText
(empty <|> x) === x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning: Alternative law, left identity

Suggested change
(empty <|> x) === x
(x) === x

7 changes: 6 additions & 1 deletion test/Test/Relude/Property.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module Test.Relude.Property
) where

import Relude
import Test.Relude.Extra.Validation.Property (validationTestList)

import Data.List (nub)
import Hedgehog (Gen, Property, Group (..), assert, forAll, property, (===))
Expand All @@ -19,7 +20,11 @@ import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range

hedgehogTestList :: [Group]
hedgehogTestList = [utfProps, listProps, logicProps]
hedgehogTestList =
[ utfProps
, listProps
, logicProps
] <> validationTestList

----------------------------------------------------------------------------
-- utf8 conversion
Expand Down