packages feed

cpmonad-0.1.0.0: test/Cpmonad/PrinterSpec.hs

{-# OPTIONS_GHC -Wno-missing-signatures #-}
module Cpmonad.PrinterSpec where

import Prelude hiding (print)
import Data.ByteString.Builder qualified as B
import Data.ByteString.Char8 qualified as B
import Data.ByteString.Char8(ByteString)
import Data.Default
import Data.List (intersperse)
import Data.String (IsString)
import Data.Vector qualified as V
import Lens.Micro
import Test.Hspec
import Test.Hspec.QuickCheck
import Test.QuickCheck

import Cpmonad.Printer

toPrinted' :: Printer a -> a -> Maybe ByteString
toPrinted' p x = B.toStrict . B.toLazyByteString <$> p.toPrinted x

sepBySp :: IsString s => [s] -> Gen [s]
sepBySp = sequence . intersperse (elements [" ", "  ", "   "]) . map pure

spec :: Spec
spec = do
  describe "pint" do
    let print = toPrinted' (pint id)
    let parse s = (pint id).fromPrinted (0, s)

    prop "fromPrinted is inverse of toPrinted" $
      \x -> (print x >>= parse) `shouldBe` Just (x, "")
    it "consumes whitespace correctly" do
      parse " 42  " `shouldBe` Just (42, "  ")

  describe "pvecint" do
    let print n v = toPrinted' (pvecintN sp _1 _2) (n, v)
    let parse n s = do ((_, v), s') <- (pvecintN sp _1 _2).fromPrinted ((n, def), s)
                       pure (v, s')

    prop "fromPrinted is inverse of toPrinted" $
      \xs -> let v = V.fromList xs ; n = V.length v in
        (print n v >>= parse n) `shouldBe` Just (v, "")
    it "consumes whitespace correctly" do
      parse 2 " 1  \n  2  " `shouldBe` Just (V.fromList [1,2], "  ")


  describe "large parser" do
    let p = (pint _1 <> sp <> pint _2 <> endl)
            <> pvecvecint _1 _2 _3
            <> (pint _4 <> endl)
            <> pvecN endl _4 _5 (pint _1 <> sp <> pint _2)
    let print = toPrinted' p
    let parse s = p.fromPrinted ((0, 0, V.empty, 0, V.empty), s)

    it "simple" do
      parse "1 2\n0 0\n2\n1 1\n2 2" `shouldBe` Just ((1, 2, V.singleton $ V.fromList [0, 0], 2, V.fromList [(1,1), (2,2)]), "")

    let input = do
          m <- sized $ \s -> chooseInt (1, 1 `max` s)
          mat <- listOf1 (vectorOf m arbitrary)
          qs <- listOf arbitrary
          pure (length mat, m, V.fromList $ map V.fromList mat, length qs, V.fromList qs)

    prop "fromPrinted is inverse of toPrinted" $ forAll input
      \x -> (print x >>= parse) == Just (x, "")

    it "consumes whitespace correctly" do
      parse " 1   2 \n 0   0 2  1 1  \n2   2  \n" `shouldBe` Just ((1, 2, V.singleton $ V.fromList [0, 0], 2, V.fromList [(1,1), (2,2)]), "  \n")