module Test.TypeRep.TypeRepMap ( typeRepMapSpec ) where import Prelude hiding (lookup) import Data.Functor.Identity (Identity (..)) import Data.List (sortBy) import Data.Ord (comparing) import Data.Typeable (cast) import GHC.Exts (fromList, toList) import Type.Reflection (SomeTypeRep(..), typeRep) import Test.Hspec (Spec, describe, it, shouldBe, shouldMatchList, shouldSatisfy, expectationFailure) import Data.TMap (TMap, empty, insert, lookup, one, size, union, keys) import Data.TypeRepMap.Internal (WrapTypeable (..)) -- Simple test for 'lookup', 'insert', 'size', 'keys', 'toList' functions. typeRepMapSpec :: Spec typeRepMapSpec = describe "TypeRepMap" $ do describe "Lookup Test" $ do it "returns the inserted element" $ lookup (fromList [WrapTypeable $ Identity 'a']) `shouldBe` Just 'a' it "returns the second inserted value of the same type" $ lookup (fromList [WrapTypeable (Identity 'b'), WrapTypeable (Identity 'a')]) `shouldBe` Just 'b' describe "Size Test" $ do it "is empty" $ size empty `shouldBe` 0 it "is of size 1 when 1 element inserted" $ size (one 'a') `shouldBe` 1 it "doesn't increase size when element of the same type is added" $ size (insert 'b' $ insert 'a' empty) `shouldBe` 1 it "returns 10 when 10 different types are inserted" $ size mapOf10 `shouldBe` 10 describe "Union test" $ do let m = fromList [WrapTypeable $ Identity 'a', WrapTypeable $ Identity True] `union` fromList [WrapTypeable $ Identity 'b'] it "lookup works on union as expected" $ do lookup m `shouldBe` Just 'a' lookup m `shouldBe` Just True lookup @Int m `shouldBe` Nothing describe "Keys Test" $ do it "returns nothing on empty map" $ keys empty `shouldBe` [] it "returns the correct TypeRep" $ keys (one 'a') `shouldBe` [SomeTypeRep $ typeRep @Char] it "returns the correct TypeReps for 10 different types" $ keys mapOf10 `shouldMatchList` [ SomeTypeRep $ typeRep @Bool , SomeTypeRep $ typeRep @[Bool] , SomeTypeRep $ typeRep @(Maybe Bool) , SomeTypeRep $ typeRep @(Maybe ()) , SomeTypeRep $ typeRep @[()] , SomeTypeRep $ typeRep @() , SomeTypeRep $ typeRep @String , SomeTypeRep $ typeRep @(Maybe Char) , SomeTypeRep $ typeRep @Char , SomeTypeRep $ typeRep @Int ] describe "ToList Test" $ do it "returns nothing on empty map" $ toList empty `shouldSatisfy` null it "returns correct result when 1 element is inserted" $ case toList (one 'a') of [WrapTypeable (Identity x)] -> cast x `shouldBe` Just 'a' _ -> expectationFailure "did not return exactly 1 result" it "returns correct result when 10 elements are inserted" $ do let getTypeRep (WrapTypeable (Identity (_ :: a))) = SomeTypeRep $ typeRep @a got = sortBy (comparing getTypeRep) (toList mapOf10) expected = sortBy (comparing fst) [ (SomeTypeRep $ typeRep @Bool, \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just True) , (SomeTypeRep $ typeRep @[Bool], \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just [True, False]) , (SomeTypeRep $ typeRep @(Maybe Bool), \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (Just True)) , (SomeTypeRep $ typeRep @(Maybe ()), \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (Just ())) , (SomeTypeRep $ typeRep @[()], \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just [()]) , (SomeTypeRep $ typeRep @(), \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just ()) , (SomeTypeRep $ typeRep @String, \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just ("aaa" :: String)) , (SomeTypeRep $ typeRep @(Maybe Char), \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (Just 'a')) , (SomeTypeRep $ typeRep @Char, \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just 'a') , (SomeTypeRep $ typeRep @Int, \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (11 :: Int)) ] length got `shouldBe` 10 sequence_ $ zipWith snd expected got mapOf10 :: TMap mapOf10 = insert True $ insert [True, False] $ insert (Just True) $ insert (Just ()) $ insert [()] $ insert () $ insert @String "aaa" $ insert (Just 'a') $ insert 'a' $ insert (11 :: Int) empty