linear-tests (empty) → 0.1.1.0
raw patch · 15 files changed
+545/−0 lines, 15 filesdep +QuickCheckdep +basedep +hspecsetup-changed
Dependencies added: QuickCheck, base, hspec, hspec-core, lens, linear, linear-tests
Files
- ChangeLog.md +8/−0
- LICENSE +30/−0
- README.md +8/−0
- Setup.hs +2/−0
- linear-tests.cabal +69/−0
- src/Linear/Arbitrary.hs +11/−0
- src/Linear/Matrix/Arbitrary.hs +66/−0
- src/Linear/Quaternion/Arbitrary.hs +28/−0
- src/Linear/V3/Arbitrary.hs +48/−0
- src/Linear/V4/Arbitrary.hs +23/−0
- test/Linear/MatrixSpec.hs +92/−0
- test/Linear/QuaternionSpec.hs +54/−0
- test/Linear/V3Spec.hs +71/−0
- test/Linear/V4Spec.hs +33/−0
- test/Spec.hs +2/−0
+ ChangeLog.md view
@@ -0,0 +1,8 @@+# Changelog for linear-tests++## 0.1.1 [2020.02.16]+- Added `InvertibleM33`+- Added `BasisV3`++## 0.1 [2020.02.14]+- Added various Arbitrary instances for `V3`, `V4`, `M33`, `M44`, and `Quaternion`.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Peter Lu (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Author name here nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,8 @@+[](https://circleci.com/gh/pdlla/linear-tests)++# linear-tests+This library provides [QuickCheck](https://hackage.haskell.org/package/QuickCheck) `Arbitrary` instances of data types in the [linear](http://hackage.haskell.org/package/linear) package.++The property tests in this package test both the newly defined `Arbitrary` instances as well as methods in the linear package itself. It's hard to distinguish between the two types of test so they are all just lumped together.++The current instances are just ones I (and hopefully others) find useful. Feel free to add your own and submit a PR.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ linear-tests.cabal view
@@ -0,0 +1,69 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 7d0fbb63b1f76fdccf74b6a953e18091d9a95568447c823ca6244cc4a413b720++name: linear-tests+version: 0.1.1.0+synopsis: Linear Algebra+description: Please see the README on GitHub at <https://github.com/pdlla/linear-tests#readme>+category: Math, Algebra, Testing+homepage: https://github.com/pdlla/linear-tests#readme+bug-reports: https://github.com/pdlla/linear-tests/issues+author: pdlla+maintainer: chippermonky@gmail.com+copyright: 2020 pdlla+license: BSD3+license-file: LICENSE+build-type: Simple+extra-source-files:+ README.md+ ChangeLog.md++source-repository head+ type: git+ location: https://github.com/pdlla/linear-tests++library+ exposed-modules:+ Linear.Arbitrary+ Linear.Matrix.Arbitrary+ Linear.Quaternion.Arbitrary+ Linear.V3.Arbitrary+ Linear.V4.Arbitrary+ other-modules:+ Paths_linear_tests+ hs-source-dirs:+ src+ ghc-options: -Wall+ build-depends:+ QuickCheck+ , base >=4.7 && <5+ , lens+ , linear+ default-language: Haskell2010++test-suite linear-tests-test+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ Linear.MatrixSpec+ Linear.QuaternionSpec+ Linear.V3Spec+ Linear.V4Spec+ Paths_linear_tests+ hs-source-dirs:+ test+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ QuickCheck+ , base >=4.7 && <5+ , hspec+ , hspec-core+ , lens+ , linear+ , linear-tests+ default-language: Haskell2010
+ src/Linear/Arbitrary.hs view
@@ -0,0 +1,11 @@+++module Linear.Arbitrary (+ module Linear.Matrix.Arbitrary,+ module Linear.Quaternion.Arbitrary,+ module Linear.V3.Arbitrary+) where++import Linear.Matrix.Arbitrary+import Linear.Quaternion.Arbitrary+import Linear.V3.Arbitrary
+ src/Linear/Matrix/Arbitrary.hs view
@@ -0,0 +1,66 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Linear.Matrix.Arbitrary (+ InvertibleM33(..)+ , DiagM33(..)+ , InvertibleM44(..)+ , AffineM44(..)+ , InvertibleAffineM44(..)+) where++import Control.Lens++import Linear.Epsilon+import Linear.Matrix+import Linear.Metric+import qualified Linear.V3 as V3+import qualified Linear.V4 as V4+import Test.QuickCheck++import Linear.V3.Arbitrary ()+import Linear.V4.Arbitrary ()+++-- | `Arbitrary InvertibleM33` instances are always invertible+newtype InvertibleM33 a = InvertibleM33 { unInvertibleM33 :: M33 a } deriving (Show)++instance (Arbitrary a, Epsilon a, Floating a) => Arbitrary (InvertibleM33 a) where+ arbitrary = fmap InvertibleM33 $ (V3.V3 <$> arbitrary <*> arbitrary <*> arbitrary) `suchThat` (not . nearZero . det33)++-- | `Arbitrary DiagM33` instances only have non-zero diagonal entries (could still be zero)+newtype DiagM33 a = DiagM33 { unDiagM33 :: M33 a } deriving (Show)++instance (Arbitrary a, Num a) => Arbitrary (DiagM33 a) where+ arbitrary = do+ s1 <- arbitrary+ s2 <- arbitrary+ s3 <- arbitrary+ return . DiagM33 $ V3.V3+ (V3.V3 s1 0 0)+ (V3.V3 0 s2 0)+ (V3.V3 0 0 s3)++newtype InvertibleM44 a = InvertibleM44 { unInvertibleM44 :: M44 a } deriving (Show)++instance (Arbitrary a, Epsilon a, Floating a) => Arbitrary (InvertibleM44 a) where+ arbitrary = fmap InvertibleM44 $ (V4.V4 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary) `suchThat` (not . nearZero . det44)++-- | `Arbitrary AffineM44` instances are affine M44 matrices (i.e. have [0,0,0,1] in last row)+newtype AffineM44 a = AffineM44 { unAffineM44 :: M44 a } deriving (Show)++instance (Arbitrary a, Num a) => Arbitrary (AffineM44 a) where+ arbitrary = do+ r1 <- arbitrary+ r2 <- arbitrary+ r3 <- arbitrary+ return . AffineM44 $ V4.V4 r1 r2 r3 (V4.V4 0 0 0 1)+++-- | `Arbitrary InvertibleAffineM44` instances are invertible affine M44 matrices+newtype InvertibleAffineM44 a = InvertibleAffineM44 { unInvertibleAffineM44 :: M44 a } deriving (Show)++instance (Arbitrary a, Num a) => Arbitrary (InvertibleAffineM44 a) where+ arbitrary = do+ m33part <- m33_to_m44 <$> arbitrary+ trans <- arbitrary+ return . InvertibleAffineM44 $ set (V4._w . V4._w) 1 . set translation trans $ m33part
+ src/Linear/Quaternion/Arbitrary.hs view
@@ -0,0 +1,28 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Linear.Quaternion.Arbitrary (+ CartesianQuaternion(..)+) where++import Linear.Epsilon+import Linear.Matrix ()+import Linear.Quaternion+import Linear.V3.Arbitrary++import Test.QuickCheck++-- | `Arbitrary Quaternion` instance+instance (Arbitrary a, Epsilon a, Floating a) => Arbitrary (Quaternion a) where+ arbitrary = do+ UnitV3 v <- arbitrary+ r <- arbitrary+ return $ axisAngle v r++-- | Arbitrary instances of this type are restricted to increment of 90 degrees along cartesian axis+newtype CartesianQuaternion a = CartesianQuaternion { unCartesianQuaternion :: Quaternion a } deriving (Show)++instance (Arbitrary a, Epsilon a, Floating a) => Arbitrary (CartesianQuaternion a) where+ arbitrary = do+ CartesianUnitV3 v <- arbitrary+ r <- elements [0, pi/2, pi, 3*pi/2]+ return . CartesianQuaternion $ axisAngle v r
+ src/Linear/V3/Arbitrary.hs view
@@ -0,0 +1,48 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Linear.V3.Arbitrary (+ UnitV3(..)+ , CartesianUnitV3(..)+ , BasisV3(..)+) where++import Control.Lens hiding (elements)++import Linear.Conjugate+import Linear.Epsilon+import Linear.Metric+import qualified Linear.Quaternion as Q+import Linear.V3+import Linear.Vector++import Test.QuickCheck++-- | `Arbitrary V3` has no restrictions on components+instance (Arbitrary a) => Arbitrary (V3 a) where+ arbitrary = V3 <$> arbitrary <*> arbitrary <*> arbitrary++-- | `Arbitrary UnitV3` always has norm 1+newtype UnitV3 a = UnitV3 {unUnitV3 :: V3 a} deriving (Show)++instance (Arbitrary a, Epsilon a, Floating a) => Arbitrary (UnitV3 a) where+ arbitrary = do+ v <- V3 <$> arbitrary <*> arbitrary <*> (arbitrary `suchThat` (not . nearZero))+ return . UnitV3 . signorm $ v++-- | `Arbitrary CartesianUnitV3` is a unit vector along cartesian axis+newtype CartesianUnitV3 a = CartesianUnitV3 {unCartesianUnitV3 :: V3 a} deriving (Show)++instance (Arbitrary a, Epsilon a, Floating a) => Arbitrary (CartesianUnitV3 a) where+ arbitrary = elements $ CartesianUnitV3 <$> [unit _x, unit _y, unit _z, - (unit _x), - (unit _y), - (unit _z)]++-- | `Aribtrary BasisV3` is a orthonormal set of vectors+newtype BasisV3 a = BasisV3 { unBasisV3 :: (V3 a, V3 a, V3 a) } deriving (Show)++instance (Arbitrary a, Epsilon a, Floating a) => Arbitrary (BasisV3 a) where+ arbitrary = do+ UnitV3 x <- arbitrary+ o <- arbitrary `suchThat` (not . nearZero . dot x)+ let+ y = signorm $ cross x o+ z = cross x y+ return $ BasisV3 (x, y, z)
+ src/Linear/V4/Arbitrary.hs view
@@ -0,0 +1,23 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Linear.V4.Arbitrary (+ UnitV4(..)+) where++import Linear.Epsilon+import Linear.Metric+import Linear.V4++import Test.QuickCheck++-- | `Arbitrary V4` has no restrictions on components+instance (Arbitrary a) => Arbitrary (V4 a) where+ arbitrary = V4 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary++-- | `Arbitrary UnitV4` always has norm 1+newtype UnitV4 a = UnitV4 {unUnitV4 :: V4 a} deriving (Show)++instance (Arbitrary a, Epsilon a, Floating a) => Arbitrary (UnitV4 a) where+ arbitrary = do+ v <- V4 <$> arbitrary <*> arbitrary <*> arbitrary <*> (arbitrary `suchThat` (not . nearZero))+ return . UnitV4 . signorm $ v
+ test/Linear/MatrixSpec.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+++module Linear.MatrixSpec (+ spec+) where++import Test.Hspec+import Test.QuickCheck++import Control.Lens++import Linear.Epsilon+import qualified Linear.Matrix as M+import qualified Linear.V3 as V3+import qualified Linear.V4 as V4++import Linear.Matrix.Arbitrary+++-- | test the property `m * m^-1 == identity`+prop_Matrix_InvertibleM33_isInvertible :: (Epsilon a, Floating a) => InvertibleM33 a -> Bool+prop_Matrix_InvertibleM33_isInvertible (InvertibleM33 m) = nearZero ((m M.!*! M.inv33 m ) - M.identity)++isDiagonal :: (Epsilon a) => M.M33 a -> Bool+isDiagonal m33 = all nearZero $ map (`view` m33) [+ V3._x . V3._y+ , V3._x . V3._z+ , V3._y . V3._x+ , V3._y . V3._z+ , V3._z . V3._x+ , V3._z . V3._y]++-- | test the property that all off diagonal entries are zero+prop_Matrix_DiagM33_isDiagonal :: (Epsilon a, Floating a) => DiagM33 a -> Bool+prop_Matrix_DiagM33_isDiagonal = isDiagonal . unDiagM33++isAffine :: (Epsilon a, Floating a) => M.M44 a -> Bool+isAffine m44 = nearZero $ view V4._w m44 - V4.V4 0 0 0 1++-- | test the property `m * m^-1 == identity`+prop_Matrix_InvertibleM44_isInvertible :: (Epsilon a, Floating a) => InvertibleM44 a -> Bool+prop_Matrix_InvertibleM44_isInvertible (InvertibleM44 m) = nearZero ((m M.!*! M.inv44 m ) - M.identity)++-- | test the property that last row is [0,0,0,1]+prop_Matrix_AffineM44_isAffine :: (Epsilon a, Floating a) => AffineM44 a -> Bool+prop_Matrix_AffineM44_isAffine (AffineM44 m44) = isAffine m44++-- | test that it is closed under multiplication+prop_Matrix_AffineM44_isClosedUnderMultiplication :: (Epsilon a, Floating a) => NonEmptyList (AffineM44 a) -> Bool+prop_Matrix_AffineM44_isClosedUnderMultiplication = isAffine . foldr1 (M.!*!) . map unAffineM44 . getNonEmpty++-- | test the property that last row is [0,0,0,1]+prop_Matrix_InvertibleAffineM44_isAffine :: (Epsilon a, Floating a) => InvertibleAffineM44 a -> Bool+prop_Matrix_InvertibleAffineM44_isAffine (InvertibleAffineM44 m44) = isAffine m44++-- | test the property `m * m^-1 == identity`+prop_Matrix_InvertibleAffineM44_isInvertible :: (Epsilon a, Floating a) => InvertibleAffineM44 a -> Bool+prop_Matrix_InvertibleAffineM44_isInvertible (InvertibleAffineM44 m44) = isAffine m44++spec :: Spec+spec = specTyped @Double++specTyped :: forall a. (Eq a, Show a, Arbitrary a, Epsilon a, Floating a) => Spec+specTyped = do+ describe "Matrix" $ do+ describe "M33" $ do+ describe "Arbitrary" $ do+ describe "InvertibleM33" $ do+ it "satifies property `m * m^-1 == identity`" $+ property $ prop_Matrix_InvertibleM33_isInvertible @a+ describe "DiagM33" $ do+ it "satisfies property that all off diagonal entries are zero" $+ property $ prop_Matrix_DiagM33_isDiagonal @a+ describe "M44" $ do+ describe "Arbitrary" $ do+ describe "InvertibleM44" $ do+ it "satifies property `m * m^-1 == identity`" $+ property $ prop_Matrix_InvertibleM44_isInvertible @a+ describe "AffineM44" $ do+ it "satisfies property [0,0,0,1] in last row" $+ property $ prop_Matrix_AffineM44_isAffine @a+ it "is closed under multiplication" $+ property $ prop_Matrix_AffineM44_isClosedUnderMultiplication @a+ describe "InvertibleAffineM44" $ do+ it "satisfies property [0,0,0,1] in last row" $+ property $ prop_Matrix_InvertibleAffineM44_isAffine @a+ it "satifies `m * m^-1 == identity`" $+ property $ prop_Matrix_InvertibleAffineM44_isInvertible @a
+ test/Linear/QuaternionSpec.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+++module Linear.QuaternionSpec (+ spec+) where++import Test.Hspec+import Test.QuickCheck++import Linear.Conjugate+import Linear.Epsilon+import Linear.Metric+import qualified Linear.Quaternion as Q+import qualified Linear.V3 as V++import Linear.Quaternion.Arbitrary+import Linear.V3.Arbitrary++-- | tests for the property `|(q*v)·v| = 1 or 0`+prop_CartesianQuaternion_arbitrary :: (Show a, Epsilon a, RealFloat a, Conjugate a) => CartesianQuaternion a -> CartesianUnitV3 a -> Bool+prop_CartesianQuaternion_arbitrary (CartesianQuaternion q) (CartesianUnitV3 v) = nearZero qvv || nearZero (qvv - 1) where+ qvv = abs $ Q.rotate q v `dot` v++-- | tests for the property `|q| = 1`+prop_Quaternion_arbitrary :: (Epsilon a, RealFloat a, Conjugate a) => Q.Quaternion a -> Bool+prop_Quaternion_arbitrary q = nearZero $ norm q - 1++-- | tests for the property `q * conjugate(q) = identity`+prop_Quaternion_conjugate :: (Epsilon a, RealFloat a, Conjugate a) => Q.Quaternion a -> Bool+prop_Quaternion_conjugate q = nearZero $ distance (q * conjugate q) (Q.Quaternion 1 (V.V3 0 0 0))++identityQuaternion :: (RealFloat a) => Q.Quaternion a+identityQuaternion = 1 -- Quaternion 1 (V3 0 0 0)++spec :: Spec+spec = specTyped @Double++specTyped :: forall a. (Eq a, Show a, Arbitrary a, Epsilon a, RealFloat a, Conjugate a) => Spec+specTyped = do+ describe "Quaternion" $ do+ describe "Arbitrary" $ do+ describe "Quaternion" $ do+ it "satisfies the property `|q| = 1`" $+ property $ prop_Quaternion_arbitrary @a+ describe "CartesianQuaternion" $ do+ it "satisfies the property `|(q*v)·v| = 1 or 0`" $+ property $ prop_CartesianQuaternion_arbitrary @a+ describe "Conjugate" $ do+ it "satisfies the property `q * conjugate(q) = identity`" $+ property $ prop_Quaternion_conjugate @a
+ test/Linear/V3Spec.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+++module Linear.V3Spec (+ spec+) where++import Test.Hspec+import Test.QuickCheck++import Linear.Epsilon+import Linear.Metric+import Linear.Vector++import Linear.V3.Arbitrary++-- | test for the property `|v| = 1`+prop_UnitV3_isUnit :: (Epsilon a, Floating a) => UnitV3 a -> Bool+prop_UnitV3_isUnit (UnitV3 v) = nearZero $ norm v - 1++-- | test for the property `|v| = 1`+prop_CartesianUnitV3_isUnit :: (Epsilon a, Floating a) => CartesianUnitV3 a -> Bool+prop_CartesianUnitV3_isUnit (CartesianUnitV3 v) = nearZero $ norm v - 1++-- | test for the property `|u·v| = 1 or 0`+prop_CartesianUnitV3_isOrthogonal :: (Epsilon a, Floating a) => CartesianUnitV3 a -> CartesianUnitV3 a -> Bool+prop_CartesianUnitV3_isOrthogonal (CartesianUnitV3 u) (CartesianUnitV3 v) = nearZero uv || nearZero (uv - 1) where+ uv = abs $ u `dot` v++-- | test for the property that all vectors are orthogonal and normal+prop_BasisV3_isOrthonormal :: (Epsilon a, Floating a) => BasisV3 a -> Bool+prop_BasisV3_isOrthonormal (BasisV3 (x,y,z)) =+ nearZero (dot x y) && nearZero (dot y z) && nearZero (dot z x)+ && nearZero (norm x - 1) && nearZero (norm y - 1) && nearZero (norm z - 1)++-- | test for the property `|v*c| = c` for unit vector v and arbitrary scalar c+prop_Metric_V3_norm :: (Epsilon a, Floating a) => UnitV3 a -> a -> Bool+prop_Metric_V3_norm (UnitV3 v) c = nearZero $ norm (v ^* c) - (abs c)++-- | test for the property `signorm(v*c) = v` for unit vector v and c >= 0+prop_Metric_V3_signorm :: (Epsilon a, Floating a) => UnitV3 a -> NonZero a -> Bool+prop_Metric_V3_signorm (UnitV3 v) c = nearZero $ signorm (v ^* (abs (getNonZero c))) - v++++spec :: Spec+spec = specTyped @Double++specTyped :: forall a. (Eq a, Show a, Arbitrary a, Epsilon a, Floating a) => Spec+specTyped = do+ describe "V3" $ do+ describe "Arbitrary" $ do+ describe "UnitV3" $ do+ it "satisfies the property `|v| = 1`" $ do+ property $ prop_UnitV3_isUnit @a+ describe "CartesianUnitV3" $ do+ it "satisfies the property `|v| = 1`" $ do+ property $ prop_CartesianUnitV3_isUnit @a+ it "satisfies the property `|u·v| = 1 or 0`" $ do+ property $ prop_CartesianUnitV3_isOrthogonal @a+ describe "BasisV3" $ do+ it "satisfies the property that vectors are orthonormal" $ do+ property $ prop_BasisV3_isOrthonormal @a+ describe "Metric" $ do+ it "satisfies property `|v*c| = c` for unit vectors" $+ property $ prop_Metric_V3_norm @a+ it "satisfies property `signorm(v*c) = v` for unit vectors" $+ property $ prop_Metric_V3_signorm @a
+ test/Linear/V4Spec.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+++module Linear.V4Spec (+ spec+) where++import Test.Hspec+import Test.QuickCheck++import Linear.Epsilon+import Linear.Metric++import Linear.V4.Arbitrary+++-- | test for the property `|v| = 1`+prop_UnitV4_isUnit :: (Epsilon a, Floating a) => UnitV4 a -> Bool+prop_UnitV4_isUnit (UnitV4 v) = nearZero $ norm v - 1++spec :: Spec+spec = specTyped @Double++specTyped :: forall a. (Eq a, Show a, Arbitrary a, Epsilon a, Floating a) => Spec+specTyped = do+ describe "V4" $ do+ describe "Arbitrary" $ do+ describe "UnitV4" $ do+ it "satisfies the property `|v| = 1`" $ do+ property $ prop_UnitV4_isUnit @a
+ test/Spec.hs view
@@ -0,0 +1,2 @@+-- hspec auto-discovery stuff+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}