packages feed

tomland-1.3.3.3: test/Test/Toml/Type/PrefixTree.hs

{-# LANGUAGE PatternSynonyms #-}

module Test.Toml.Type.PrefixTree
    ( prefixTreeSpec
    ) where

import Hedgehog (forAll, (===))
import Test.Hspec (Arg, Expectation, Spec, SpecWith, describe, it, parallel, shouldBe)
import Test.Hspec.Hedgehog (hedgehog)

import Test.Toml.Gen (genKey, genPrefixMap, genVal)
import Test.Toml.Property (assocSemigroup, leftIdentityMonoid, rightIdentityMonoid)
import Toml.Type.Key (pattern (:||))

import qualified Toml.Type.PrefixTree as Prefix


prefixTreeSpec :: Spec
prefixTreeSpec = describe "PrefixTree unit and property tests" $ do
    prefixTreeUnitSpec
    prefixTreePropertySpec

prefixTreeUnitSpec :: Spec
prefixTreeUnitSpec = describe "Unit tests for basic cases" $ do
    -- some test keys
    let a  = "a" :|| []
    let b  = "b" :|| []
    let c  = "c" :|| []
    let ab = "a" :|| ["b"]

    it "Lookup on empty map returns Nothing" $
        Prefix.lookup @Bool a mempty `shouldBe` Nothing
    it "Lookup in single map returns this element" $ do
        let t = Prefix.single a True
        Prefix.lookup a t `shouldBe` Just True
        Prefix.lookup b t `shouldBe` Nothing
    it "Lookup after insert returns this element" $ do
        let t = Prefix.insert a True mempty
        Prefix.lookup a t `shouldBe` Just True
        Prefix.lookup b t `shouldBe` Nothing
    it "Lookup after multiple non-overlapping inserts" $ do
        let t = Prefix.insert a True $ Prefix.insert b False mempty
        Prefix.lookup a t `shouldBe` Just True
        Prefix.lookup b t `shouldBe` Just False
        Prefix.lookup c t `shouldBe` Nothing
    it "Prefix lookup" $ do
        let t = Prefix.insert ab True mempty
        Prefix.lookup a  t `shouldBe` Nothing
        Prefix.lookup ab t `shouldBe` Just True
    it "Composite key lookup" $ do
        let t = Prefix.insert a True $ Prefix.insert ab False mempty
        Prefix.lookup a  t `shouldBe` Just True
        Prefix.lookup ab t `shouldBe` Just False

prefixTreePropertySpec :: Spec
prefixTreePropertySpec = parallel $ describe "Laws and behaviour property tests" $ do
    insertLookupSpec
    insertInsertSpec
    assocSemigroup      genPrefixMap
    leftIdentityMonoid  genPrefixMap
    rightIdentityMonoid genPrefixMap

insertLookupSpec :: SpecWith (Arg Expectation)
insertLookupSpec = it "lookup k (insert k v m) ≡ Just v" $ hedgehog $ do
    t   <- forAll genPrefixMap
    key <- forAll genKey
    val <- forAll genVal

    Prefix.lookup key (Prefix.insert key val t) === Just val

    -- DEBUG: ensures that trees of depth at least 5 are generated
    -- assert $ depth prefMap < 5

insertInsertSpec :: SpecWith (Arg Expectation)
insertInsertSpec = it "insert x a . insert x b ≡ insert x a" $ hedgehog $ do
    t <- forAll genPrefixMap
    x <- forAll genKey
    a <- forAll genVal
    b <- forAll genVal

    Prefix.lookup x (Prefix.insert x a $ Prefix.insert x b t) === Just a

----------------------------------------------------------------------------
-- DEBUG
----------------------------------------------------------------------------

-- useful functions to test generators
-- uncomment when you need them

-- depth :: PrefixMap a -> Int
-- depth = HashMap.foldl' (\acc t -> max acc (depthT t)) 0
--
-- depthT :: PrefixTree a -> Int
-- depthT (Leaf _ _)           = 1
-- depthT (Branch _ _ prefMap) = 1 + depth prefMap