module Saturn.Unstable.Type.RangeSpec where

import qualified Data.Maybe as Maybe
import qualified Data.Text.Lazy.Builder as Builder
import qualified Data.Word as Word
import qualified Saturn.Unstable.Extra.Tuple as Tuple
import qualified Saturn.Unstable.Type.Number as Number
import qualified Saturn.Unstable.Type.NumberSpec as NumberSpec
import qualified Saturn.Unstable.Type.Range as Range
import qualified Test.Hspec as Hspec
import qualified Test.QuickCheck as QuickCheck
import qualified Text.Parsec as Parsec

spec :: Hspec.Spec
spec :: Spec
spec = String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
Hspec.describe String
"Saturn.Unstable.Type.Range" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
  String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
Hspec.it String
"round trips"
    (Property -> Spec)
-> ((Range -> Expectation) -> Property)
-> (Range -> Expectation)
-> Spec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Gen Range
-> (Range -> [Range]) -> (Range -> Expectation) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> [a]) -> (a -> prop) -> Property
QuickCheck.forAllShrink Gen Range
arbitrary Range -> [Range]
shrink
    ((Range -> Expectation) -> Spec) -> (Range -> Expectation) -> Spec
forall a b. (a -> b) -> a -> b
$ \Range
x -> do
      Parsec Text () Range -> String -> Text -> Either ParseError Range
forall s t a.
Stream s Identity t =>
Parsec s () a -> String -> s -> Either ParseError a
Parsec.parse Parsec Text () Range
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Range
Range.parsec String
"" (Builder -> Text
Builder.toLazyText (Builder -> Text) -> Builder -> Text
forall a b. (a -> b) -> a -> b
$ Range -> Builder
Range.toBuilder Range
x)
        Either ParseError Range -> Either ParseError Range -> Expectation
forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
`Hspec.shouldBe` Range -> Either ParseError Range
forall a b. b -> Either a b
Right Range
x

arbitrary :: QuickCheck.Gen Range.Range
arbitrary :: Gen Range
arbitrary =
  Gen (Number, Number)
-> ((Number, Number) -> Maybe Range) -> Gen Range
forall a b. Gen a -> (a -> Maybe b) -> Gen b
QuickCheck.suchThatMap
    (Gen Number -> Gen Number -> Gen (Number, Number)
forall a b. Gen a -> Gen b -> Gen (a, b)
forall (f :: * -> * -> *) a b.
Arbitrary2 f =>
Gen a -> Gen b -> Gen (f a b)
QuickCheck.liftArbitrary2 Gen Number
NumberSpec.arbitrary Gen Number
NumberSpec.arbitrary)
    (Number, Number) -> Maybe Range
Range.fromTuple

shrink :: Range.Range -> [Range.Range]
shrink :: Range -> [Range]
shrink =
  ((Number, Number) -> Maybe Range) -> [(Number, Number)] -> [Range]
forall a b. (a -> Maybe b) -> [a] -> [b]
Maybe.mapMaybe (Number, Number) -> Maybe Range
Range.fromTuple
    ([(Number, Number)] -> [Range])
-> (Range -> [(Number, Number)]) -> Range -> [Range]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Number -> [Number])
-> (Number -> [Number]) -> (Number, Number) -> [(Number, Number)]
forall a b. (a -> [a]) -> (b -> [b]) -> (a, b) -> [(a, b)]
forall (f :: * -> * -> *) a b.
Arbitrary2 f =>
(a -> [a]) -> (b -> [b]) -> f a b -> [f a b]
QuickCheck.liftShrink2 Number -> [Number]
NumberSpec.shrink Number -> [Number]
NumberSpec.shrink
    ((Number, Number) -> [(Number, Number)])
-> (Range -> (Number, Number)) -> Range -> [(Number, Number)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Range -> (Number, Number)
Range.toTuple

new :: (MonadFail m) => (Word.Word8, Word.Word8) -> m Range.Range
new :: forall (m :: * -> *). MonadFail m => (Word8, Word8) -> m Range
new (Word8, Word8)
tuple =
  m Range -> (Range -> m Range) -> Maybe Range -> m Range
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> m Range
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> m Range) -> String -> m Range
forall a b. (a -> b) -> a -> b
$ String
"invalid Range: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> (Word8, Word8) -> String
forall a. Show a => a -> String
show (Word8, Word8)
tuple) Range -> m Range
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    (Maybe Range -> m Range)
-> ((Number, Number) -> Maybe Range) -> (Number, Number) -> m Range
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Number, Number) -> Maybe Range
Range.fromTuple
    ((Number, Number) -> m Range) -> (Number, Number) -> m Range
forall a b. (a -> b) -> a -> b
$ (Word8 -> Number) -> (Word8, Word8) -> (Number, Number)
forall a b. (a -> b) -> (a, a) -> (b, b)
Tuple.mapBoth Word8 -> Number
Number.fromWord8 (Word8, Word8)
tuple