File: ReadSpec.hs

package info (click to toggle)
haskell-deriving-compat 0.6.6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 492 kB
  • sloc: haskell: 6,121; makefile: 5
file content (124 lines) | stat: -rw-r--r-- 3,098 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
{-# LANGUAGE CPP #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}

{-|
Module:      ReadSpec
Copyright:   (C) 2015-2017 Ryan Scott
License:     BSD-style (see the file LICENSE)
Maintainer:  Ryan Scott
Portability: Template Haskell

@hspec@ tests for derived 'Read', 'Read1', and 'Read2' instances.
-}
module ReadSpec where

import Data.Deriving
import Data.Functor.Classes (Read1, readsPrec1)
import Data.Proxy

import Prelude ()
import Prelude.Compat

import Test.Hspec
import Test.Hspec.QuickCheck (prop)
import Test.QuickCheck (Arbitrary(..))

import Text.Read (minPrec)

import Types.ReadShow ()

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

-- Plain data types

data TyCon# a b = TyCon# {
    tcA# :: a
  , tcB# :: b
} deriving (Eq, Show)

data Empty a b

-- Data families

data family TyFamily# y z :: *

data instance TyFamily# a b = TyFamily# {
    tfA# :: a
  , tfB# :: b
} deriving (Eq, Show)

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

-- Plain data types

$(deriveRead  ''TyCon#)
$(deriveRead1 ''TyCon#)
#if defined(NEW_FUNCTOR_CLASSES)
$(deriveRead2 ''TyCon#)
#endif

instance (Arbitrary a, Arbitrary b) => Arbitrary (TyCon# a b) where
  arbitrary = TyCon# <$> arbitrary <*> arbitrary

$(deriveRead  ''Empty)
$(deriveRead1 ''Empty)
#if defined(NEW_FUNCTOR_CLASSES)
$(deriveRead2 ''Empty)
#endif

#if MIN_VERSION_template_haskell(2,7,0)
-- Data families

$(deriveRead  'TyFamily#)
$(deriveRead1 'TyFamily#)
# if defined(NEW_FUNCTOR_CLASSES)
$(deriveRead2 'TyFamily#)
# endif

instance (Arbitrary a, Arbitrary b) => Arbitrary (TyFamily# a b) where
  arbitrary = TyFamily# <$> arbitrary <*> arbitrary
#endif

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

prop_Read :: forall f a. (Read a, Read (f a), Read1 f,
                          Eq (f a), Show (f a))
          => f a -> Expectation
prop_Read x = readArb readsPrec `shouldBe` readArb readsPrec1
  where
    readArb :: (Int -> ReadS (f a)) -> f a
    readArb = read' (show x)

readSpec :: forall f a. (Arbitrary (f a), Eq (f a), Show (f a),
                         Read a, Read (f a), Read1 f)
         => Proxy (f a) -> Spec
readSpec _ = prop "has a valid Read1 instance" (prop_Read :: f a -> Expectation)

-- Adapted from the definition of readEither
readEither' :: String -> (Int -> ReadS a) -> Either String a
readEither' s rs =
  case [ x | (x,"") <- rs minPrec s ] of
    [x] -> Right x
    []  -> Left "Prelude.read: no parse"
    _   -> Left "Prelude.read: ambiguous parse"

read' :: String -> (Int -> ReadS a) -> a
read' s = either error id . readEither' s

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

main :: IO ()
main = hspec spec

spec :: Spec
spec = parallel $ do
  describe "TyCon#" $
    readSpec (Proxy :: Proxy (TyCon# Char Int))
#if MIN_VERSION_template_haskell(2,7,0)
  describe "TyFamily#" $
    readSpec (Proxy :: Proxy (TyFamily# Char Int))
#endif