Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Updates for 0.12
  • Loading branch information
garyb committed May 3, 2018
commit 0920044cdc95e2620cd0474744693709d00f4ca1
33 changes: 17 additions & 16 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,24 @@
"package.json"
],
"dependencies": {
"purescript-arrays": "^4.3.0",
"purescript-console": "^3.0.0",
"purescript-either": "^3.0.0",
"purescript-enums": "^3.0.0",
"purescript-exceptions": "^3.0.0",
"purescript-gen": "^1.0.0",
"purescript-lists": "^4.0.0",
"purescript-nonempty": "^4.0.0",
"purescript-partial": "^1.2.0",
"purescript-random": "^3.0.0",
"purescript-strings": "^3.5.0",
"purescript-transformers": "^3.0.0",
"purescript-generics-rep": "^5.0.0",
"purescript-typelevel-prelude": "^2.4.0",
"purescript-record": "^0.2.0"
"purescript-arrays": "#compiler/0.12",
"purescript-console": "#compiler/0.12",
"purescript-either": "#compiler/0.12",
"purescript-enums": "#compiler/0.12",
"purescript-exceptions": "#compiler/0.12",
"purescript-gen": "#compiler/0.12",
"purescript-generics-rep": "#compiler/0.12",
"purescript-lcg": "#compiler/0.12",
"purescript-lists": "#compiler/0.12",
"purescript-nonempty": "#compiler/0.12",
"purescript-partial": "#compiler/0.12",
"purescript-random": "#compiler/0.12",
"purescript-record": "#compiler/0.12",
"purescript-strings": "#compiler/0.12",
"purescript-transformers": "#compiler/0.12",
"purescript-typelevel-prelude": "#compiler/0.12"
},
"devDependencies": {
"purescript-assert": "^3.0.0"
"purescript-assert": "#compiler/0.12"
}
}
32 changes: 13 additions & 19 deletions src/Test/QuickCheck.purs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
-- | main = quickCheck \n -> n + 1 > n
-- | ```
module Test.QuickCheck
( QC
, quickCheck
( quickCheck
, quickCheckGen
, quickCheck'
, quickCheckGen'
Expand All @@ -44,36 +43,31 @@ module Test.QuickCheck
, (>?)
, assertGreaterThanEq
, (>=?)
, module Test.QuickCheck.LCG
, module Random.LCG
, module Test.QuickCheck.Arbitrary
) where

import Prelude

import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, log)
import Control.Monad.Eff.Exception (EXCEPTION, throwException, error)
import Control.Monad.Eff.Random (RANDOM)
import Control.Monad.Rec.Class (Step(..), tailRec)
import Data.Foldable (for_)
import Data.List (List)
import Data.Maybe (Maybe(..))
import Data.Maybe.First (First(..))
import Data.Monoid (mempty)
import Data.Tuple (Tuple(..))
import Data.Unfoldable (replicateA)
import Effect (Effect)
import Effect.Console (log)
import Effect.Exception (throwException, error)
import Random.LCG (Seed, mkSeed, unSeed, randomSeed)
import Test.QuickCheck.Arbitrary (class Arbitrary, arbitrary, class Coarbitrary, coarbitrary)
import Test.QuickCheck.Gen (Gen, evalGen, runGen)
import Test.QuickCheck.LCG (Seed, runSeed, randomSeed)

-- | A type synonym which represents the effects used by the `quickCheck` function.
type QC eff a = Eff (console :: CONSOLE, random :: RANDOM, exception :: EXCEPTION | eff) a

-- | Test a property.
-- |
-- | This function generates a new random seed, runs 100 tests and
-- | prints the test results to the console.
quickCheck :: forall eff prop. Testable prop => prop -> QC eff Unit
quickCheck :: forall prop. Testable prop => prop -> Effect Unit
quickCheck prop = quickCheck' 100 prop

-- | A version of `quickCheck` with the property specialized to `Gen`.
Expand All @@ -84,31 +78,31 @@ quickCheck prop = quickCheck' 100 prop
-- | `MonadGen`-constrained properties as they will not infer correctly when
-- | used with the `quickCheck` functions unless an explicit type annotation is
-- | used.
quickCheckGen :: forall eff prop. Testable prop => Gen prop -> QC eff Unit
quickCheckGen :: forall prop. Testable prop => Gen prop -> Effect Unit
quickCheckGen = quickCheck

-- | A variant of the `quickCheck` function which accepts an extra parameter
-- | representing the number of tests which should be run.
quickCheck' :: forall eff prop. Testable prop => Int -> prop -> QC eff Unit
quickCheck' :: forall prop. Testable prop => Int -> prop -> Effect Unit
quickCheck' n prop = do
seed <- randomSeed
quickCheckWithSeed seed n prop

-- | A version of `quickCheck'` with the property specialized to `Gen`.
quickCheckGen' :: forall eff prop. Testable prop => Int -> Gen prop -> QC eff Unit
quickCheckGen' :: forall prop. Testable prop => Int -> Gen prop -> Effect Unit
quickCheckGen' = quickCheck'

-- | A variant of the `quickCheck'` function that accepts a specific seed as
-- | well as the number tests that should be run.
quickCheckWithSeed
:: forall eff prop. Testable prop => Seed -> Int -> prop -> QC eff Unit
:: forall prop. Testable prop => Seed -> Int -> prop -> Effect Unit
quickCheckWithSeed initialSeed n prop = do
let result = tailRec loop { seed: initialSeed, index: 0, successes: 0, firstFailure: mempty }
log $ show result.successes <> "/" <> show n <> " test(s) passed."
for_ result.firstFailure \{ index, message, seed: failureSeed } ->
throwException $ error
$ "Test " <> show (index + 1)
<> " (seed " <> show (runSeed failureSeed) <> ") failed: \n"
<> " (seed " <> show (unSeed failureSeed) <> ") failed: \n"
<> message
where
loop :: LoopState -> Step LoopState LoopState
Expand All @@ -133,7 +127,7 @@ quickCheckWithSeed initialSeed n prop = do
}

-- | A version of `quickCheckWithSeed` with the property specialized to `Gen`.
quickCheckGenWithSeed :: forall eff prop. Testable prop => Seed -> Int -> Gen prop -> QC eff Unit
quickCheckGenWithSeed :: forall prop. Testable prop => Seed -> Int -> Gen prop -> Effect Unit
quickCheckGenWithSeed = quickCheckWithSeed

type LoopState =
Expand Down
50 changes: 18 additions & 32 deletions src/Test/QuickCheck/Arbitrary.purs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ import Prelude

import Control.Monad.Gen.Class (chooseBool)
import Control.Monad.Gen.Common as MGC
import Control.Monad.ST (pureST)
import Control.Monad.ST as ST
import Data.Array.NonEmpty (NonEmptyArray)
import Data.Array.NonEmpty as NEA
import Data.Array.ST (pushSTArray, unsafeFreeze, unsafeThaw)
import Data.Char (toCharCode, fromCharCode)
import Data.Either (Either(..))
import Data.Foldable (foldl)
import Data.Generic.Rep (class Generic, to, from, NoArguments(..), Sum(..), Product(..), Constructor(..), Argument(..), Rec(..), Field(..))
import Data.Generic.Rep (class Generic, to, from, NoArguments(..), Sum(..), Product(..), Constructor(..), Argument(..))
import Data.Identity (Identity(..))
import Data.Int (toNumber)
import Data.Lazy (Lazy, defer, force)
Expand All @@ -31,16 +31,17 @@ import Data.List.NonEmpty (NonEmptyList(..))
import Data.Maybe (Maybe(..), fromJust)
import Data.Newtype (wrap)
import Data.NonEmpty (NonEmpty(..), (:|))
import Data.Record (insert)
import Data.Record as Record
import Data.String (charCodeAt, fromCharArray, split)
import Data.String.NonEmpty (NonEmptyString)
import Data.String.NonEmpty as NES
import Data.Symbol (class IsSymbol, SProxy(..))
import Data.Tuple (Tuple(..))
import Partial.Unsafe (unsafePartial)
import Prim.Row as Row
import Prim.RowList as RL
import Test.QuickCheck.Gen (Gen, arrayOf, chooseInt, elements, listOf, oneOf, perturbGen, repeatable, sized, uniform)
import Type.Prelude (class RowToList)
import Type.Row (kind RowList, class RowLacks, Nil, Cons, RLProxy(..))
import Type.Data.RowList (RLProxy(..))

-- | The `Arbitrary` class represents those types whose values can be
-- | _randomly-generated_.
Expand Down Expand Up @@ -117,13 +118,13 @@ instance arbArray :: Arbitrary a => Arbitrary (Array a) where
arbitrary = arrayOf arbitrary

instance coarbArray :: Coarbitrary a => Coarbitrary (Array a) where
coarbitrary = foldl (\f x -> f <<< coarbitrary x) id
coarbitrary = foldl (\f x -> f <<< coarbitrary x) identity

instance arbNonEmptyArray :: Arbitrary a => Arbitrary (NonEmptyArray a) where
arbitrary = do
x <- arbitrary
xs <- arbitrary
pure $ unsafePartial fromJust $ NEA.fromArray $ pureST do
pure $ unsafePartial fromJust $ NEA.fromArray $ ST.run do
mxs <- unsafeThaw xs
_ <- pushSTArray mxs x
unsafeFreeze mxs
Expand Down Expand Up @@ -163,7 +164,7 @@ instance arbitraryList :: Arbitrary a => Arbitrary (List a) where
arbitrary = sized \n -> chooseInt zero n >>= flip listOf arbitrary

instance coarbList :: Coarbitrary a => Coarbitrary (List a) where
coarbitrary = foldl (\f x -> f <<< coarbitrary x) id
coarbitrary = foldl (\f x -> f <<< coarbitrary x) identity

instance arbitraryIdentity :: Arbitrary a => Arbitrary (Identity a) where
arbitrary = Identity <$> arbitrary
Expand Down Expand Up @@ -193,7 +194,7 @@ instance arbitraryNoArguments :: Arbitrary NoArguments where
arbitrary = pure NoArguments

instance coarbitraryNoArguments :: Coarbitrary NoArguments where
coarbitrary NoArguments = id
coarbitrary NoArguments = identity

-- | To be able to evenly distribute over chains of Sum types we build up
-- | a collection of generators and choose between. Each right component
Expand Down Expand Up @@ -232,18 +233,6 @@ instance arbitraryArgument :: Arbitrary a => Arbitrary (Argument a) where
instance coarbitraryArgument :: Coarbitrary a => Coarbitrary (Argument a) where
coarbitrary (Argument a) = coarbitrary a

instance arbitraryRec :: Arbitrary a => Arbitrary (Rec a) where
arbitrary = Rec <$> arbitrary

instance coarbitraryRec :: Coarbitrary a => Coarbitrary (Rec a) where
coarbitrary (Rec a) = coarbitrary a

instance arbitraryField :: Arbitrary a => Arbitrary (Field s a) where
arbitrary = Field <$> arbitrary

instance coarbitraryField :: Coarbitrary a => Coarbitrary (Field s a) where
coarbitrary (Field a) = coarbitrary a

-- | A `Generic` implementation of the `arbitrary` member from the `Arbitrary` type class.
genericArbitrary :: forall a rep. Generic a rep => Arbitrary rep => Gen a
genericArbitrary = to <$> (arbitrary :: Gen rep)
Expand All @@ -253,30 +242,27 @@ genericCoarbitrary :: forall a rep. Generic a rep => Coarbitrary rep => a -> Gen
genericCoarbitrary x g = to <$> coarbitrary (from x) (from <$> g)

-- | A helper typeclass to implement `Arbitrary` for records.
class ArbitraryRowList
(list :: RowList)
(row :: # Type)
| list -> row where
class ArbitraryRowList list row | list -> row where
arbitraryRecord :: RLProxy list -> Gen (Record row)

instance arbitraryRowListNil :: ArbitraryRowList Nil () where
instance arbitraryRowListNil :: ArbitraryRowList RL.Nil () where
arbitraryRecord _ = pure {}

instance arbitraryRowListCons ::
( Arbitrary a
, ArbitraryRowList listRest rowRest
, RowLacks key rowRest
, RowCons key a rowRest rowFull
, RowToList rowFull (Cons key a listRest)
, Row.Lacks key rowRest
, Row.Cons key a rowRest rowFull
, RL.RowToList rowFull (RL.Cons key a listRest)
, IsSymbol key
) => ArbitraryRowList (Cons key a listRest) rowFull where
) => ArbitraryRowList (RL.Cons key a listRest) rowFull where
arbitraryRecord _ = do
value <- arbitrary
previous <- arbitraryRecord (RLProxy :: RLProxy listRest)
pure $ insert (SProxy :: SProxy key) value previous
pure $ Record.insert (SProxy :: SProxy key) value previous

instance arbitraryRecordInstance ::
( RowToList row list
( RL.RowToList row list
, ArbitraryRowList list row
) => Arbitrary (Record row) where
arbitrary = arbitraryRecord (RLProxy :: RLProxy list)
31 changes: 0 additions & 31 deletions src/Test/QuickCheck/Data/AlphaNumString.purs

This file was deleted.

13 changes: 6 additions & 7 deletions src/Test/QuickCheck/Gen.purs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ import Prelude

import Control.Alt (class Alt)
import Control.Lazy (class Lazy)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Random (RANDOM)
import Control.Monad.Gen.Class (class MonadGen)
import Control.Monad.Rec.Class (class MonadRec, Step(..), tailRecM)
import Control.Monad.State (State, runState, evalState)
Expand All @@ -50,9 +48,10 @@ import Data.Monoid.Additive (Additive(..))
import Data.Newtype (unwrap)
import Data.NonEmpty (NonEmpty, (:|))
import Data.Tuple (Tuple(..), fst, snd)
import Effect (Effect)
import Math ((%))
import Partial.Unsafe (unsafePartial)
import Test.QuickCheck.LCG (Seed, lcgPerturb, lcgN, lcgNext, runSeed, randomSeed)
import Random.LCG (Seed, lcgPerturb, lcgM, lcgNext, unSeed, randomSeed)

-- | Tests are parameterized by the `Size` of the randomly-generated data,
-- | the meaning of which depends on the particular generator used.
Expand Down Expand Up @@ -231,23 +230,23 @@ sample :: forall a. Seed -> Size -> Gen a -> Array a
sample seed sz g = evalGen (vectorOf sz g) { newSeed: seed, size: sz }

-- | Sample a random generator, using a randomly generated seed
randomSample' :: forall r a. Size -> Gen a -> Eff (random :: RANDOM | r) (Array a)
randomSample' :: forall a. Size -> Gen a -> Effect (Array a)
randomSample' n g = do
seed <- randomSeed
pure $ sample seed n g

-- | Get a random sample of 10 values
randomSample :: forall r a. Gen a -> Eff (random :: RANDOM | r) (Array a)
randomSample :: forall a. Gen a -> Effect (Array a)
randomSample = randomSample' 10

-- | A random generator which simply outputs the current seed
lcgStep :: Gen Int
lcgStep = Gen $ state f where
f s = Tuple (runSeed s.newSeed) (s { newSeed = lcgNext s.newSeed })
f s = Tuple (unSeed s.newSeed) (s { newSeed = lcgNext s.newSeed })

-- | A random generator which approximates a uniform random variable on `[0, 1]`
uniform :: Gen Number
uniform = (\n -> toNumber n / toNumber lcgN) <$> lcgStep
uniform = (\n -> toNumber n / toNumber lcgM) <$> lcgStep

foreign import float32ToInt32 :: Number -> Int

Expand Down
Loading