packages feed

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 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 @@+[![CircleCI](https://circleci.com/gh/pdlla/linear-tests.svg?style=svg)](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 #-}