packages feed

unicode-data-scripts-0.5.0: test/ICU/ScriptsSpec.hs

{-# LANGUAGE BlockArguments #-}

module ICU.ScriptsSpec
    ( spec
    ) where

import Data.Char (toUpper, ord)
import Data.Foldable (traverse_)
import qualified Data.List as L
import qualified Data.List.NonEmpty as NE
import Data.Version (versionBranch, showVersion)
import Debug.Trace (trace, traceM)
import Numeric (showHex)
import Test.Hspec ( Spec, it, expectationFailure, shouldSatisfy )

import qualified ICU.Char as ICU
import qualified ICU.Scripts as ICU
import qualified Unicode.Char.General.Scripts as S

spec :: Spec
spec = do
    it "scriptShortName"
        let check s = case toIcuScript s of
                    Just _ -> True
                    Nothing
                        | versionMismatch -> trace (mconcat
                            [ "[WARNING] Cannot test scriptShortName for "
                            , show s
                            , ": incompatible ICU version ("
                            , showVersion ICU.unicodeVersion
                            , " /= "
                            , showVersion S.unicodeVersion
                            , ")." ]) True
                        | otherwise -> False
        in traverse_ (`shouldSatisfy` check) [minBound..maxBound]
    it "script"
        let check c
                | s == sRef = pure ()
                | versionMismatch = traceM . mconcat $
                    [ "[WARNING] Cannot test "
                    , showCodePoint c
                    , ": incompatible ICU version ("
                    , showVersion ICU.unicodeVersion
                    , " /= "
                    , showVersion S.unicodeVersion
                    , "). Expected "
                    , show sRef
                    , ", but got: "
                    , show s ]
                | otherwise = expectationFailure $ mconcat
                    [ show c, ": expected “", sRef, "”, got “", s, "”" ]
                where
                !s    = S.scriptShortName (S.script c)
                !sRef = ICU.scriptShortName (ICU.script c)
        in traverse_ check [minBound..maxBound]
    it "scriptDefinition"
        let {
        check s =
            case lookup (S.scriptShortName s) icuScripts of
                Nothing
                    | ourUnicodeVersion > theirUnicodeVersion
                    -> traceM . mconcat $
                        [ "[WARNING] Cannot convert script "
                        , show s
                        , ": incompatible ICU version ("
                        , showVersion ICU.unicodeVersion
                        , " /= "
                        , showVersion S.unicodeVersion
                        , "). "
                        , "Max supported ICU script:"
                        , show ICU.maxSupportedScript ]
                    | otherwise -> error ("Cannot convert script: " ++ show s)
                Just s'
                    | def == defRef -> pure ()
                    | ourUnicodeVersion /= theirUnicodeVersion
                    -> traceM . mconcat $
                        [ "[WARNING] Cannot test "
                        , show s
                        , ": incompatible ICU version ("
                        , showVersion ICU.unicodeVersion
                        , " /= "
                        , showVersion S.unicodeVersion
                        , ")."
                        , if null missing
                            then ""
                            else " Missing: " ++ show missing
                        , "."
                        , if null unexpected
                            then ""
                            else " Unexpected: " ++ show unexpected
                        ]
                    | otherwise -> expectationFailure $ mconcat
                        [ show s
                        , ": expected “", show def
                        , "”, got “", show defRef, "”" ]
                    where
                        !defRef = filter ((== s') . ICU.script) [minBound..maxBound]
                        !def    = S.scriptDefinition s
                        (missing, unexpected) = case s of
                            -- No diff for “Unknown” script, lists are too big
                            S.Unknown -> mempty
                            _ -> (defRef L.\\ def, def L.\\ defRef)
        } in traverse_ check [minBound..maxBound]
    it "scriptExtensions"
        let check c
                | es == esRef = pure ()
                | versionMismatch = traceM . mconcat $
                    [ "[WARNING] Cannot test "
                    , showCodePoint c
                    , ": incompatible ICU version ("
                    , showVersion ICU.unicodeVersion
                    , " /= "
                    , showVersion S.unicodeVersion
                    , "). Expected "
                    , show esRef
                    , ", but got: "
                    , show es ]
                | otherwise = expectationFailure $ mconcat
                    [ show c
                    , ": expected “", show esRef
                    , "”, got “", show es, "”" ]
                where
                !es = NE.sort (S.scriptShortName <$> S.scriptExtensions c)
                !esRef = NE.sort (ICU.scriptShortName <$> ICU.scriptExtensions c)
        in traverse_ check [minBound..maxBound]
    where
    ourUnicodeVersion = versionBranch S.unicodeVersion
    theirUnicodeVersion = take 3 (versionBranch ICU.unicodeVersion)
    showCodePoint c = ("U+" ++) . fmap toUpper $ showHex (ord c) ""
    versionMismatch = ourUnicodeVersion /= theirUnicodeVersion
    icuScripts = (\s -> (ICU.scriptShortName s, s)) <$> [minBound..maxBound]
    toIcuScript = (`lookup` icuScripts) . S.scriptShortName