# LANGUAGE TypeApplications #

module Data.GenValidity.TextSpec
  ( spec,
  )
where

import Control.Monad
import Data.GenValidity.Text
import Data.List
import qualified Data.Text as ST
import qualified Data.Text.Array as A
import qualified Data.Text.Internal as ST
import qualified Data.Text.Internal.Lazy as LT
import qualified Data.Text.Lazy as LT
import Test.Hspec
import Test.QuickCheck
import Test.Validity
import Text.Printf

showTextDebug :: ST.Text -> String
showTextDebug (ST.Text arr off len) =
  unlines
    [ unwords
        [ "arr:   ",
          intercalate "," $
            map (printf "%4d") $ A.toList arr off len
        ],
      unwords
        [ "hexarr:",
          intercalate "," $
            map (printf "%4x") $ A.toList arr off len
        ],
      unwords ["off:      ", show off],
      unwords ["len:      ", show len]
    ]

showLazyTextDebug :: LT.Text -> String
showLazyTextDebug LT.Empty = "empty"
showLazyTextDebug (LT.Chunk st lt) =
  unlines
    [ "A chuck with this strict text:",
      showTextDebug st,
      "and this rest of the lazy text:",
      showLazyTextDebug lt,
      ""
    ]

spec :: Spec
spec = do
  describe "Strict Text" $ do
    genValidSpec @ST.Text
    describe "genValid" $ do
      it "is always empty when resized to 0" $
        forAll (resize 0 genValid) (`shouldSatisfy` ST.null)
      it "generates valid text" $
        forAll (genValid) $ \t ->
          unless (isValid t) $ expectationFailure $ showTextDebug t
    describe "textStartingWith" $ do
      it "is never empty" $
        forAll arbitrary $ \c ->
          forAll (textStartingWith c) $ \t ->
            t `shouldNotSatisfy` ST.null
      it "contains exactly the first character if resized to 0" $
        forAll arbitrary $ \c ->
          forAll (resize 0 $ textStartingWith c) $ \t ->
            t `shouldBe` ST.pack [c]
      it "contains exactly the first character if resized to 1" $
        forAll arbitrary $ \c ->
          forAll (resize 0 $ textStartingWith c) $ \t ->
            t `shouldBe` ST.pack [c]
      it "always starts with the given char" $
        forAll arbitrary $ \c ->
          forAll (textStartingWith c) $ \t -> ST.head t `shouldBe` c
    describe "textWithA" $
      it "contains the given character" $
        forAll arbitrary $ \c ->
          forAll (textWithA c) $ \t -> ST.unpack t `shouldSatisfy` elem c
    describe "textWithoutAny" $ do
      it "works with \65533" $
        let c = '\65533'
         in forAll (textWithoutAny c) $ \t ->
              ST.unpack t `shouldNotSatisfy` elem c
      it "never contains the given char" $
        forAllShrink arbitrary shrink $ \c ->
          forAll (textWithoutAny c) $ \t ->
            ST.unpack t `shouldNotSatisfy` elem c
    describe "textWithoutAnyOf" $ do
      it "works with \65533" $
        let cs = "\65533"
         in forAll (textWithoutAnyOf cs) $ \text ->
              ST.unpack text `shouldNotSatisfy` (\t -> any (`elem` t) cs)
      it "never contains any of the given chars" $
        forAllShrink arbitrary shrink $ \cs ->
          forAll (textWithoutAnyOf cs) $ \text ->
            ST.unpack text `shouldNotSatisfy` (\t -> any (`elem` t) cs)
  describe "Lazy Text" $ do
    genValidSpec @LT.Text
    describe "genValid" $ do
      it "is always empty when resized to 0" $
        forAll (resize 0 genValid) (`shouldSatisfy` LT.null)
      it "generates valid text" $
        forAll (genValid) $ \t ->
          unless (isValid t) $
            expectationFailure $ showLazyTextDebug t

# LANGUAGE TypeApplications #

module Data.GenValidity.TextSpec
  ( spec,
  )
where

import Control.Monad
import Data.GenValidity.Text
import Data.List
import qualified Data.Text as ST
import qualified Data.Text.Array as A
import qualified Data.Text.Internal as ST
import qualified Data.Text.Internal.Lazy as LT
import qualified Data.Text.Lazy as LT
import Test.Hspec
import Test.QuickCheck
import Test.Validity
import Text.Printf

showTextDebug :: ST.Text -> String
showTextDebug (ST.Text arr off len) =
  unlines
    [ unwords
        [ "arr:   ",
          intercalate "," $
            map (printf "%4d") $ A.toList arr off len
        ],
      unwords
        [ "hexarr:",
          intercalate "," $
            map (printf "%4x") $ A.toList arr off len
        ],
      unwords ["off:      ", show off],
      unwords ["len:      ", show len]
    ]

showLazyTextDebug :: LT.Text -> String
showLazyTextDebug LT.Empty = "empty"
showLazyTextDebug (LT.Chunk st lt) =
  unlines
    [ "A chuck with this strict text:",
      showTextDebug st,
      "and this rest of the lazy text:",
      showLazyTextDebug lt,
      ""
    ]

spec :: Spec
spec = do
  describe "Strict Text" $ do
    genValidSpec @ST.Text
    describe "genValid" $ do
      it "is always empty when resized to 0" $
        forAll (resize 0 genValid) (`shouldSatisfy` ST.null)
      it "generates valid text" $
        forAll (genValid) $ \t ->
          unless (isValid t) $ expectationFailure $ showTextDebug t
    describe "textStartingWith" $ do
      it "is never empty" $
        forAll arbitrary $ \c ->
          forAll (textStartingWith c) $ \t ->
            t `shouldNotSatisfy` ST.null
      it "contains exactly the first character if resized to 0" $
        forAll arbitrary $ \c ->
          forAll (resize 0 $ textStartingWith c) $ \t ->
            t `shouldBe` ST.pack [c]
      it "contains exactly the first character if resized to 1" $
        forAll arbitrary $ \c ->
          forAll (resize 0 $ textStartingWith c) $ \t ->
            t `shouldBe` ST.pack [c]
      it "always starts with the given char" $
        forAll arbitrary $ \c ->
          forAll (textStartingWith c) $ \t -> ST.head t `shouldBe` c
    describe "textWithA" $
      it "contains the given character" $
        forAll arbitrary $ \c ->
          forAll (textWithA c) $ \t -> ST.unpack t `shouldSatisfy` elem c
    describe "textWithoutAny" $ do
      it "works with \65533" $
        let c = '\65533'
         in forAll (textWithoutAny c) $ \t ->
              ST.unpack t `shouldNotSatisfy` elem c
      it "never contains the given char" $
        forAllShrink arbitrary shrink $ \c ->
          forAll (textWithoutAny c) $ \t ->
            ST.unpack t `shouldNotSatisfy` elem c
    describe "textWithoutAnyOf" $ do
      it "works with \65533" $
        let cs = "\65533"
         in forAll (textWithoutAnyOf cs) $ \text ->
              ST.unpack text `shouldNotSatisfy` (\t -> any (`elem` t) cs)
      it "never contains any of the given chars" $
        forAllShrink arbitrary shrink $ \cs ->
          forAll (textWithoutAnyOf cs) $ \text ->
            ST.unpack text `shouldNotSatisfy` (\t -> any (`elem` t) cs)
  describe "Lazy Text" $ do
    genValidSpec @LT.Text
    describe "genValid" $ do
      it "is always empty when resized to 0" $
        forAll (resize 0 genValid) (`shouldSatisfy` LT.null)
      it "generates valid text" $
        forAll (genValid) $ \t ->
          unless (isValid t) $
            expectationFailure $ showLazyTextDebug t
