packages feed

tadka-2.0.0.0: test/props/Source.hs

{-# LANGUAGE OverloadedStrings #-}

-- | Phase I — the pluggable 'SourceCode' seam. The canonical 'NamedSource'
-- instance is total and its windowed reads agree, by definition, with a filter
-- of the full line enumeration.
module Source (group) where

import           Data.Text                  (Text)
import qualified Data.Text                  as T

import           Hedgehog
import qualified Hedgehog.Gen               as Gen
import qualified Hedgehog.Range             as Range

import           Tadka                      (NamedSource, mkNamedSource, sourceName,
                                             sourceText)
import           Tadka.Internal.SourceCode  (SourceCode (..))

group :: Group
group = Group "SourceCode (Phase I)"
  [ ("scName is the source name",            prop_name)
  , ("scLines (1, huge) enumerates all lines", prop_full)
  , ("scLines window == filtered enumeration", prop_window)
  ]

rightOrErr :: Show a => Either a b -> b
rightOrErr = either (error . show) id

genSource :: Gen NamedSource
genSource = do
  name <- Gen.text (Range.linear 1 8) Gen.alpha
  segs <- Gen.list (Range.linear 0 6) (Gen.text (Range.linear 0 10) (Gen.filterT (/= '\n') Gen.ascii))
  pure (rightOrErr (mkNamedSource name (T.intercalate (T.singleton '\n') segs)))

allLines :: NamedSource -> [(Int, Text)]
allLines ns = zip [1 ..] (map dropCR (T.splitOn (T.singleton '\n') (sourceText ns)))
  where dropCR t = case T.stripSuffix (T.singleton '\r') t of
          Just t' -> t'
          Nothing -> t

prop_name :: Property
prop_name = property $ do
  ns <- forAll genSource
  scName ns === sourceName ns

prop_full :: Property
prop_full = property $ do
  ns <- forAll genSource
  scLines ns (1, 1000000) === allLines ns

-- The defining property, exercised over arbitrary (including negative/inverted)
-- ranges: a window is exactly the lines of the full enumeration within it.
prop_window :: Property
prop_window = property $ do
  ns <- forAll genSource
  lo <- forAll (Gen.int (Range.linear (-3) 12))
  hi <- forAll (Gen.int (Range.linear (-3) 12))
  scLines ns (lo, hi) === [ p | p@(n, _) <- allLines ns, n >= lo, n <= hi ]