unicode-data-names-0.4.0: test/Unicode/Char/General/NamesSpec.hs
{-# LANGUAGE BlockArguments #-}
module Unicode.Char.General.NamesSpec
( spec
) where
import Data.Foldable (traverse_)
import GHC.Exts (Char (..), andI#, isTrue#, ord#, (<#))
import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)
import Unicode.Char.General (
GeneralCategory (NotAssigned, PrivateUse, Surrogate),
generalCategory,
)
import Unicode.Char.General.Names (
NameAliasType (..),
correctedName,
label,
name,
nameAliases,
nameAliasesByType,
nameAliasesWithTypes,
nameOrAlias,
)
import qualified Unicode.Internal.Char.UnicodeData.DerivedName as DerivedName
spec :: Spec
spec = do
it "template hex code length is 4 or 5"
-- Ensure no padding is required for hexadecimal codepoints and
-- that we the allocation is correct for ByteString & Text APIs.
let {
check (C# c#) = case DerivedName.name c# of
(# _, len# #) ->
isTrue# (len# <# DerivedName.CjkCompatibilityIdeograph) ||
isTrue# ((0xFFF# <# ord# c#) `andI#` (ord# c# <# 0x100000#))
} in traverse_ (`shouldSatisfy` check) [minBound..maxBound]
it "name: Test some characters" do
name minBound `shouldBe` Nothing
name 'A' `shouldBe` Just "LATIN CAPITAL LETTER A"
name '\x0080' `shouldBe` Nothing
name '\x009f' `shouldBe` Nothing
-- Name with correction
name '\x01A2' `shouldBe` Just "LATIN CAPITAL LETTER OI"
name '\x2200' `shouldBe` Just "FOR ALL"
-- Name generated using pattern (example from UCD file)
name '\x4e12' `shouldBe` Just "CJK UNIFIED IDEOGRAPH-4E12"
name '\xfeff' `shouldBe` Just "ZERO WIDTH NO-BREAK SPACE"
name '\xffff' `shouldBe` Nothing
-- Name with correction
name '\x1D0C5' `shouldBe` Just "BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS"
name '\x1f41d' `shouldBe` Just "HONEYBEE"
-- Name generated using pattern (example from UCD file)
name '\x2f89f' `shouldBe` Just "CJK COMPATIBILITY IDEOGRAPH-2F89F"
-- Last name defined, as of Unicode 15.0.0
name '\xe01ef' `shouldBe` Just "VARIATION SELECTOR-256"
name maxBound `shouldBe` Nothing
it "correctedName: Test some characters" do
correctedName minBound `shouldBe` Nothing
correctedName 'A' `shouldBe` Just "LATIN CAPITAL LETTER A"
correctedName '\x0080' `shouldBe` Nothing
correctedName '\x009f' `shouldBe` Nothing
-- Name with correction
correctedName '\x01A2' `shouldBe` Just "LATIN CAPITAL LETTER GHA"
correctedName '\x2200' `shouldBe` Just "FOR ALL"
-- Name generated using pattern (example from UCD file)
correctedName '\x4e12' `shouldBe` Just "CJK UNIFIED IDEOGRAPH-4E12"
correctedName '\xfeff' `shouldBe` Just "ZERO WIDTH NO-BREAK SPACE"
correctedName '\xffff' `shouldBe` Nothing
-- Name with correction
correctedName '\x1D0C5' `shouldBe` Just "BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA VASIS"
correctedName '\x1f41d' `shouldBe` Just "HONEYBEE"
-- Name generated using pattern (example from UCD file)
correctedName '\x2f89f' `shouldBe` Just "CJK COMPATIBILITY IDEOGRAPH-2F89F"
-- Last name defined, as of Unicode 15.0.0
correctedName '\xe01ef' `shouldBe` Just "VARIATION SELECTOR-256"
correctedName maxBound `shouldBe` Nothing
it "nameOrAlias: Test some characters" do
nameOrAlias minBound `shouldBe` Just "NULL"
nameOrAlias 'A' `shouldBe` Just "LATIN CAPITAL LETTER A"
nameOrAlias '\x0080' `shouldBe` Just "PADDING CHARACTER"
nameOrAlias '\x009f' `shouldBe` Just "APPLICATION PROGRAM COMMAND"
-- Name with correction
nameOrAlias '\x01A2' `shouldBe` Just "LATIN CAPITAL LETTER OI"
nameOrAlias '\x2200' `shouldBe` Just "FOR ALL"
-- Name generated using pattern (example from UCD file)
nameOrAlias '\x4e12' `shouldBe` Just "CJK UNIFIED IDEOGRAPH-4E12"
nameOrAlias '\xfeff' `shouldBe` Just "ZERO WIDTH NO-BREAK SPACE"
nameOrAlias '\xffff' `shouldBe` Nothing
-- Name with correction
nameOrAlias '\x1D0C5' `shouldBe` Just "BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS"
nameOrAlias '\x1f41d' `shouldBe` Just "HONEYBEE"
-- Name generated using pattern (example from UCD file)
nameOrAlias '\x2f89f' `shouldBe` Just "CJK COMPATIBILITY IDEOGRAPH-2F89F"
-- Last name defined, as of Unicode 15.0.0
nameOrAlias '\xe01ef' `shouldBe` Just "VARIATION SELECTOR-256"
nameOrAlias maxBound `shouldBe` Nothing
it "nameAliasesWithTypes: test some characters" do
nameAliasesWithTypes '\0' `shouldBe`
[(Control, ["NULL"]), (Abbreviation, ["NUL"])]
nameAliasesWithTypes '\x0A' `shouldBe`
[(Control, ["LINE FEED", "NEW LINE", "END OF LINE"])
,(Abbreviation, ["LF", "NL", "EOL"])]
nameAliasesWithTypes '\x80' `shouldBe`
[(Figment, ["PADDING CHARACTER"]), (Abbreviation, ["PAD"])]
nameAliasesWithTypes '\x01A2' `shouldBe`
[(Correction, ["LATIN CAPITAL LETTER GHA"])]
nameAliasesWithTypes '\xFEFF' `shouldBe`
[(Alternate, ["BYTE ORDER MARK"]), (Abbreviation, ["BOM", "ZWNBSP"])]
nameAliasesWithTypes '\xE01EF' `shouldBe`
[(Abbreviation, ["VS256"])]
it "nameAliasesByType" do
let f c = foldr
(\t -> case nameAliasesByType t c of {[] -> id;xs -> ((t,xs):)})
mempty
[minBound..maxBound]
check c = f c == nameAliasesWithTypes c
traverse_ (`shouldSatisfy` check) [minBound..maxBound]
describe "nameAliases" do
it "test some characters" do
nameAliases '\0' `shouldBe`
["NULL", "NUL"]
nameAliases '\x0A' `shouldBe`
["LINE FEED", "NEW LINE", "END OF LINE", "LF", "NL", "EOL"]
nameAliases '\x80' `shouldBe`
["PADDING CHARACTER", "PAD"]
nameAliases '\x01A2' `shouldBe`
["LATIN CAPITAL LETTER GHA"]
nameAliases '\xFEFF' `shouldBe`
["BYTE ORDER MARK", "BOM", "ZWNBSP"]
nameAliases '\xE01EF' `shouldBe`
["VS256"]
it "compare to nameAliasesWithTypes" do
let check c = nameAliases c == mconcat (snd <$> nameAliasesWithTypes c)
traverse_ (`shouldSatisfy` check) [minBound..maxBound]
it "Every defined character has at least a name or an alias" do
let checkName c = case nameOrAlias c of
Just _ -> True
Nothing -> case generalCategory c of
Surrogate -> True
PrivateUse -> True
NotAssigned -> True
_ -> False
traverse_ (`shouldSatisfy` checkName) [minBound..maxBound]
describe "label" do
it "Some characters" do
label '\x0000' `shouldBe` "control-0000"
label '\x009F' `shouldBe` "control-009F"
label 'a' `shouldBe` "UNDEFINED"
label '1' `shouldBe` "UNDEFINED"
label '\x1D0C5' `shouldBe` "UNDEFINED"
label '\x2F89F' `shouldBe` "UNDEFINED"
label '\xE000' `shouldBe` "private-use-E000"
label '\x10FFFD' `shouldBe` "private-use-10FFFD"
label '\xD800' `shouldBe` "surrogate-D800"
label '\xDFFF' `shouldBe` "surrogate-DFFF"
label '\xFDD0' `shouldBe` "noncharacter-FDD0"
label '\x10FFFF' `shouldBe` "noncharacter-10FFFF"
label '\x0378' `shouldBe` "reserved-0378"
label '\x1FFFD' `shouldBe` "reserved-1FFFD"
label '\xEFFFD' `shouldBe` "reserved-EFFFD"
it "Every character has either a name or a label" do
let checkName c = case name c of
Just _ -> True
Nothing -> label c /= "UNDEFINED"
traverse_ (`shouldSatisfy` checkName) [minBound..maxBound]