packages feed

ascii-superset-1.3.0.1: test/Main.hs

module Main (main) where

import ASCII.Case (Case (..))
import ASCII.Case qualified as Case
import ASCII.CaseRefinement (ASCII'lower, ASCII'upper, asciiCaseUnsafe)
import ASCII.CaseRefinement qualified as CaseRefinement
import ASCII.Caseless qualified as CC
import ASCII.Char (Char (..))
import ASCII.Char qualified as ASCII
import ASCII.Refinement (ASCII, asciiUnsafe)
import ASCII.Refinement qualified as Refinement
import ASCII.Superset (fromChar, fromCharList)
import ASCII.Superset qualified as Superset
import Data.Char qualified as Unicode
import Data.Foldable qualified as Foldable
import Data.Function ((&))
import Data.Text (Text)
import Data.Word (Word8)
import Numeric.Natural (Natural)
import Test.Hspec
import Prelude

main :: IO ()
main = hspec $ do
  describe "fromChar" $ do
    it "letter" $ do
      let f x = fromChar x :: Word8
      f CapitalLetterA `shouldBe` 65

    it "to unicode" $ do
      let f = fromChar
      f CapitalLetterA `shouldBe` 'A'

    it "id" $ do
      let f x = fromChar (x :: ASCII.Char) :: ASCII.Char
      f CapitalLetterA `shouldBe` CapitalLetterA

  describe "refinement" $ do
    it "validateChar" $ do
      let f x = Refinement.validateChar x :: Maybe (ASCII Int)
      f (-1) `shouldBe` Nothing
      f 65 `shouldBe` Just (asciiUnsafe 65)
      f 97 `shouldBe` Just (asciiUnsafe 97)
      f 128 `shouldBe` Nothing

    describe "fromCharList" $ do
      it "Text" $ do
        let f x = fromCharList x :: Text
        f [CapitalLetterH, SmallLetterI, ExclamationMark] `shouldBe` "Hi!"

      it "ASCII Text" $ do
        let f x = Refinement.fromCharList x :: ASCII Text
        f [CapitalLetterH, SmallLetterI, ExclamationMark] `shouldBe` asciiUnsafe "Hi!"

    it "toCharList" $ do
      let f x =
            Refinement.toCharList
              (Refinement.substituteString x :: ASCII Text)
      f "Piñata"
        `shouldBe` [ CapitalLetterP,
                     SmallLetterI,
                     Substitute,
                     SmallLetterA,
                     SmallLetterT,
                     SmallLetterA
                   ]

    it "substituteString" $ do
      let f x = Refinement.substituteString x :: ASCII Text
      f "Cristóbal" `shouldBe` asciiUnsafe "Crist\SUBbal"

    it "validateString" $ do
      let f x = Refinement.validateString x :: Maybe (ASCII Text)
      f "Hello" `shouldBe` Just (asciiUnsafe "Hello")
      f "Cristóbal" `shouldBe` Nothing

  describe "case refinement" $ do
    describe "validateChar" $ do
      it "lower" $ do
        let f x = CaseRefinement.validateChar x :: Maybe (ASCII'lower Int)
        f (-1) `shouldBe` Nothing
        f 65 `shouldBe` Nothing
        f 97 `shouldBe` Just (asciiCaseUnsafe 97)
        f 128 `shouldBe` Nothing

      it "upper" $ do
        let f x = CaseRefinement.validateChar x :: Maybe (ASCII'upper Int)
        f (-1) `shouldBe` Nothing
        f 65 `shouldBe` Just (asciiCaseUnsafe 65)
        f 97 `shouldBe` Nothing
        f 128 `shouldBe` Nothing

    describe "fromCaselessCharList" $ do
      it "lower" $ do
        let f x = CaseRefinement.fromCaselessCharList x :: ASCII'lower Text
        f [CC.LetterH, CC.LetterI, CC.ExclamationMark] `shouldBe` asciiCaseUnsafe "hi!"

      it "upper" $ do
        let f x = CaseRefinement.fromCaselessCharList x :: ASCII'upper Text
        f [CC.LetterH, CC.LetterI, CC.ExclamationMark] `shouldBe` asciiCaseUnsafe "HI!"

    describe "toCaselessCharList" $ do
      it "lower" $ do
        let f x = CaseRefinement.toCaselessCharList (x :: ASCII'lower Text)
        f (asciiCaseUnsafe "hi!") `shouldBe` [CC.LetterH, CC.LetterI, CC.ExclamationMark]

      it "upper" $ do
        let f x = CaseRefinement.toCaselessCharList (x :: ASCII'upper Text)
        f (asciiCaseUnsafe "HI!") `shouldBe` [CC.LetterH, CC.LetterI, CC.ExclamationMark]

    describe "substituteString" $ do
      it "lower" $ do
        let f x = CaseRefinement.substituteString x :: ASCII'lower Text
        f "Cób" `shouldBe` asciiCaseUnsafe "\SUB\SUBb"

      it "upper" $ do
        let f x = CaseRefinement.substituteString x :: ASCII'upper Text
        f "Cób" `shouldBe` asciiCaseUnsafe "C\SUB\SUB"

    describe "validateString" $ do
      it "lower" $ do
        let f x = CaseRefinement.validateString x :: Maybe (ASCII'lower Text)
        f "hello" `shouldBe` Just (asciiCaseUnsafe "hello")
        f "Hello" `shouldBe` Nothing

      it "upper" $ do
        let f x = CaseRefinement.validateString x :: Maybe (ASCII'upper Text)
        f "HELLO" `shouldBe` Just (asciiCaseUnsafe "HELLO")
        f "Hello" `shouldBe` Nothing

  describe "case conversion" $ do
    describe "toCaseChar" $ do
      let check :: forall a. Eq a => Superset.CharSuperset a => Expectation
          check =
            ( [UpperCase, LowerCase]
                & Foldable.all
                  ( \c ->
                      ASCII.allCharacters
                        & Foldable.all
                          ( \x ->
                              Superset.toCaseChar c (fromChar @a x)
                                == fromChar @a (Case.toCase c x)
                          )
                  )
            )
              `shouldBe` True
      it "ASCII.Char" $ check @ASCII.Char
      it "Unicode.Char" $ check @Unicode.Char
      it "Natural" $ check @Natural
      it "Int" $ check @Int
      it "Word8" $ check @Word8

    describe "toCaseString" $ do
      it "Text" $ do
        let x = "012 abc DEF ﬓ" :: Text
        Superset.toCaseString UpperCase x `shouldBe` "012 ABC DEF ﬓ"
        Superset.toCaseString LowerCase x `shouldBe` "012 abc def ﬓ"

    describe "refineStringToCase" $ do
      it "Text" $ do
        let x = asciiUnsafe "Hi!" :: ASCII Text
        CaseRefinement.refineStringToCase x `shouldBe` (asciiCaseUnsafe "HI!" :: ASCII'upper Text)
        CaseRefinement.refineStringToCase x `shouldBe` (asciiCaseUnsafe "hi!" :: ASCII'lower Text)

    describe "toCasefulChar" $ do
      describe "lower case" $ do
        let a :: Superset.ToCasefulChar 'LowerCase char => char
            a = Superset.toCasefulChar @'LowerCase CC.LetterA

        it "can be Char" $ a `shouldBe` SmallLetterA
        it "can be superset type" $ a `shouldBe` 'a'
        it "can be case-refined type" $ a `shouldBe` (asciiCaseUnsafe 'a' :: ASCII'lower Unicode.Char)

      describe "upper case" $ do
        let a :: Superset.ToCasefulChar 'UpperCase char => char
            a = Superset.toCasefulChar @'UpperCase CC.LetterA

        it "can be Char" $ a `shouldBe` CapitalLetterA
        it "can be superset type" $ a `shouldBe` 'A'
        it "can be case-refined type" $ a `shouldBe` (asciiCaseUnsafe 'A' :: ASCII'upper Unicode.Char)

    describe "toCasefulString" $ do
      describe "lower case" $ do
        let x :: Superset.ToCasefulString 'LowerCase string => string
            x = Superset.toCasefulString @'LowerCase [CC.LetterH, CC.LetterI, CC.ExclamationMark]

        it "can be [Char]" $ x `shouldBe` [SmallLetterH, SmallLetterI, ExclamationMark]
        it "can be superset type" $ x `shouldBe` ("hi!" :: Text)
        it "can be case-refined type" $ x `shouldBe` (asciiCaseUnsafe "hi!" :: ASCII'lower Text)

      describe "upper case" $ do
        let x :: Superset.ToCasefulString 'UpperCase string => string
            x = Superset.toCasefulString @'UpperCase [CC.LetterH, CC.LetterI, CC.ExclamationMark]

        it "can be [Char]" $ x `shouldBe` [CapitalLetterH, CapitalLetterI, ExclamationMark]
        it "can be superset type" $ x `shouldBe` ("HI!" :: Text)
        it "can be case-refined type" $ x `shouldBe` (asciiCaseUnsafe "HI!" :: ASCII'upper Text)