packages feed

ipa-0.2: test/Main.hs

{-# LANGUAGE PatternSynonyms #-}

-- |
module Main where

import           Data.Foldable ( traverse_ )
import           Data.Maybe    ( isNothing )

import           Language.IPA
                 ( Backness(..)
                 , Height(..)
                 , IPA(IPA)
                 , Length(..)
                 , Manner(..)
                 , Phonation(..)
                 , Place(..)
                 , ReprIPA(toIPA', toIPA, toXSampa', toXSampa)
                 , Roundedness(..)
                 , Segment(..)
                 , SegmentalFeature(..)
                 , Sibilance(..)
                 , Stress(Primary)
                 , SuprasegmentalFeature(..)
                 , Syllable(..)
                 , ToneContour(..)
                 , XSampa(XSampa)
                 , mkIPA
                 , pattern ImplosiveConsonant
                 , pattern PulmonicConsonant
                 )

import           Test.Hspec    ( describe
                               , hspec
                               , it
                               , shouldBe
                               , shouldSatisfy
                               )

{- HLINT ignore "Redundant do" -}
main :: IO ()
main = ipa >> xsampa

ipa :: IO ()
ipa = hspec $ do
    describe "Segments" $ do
        it "Rejects nonsense segments" $ do
            let phones = toIPA
                    <$> [ PulmonicConsonant Voiceless
                                            Uvular
                                            (Fricative Sibilant)
                        , PulmonicConsonant Voiced Velar Flap
                        , PulmonicConsonant Voiced Pharyngeal Plosive
                        , PulmonicConsonant Voiceless Glottal Trill
                        , Vowel NearClose Central Unrounded
                        , Vowel NearOpen Back Rounded
                        ]
            traverse_ (`shouldSatisfy` isNothing) phones

    describe "Segmental features" $ do
        it "Correctly makes 'Short' a noop" $ do
            let vcfu   = Vowel Close Front Unrounded
                i      = toIPA' vcfu
                iShort = toIPA' $ WithSegmentalFeature (Length Short) vcfu

            i `shouldBe` iShort

        it "Chains articulatory features" $ do
            let vowel       = Vowel Close Back Unrounded
                IPA chained = toIPA'
                    $ WithSegmentalFeature (Length OverLong)
                                           (WithSegmentalFeature Compressed
                                                                 vowel)
            chained `shouldBe` "ɯᵝːː"

    describe "Suprasegmentals" $ do
        it "Preserves individual segments and order" $ do
            let segments     = [ ImplosiveConsonant Voiced Bilabial
                               , Vowel CloseMid Back Unrounded
                               ]
                IPA syllable = toIPA' $ Syllable segments
            syllable `shouldBe` "ɓɤ"

    describe "Suprasegmental features" $ do
        it "Chains articulatory features" $ do
            let segments    = [ PulmonicConsonant Voiced Alveolar Plosive
                              , Vowel CloseMid Back Rounded
                              ]
                syllable    = Syllable segments
                tone        = LexicalToneContour Rising
                IPA chained = toIPA'
                    $ WithSuprasegmentalFeature --
                    (Stress Primary)
                    (WithSuprasegmentalFeature tone syllable)
            chained `shouldBe` "do˩˥ˈ"

    describe "IPA normalization" $ do
        it "Normalizes IPA values to NFC" $ do
            let oRisingNFD     = "o\x0301" -- decomposed form
                IPA oRisingIPA = mkIPA oRisingNFD
            oRisingIPA `shouldBe` "\x00f3"

xsampa :: IO ()
xsampa = hspec $ do
    describe "Suprasegmentals" $ do
        it "Preserves individual segments and order" $ do
            let segments        = [ ImplosiveConsonant Voiced Bilabial
                                  , Vowel CloseMid Back Unrounded
                                  ]
                XSampa syllable = toXSampa' $ Syllable segments
            syllable `shouldBe` "b_<7"

    describe "Segmental features" $ do
        it "Correctly makes 'Short' a noop" $ do
            let vcfu   = Vowel Close Front Unrounded
                i      = toXSampa' vcfu
                iShort = toXSampa' $ WithSegmentalFeature (Length Short) vcfu

            i `shouldBe` iShort

        it "Chains articulatory features" $ do
            let vowel          = Vowel Close Back Unrounded
                XSampa chained = toXSampa'
                    $ WithSegmentalFeature (Length OverLong)
                                           (WithSegmentalFeature Lowered vowel)
            chained `shouldBe` "M_o::"

    describe "Segments" $ do
        it "Rejects nonsense segments" $ do
            let phones = toXSampa
                    <$> [ PulmonicConsonant Voiceless
                                            Uvular
                                            (Fricative Sibilant)
                        , PulmonicConsonant Voiced Velar Flap
                        , PulmonicConsonant Voiced Pharyngeal Plosive
                        , PulmonicConsonant Voiceless Glottal Trill
                        , Vowel NearClose Central Unrounded
                        , Vowel NearOpen Back Rounded
                        ]
            traverse_ (`shouldSatisfy` isNothing) phones

    describe "Suprasegmental features" $ do
        it "Chains articulatory features" $ do
            let segments       = [ PulmonicConsonant Voiced Alveolar Plosive
                                 , Vowel CloseMid Back Rounded
                                 ]
                syllable       = Syllable segments
                tone           = LexicalToneContour Rising
                XSampa chained = toXSampa'
                    $ WithSuprasegmentalFeature --
                    (Stress Primary)
                    (WithSuprasegmentalFeature tone syllable)
            chained `shouldBe` "do_R\""