{-# LANGUAGE CPP, BlockArguments #-}
module ICU.NamesSpec
( spec
) where
import Control.Applicative (Alternative(..))
import Data.Foldable (traverse_)
import Data.Version (showVersion, versionBranch)
import Numeric (showHex)
import Test.Hspec
( describe
, expectationFailure
, it
, pendingWith
, Spec
, HasCallStack, SpecWith )
import qualified ICU.Char as ICU
import qualified ICU.Names as ICUString
import qualified Unicode.Char as U
import qualified Unicode.Char.General.Names as String
#ifdef HAS_BYTESTRING
import qualified Data.ByteString.Char8 as B8
import qualified Unicode.Char.General.Names.ByteString as ByteString
#endif
#ifdef HAS_TEXT
import qualified Unicode.Char.General.Names.Text as Text
import qualified ICU.Names.Text as ICUText
#endif
spec :: Spec
spec = do
describe "name" do
checkAndGatherErrors "String" String.name ICUString.name
#ifdef HAS_BYTESTRING
checkAndGatherErrors "ByteString"
ByteString.name
(fmap B8.pack . ICUString.name)
#endif
#ifdef HAS_TEXT
checkAndGatherErrors "Text" Text.name ICUText.name
#endif
describe "correctedName" do
checkAndGatherErrors "String"
String.correctedName
ICUString.correctedName
#ifdef HAS_BYTESTRING
checkAndGatherErrors "ByteString"
ByteString.correctedName
(fmap B8.pack . ICUString.correctedName)
#endif
#ifdef HAS_TEXT
checkAndGatherErrors "Text"
Text.correctedName
ICUText.correctedName
#endif
where
ourUnicodeVersion = versionBranch U.unicodeVersion
showCodePoint c = ("U+" ++) . fmap U.toUpper . showHex (U.ord c)
-- There is no feature to display warnings other than `trace`, so
-- hack our own:
-- 1. Compare given functions in pure code and gather warning & errors
-- 2. Create dummy spec that throw an expectation failure, if relevant.
-- 3. Create pending spec for each Char that raises a Unicode version
-- mismatch between ICU and unicode-data.
checkAndGatherErrors
:: forall a. (HasCallStack, Eq a, Show a)
=> String
-> (Char -> Maybe a)
-> (Char -> Maybe a)
-> SpecWith ()
checkAndGatherErrors label f fRef = do
it label (maybe (pure ()) expectationFailure err)
if null ws
then pure ()
else describe (label ++ " (Unicode version conflict)")
(traverse_ mkWarning ws)
where
Acc ws err = foldr check (Acc [] Nothing) [minBound..maxBound]
check c acc
-- Test passed
| n == nRef = acc
-- Unicode version mismatch: char is not mapped in one of the libs:
-- add warning.
| ageMismatch c = acc{warnings=c : warnings acc}
-- Error
| otherwise =
let !msg = mconcat
[ showCodePoint c ": expected "
, maybe "\"\"" show nRef
, ", got ", maybe "\"\"" show n, "" ]
in acc{firstError = firstError acc <|> Just msg}
where
!n = f c
!nRef = fRef c
mkWarning c = it (showCodePoint c "") . pendingWith $ mconcat
[ "Incompatible ICU Unicode version: expected "
, showVersion U.unicodeVersion
, ", got: "
, showVersion ICU.unicodeVersion
, " (ICU character age is: "
, showVersion (ICU.charAge c)
, ")" ]
ageMismatch c =
let age = take 3 (versionBranch (ICU.charAge c))
in age > ourUnicodeVersion || age == [0, 0, 0]
data Acc = Acc { warnings :: ![Char], firstError :: !(Maybe String) }