greskell-2.0.1.0: test/Data/Greskell/GraphSpec.hs
{-# LANGUAGE OverloadedStrings #-}
module Data.Greskell.GraphSpec
( main
, spec
) where
import Control.Monad (forM_)
import Data.Aeson (FromJSON, toJSON)
import qualified Data.Aeson as Aeson
import qualified Data.ByteString.Lazy as BSL
import Data.HashSet (HashSet)
import qualified Data.HashSet as HS
import Data.Monoid (Monoid (..), (<>))
import Data.Text (Text, unpack)
import Test.Hspec
import Data.Greskell.AsLabel (AsLabel (..))
import Data.Greskell.Graph (AEdge (..), AProperty (..), AVertex (..),
AVertexProperty (..), ElementID (..), Path (..),
PathEntry (..), pathToPMap)
import Data.Greskell.GraphSON (GValueBody (..), nonTypedGValue, nonTypedGraphSON,
typedGValue', typedGraphSON, typedGraphSON')
import Data.Greskell.PMap (lookupList, pMapFromList)
main :: IO ()
main = hspec spec
spec :: Spec
spec = do
spec_AEdge
spec_AProperty
spec_AVertexProperty
spec_AVertex
spec_Path
loadGraphSON :: FromJSON a => FilePath -> IO (Either String a)
loadGraphSON filename = fmap Aeson.eitherDecode $ BSL.readFile ("test/graphson/" ++ filename)
spec_AEdge :: Spec
spec_AEdge = describe "AEdge" $ do
it "should parse GraphSON v1" $ do
let expected = nonTypedGraphSON
$ AEdge
{ aeId = ElementID $ nonTypedGValue $ GNumber 13,
aeLabel = "develops"
}
loadGraphSON "edge_v1.json" `shouldReturn` Right expected
let expected_v23 = typedGraphSON
$ AEdge
{ aeId = ElementID $ typedGValue' "g:Int32" $ GNumber 13,
aeLabel = "develops"
}
it "should parse GraphSON v2" $ do
loadGraphSON "edge_v2.json" `shouldReturn` Right expected_v23
it "should parse GraphSON v3" $ do
loadGraphSON "edge_v3.json" `shouldReturn` Right expected_v23
spec_AProperty :: Spec
spec_AProperty = describe "AProperty" $ do
it "should parse GraphSON v1 (GValue)" $ do
let ex = nonTypedGraphSON $ AProperty "since" $ nonTypedGValue $ GNumber 2009
loadGraphSON "property_v1.json" `shouldReturn` Right ex
it "should parse GraphSON v1 (bare Int)" $ do
let ex = nonTypedGraphSON $ AProperty "since" $ (2009 :: Int)
loadGraphSON "property_v1.json" `shouldReturn` Right ex
let ex23 = typedGraphSON $ AProperty "since" $ typedGValue' "g:Int32" $ GNumber 2009
ex23_nowrap = typedGraphSON $ AProperty "since" $ (2009 :: Int)
it "should parse GraphSON v2 (GValue)" $ do
loadGraphSON "property_v2.json" `shouldReturn` Right ex23
it "should parse GraphSON v2 (bare Int)" $ do
loadGraphSON "property_v2.json" `shouldReturn` Right ex23_nowrap
it "should parse GraphSON v3 (GValue)" $ do
loadGraphSON "property_v3.json" `shouldReturn` Right ex23
it "should parse GraphSON v3 (bare Int)" $ do
loadGraphSON "property_v3.json" `shouldReturn` Right ex23_nowrap
spec_AVertexProperty :: Spec
spec_AVertexProperty = describe "AVertexProperty" $ do
it "should parse GraphSON v1" $ do
let ex = nonTypedGraphSON $
AVertexProperty
{ avpId = ElementID $ nonTypedGValue $ GNumber 0,
avpLabel = "name",
avpValue = nonTypedGValue $ GString "marko"
}
loadGraphSON "vertex_property_v1.json" `shouldReturn` Right ex
let ex23 = typedGraphSON $
AVertexProperty
{ avpId = ElementID $ typedGValue' "g:Int64" $ GNumber 0,
avpLabel = "name",
avpValue = nonTypedGValue $ GString "marko"
}
it "should parse GraphSON v2" $ do
loadGraphSON "vertex_property_v2.json" `shouldReturn` Right ex23
it "should parse GraphSON v3" $ do
loadGraphSON "vertex_property_v3.json" `shouldReturn` Right ex23
spec_AVertex :: Spec
spec_AVertex = describe "AVertex" $ do
it "should parse GraphSON v1" $ do
let ex = nonTypedGraphSON $
AVertex
{ avId = ElementID $ nonTypedGValue $ GNumber 1,
avLabel = "person"
}
loadGraphSON "vertex_v1.json" `shouldReturn` Right ex
let ex23 = typedGraphSON $
AVertex
{ avId = ElementID $ typedGValue' "g:Int32" $ GNumber 1,
avLabel = "person"
}
it "should parse GraphSON v2" $ do
loadGraphSON "vertex_v2.json" `shouldReturn` Right ex23
it "should parse GraphSON v3" $ do
loadGraphSON "vertex_v3.json" `shouldReturn` Right ex23
mkEID :: Maybe Text -> GValueBody -> ElementID a
mkEID mtype vb =
case mtype of
Nothing -> ElementID $ nonTypedGValue vb
Just t -> ElementID $ typedGValue' t vb
mkLabels :: [Text] -> HashSet (AsLabel a)
mkLabels = HS.fromList . map AsLabel
mkPE :: [Text] -> a -> PathEntry a
mkPE labels obj = PathEntry (mkLabels labels) obj
spec_Path :: Spec
spec_Path = describe "Path" $ do
let exp_path_v1 =
Path
[ PathEntry (HS.fromList ["a"]) $ AVertex (mkEID Nothing $ GNumber 1) "person",
PathEntry (HS.fromList ["b", "c"]) $ AVertex (mkEID Nothing $ GNumber 10) "software",
PathEntry HS.empty $ AVertex (mkEID Nothing $ GNumber 11) "software"
]
exp_path_v2 =
Path
[ PathEntry (HS.fromList ["a"]) $ AVertex (mkEID (Just "g:Int32") $ GNumber 1) "person",
PathEntry (HS.fromList ["b", "c"]) $ AVertex (mkEID (Just "g:Int32") $ GNumber 10) "software",
PathEntry HS.empty $ AVertex (mkEID (Just "g:Int32") $ GNumber 11) "software"
]
exp_path_v3 = exp_path_v2
it "should parse GraphSON v1" $ do
loadGraphSON "path_v1.json" `shouldReturn` Right exp_path_v1
it "should parse GraphSON v2" $ do
loadGraphSON "path_v2.json" `shouldReturn` Right exp_path_v2
it "should parse GraphSON v3" $ do
loadGraphSON "path_v3.json" `shouldReturn` Right exp_path_v3
describe "pathToPMap" $ do
specify "empty path" $ do
let p :: Path Int
p = mempty
(pathToPMap p) `shouldBe` mempty
specify "objects without labels" $ do
let p :: Path Int
p = Path [ PathEntry mempty 10,
PathEntry mempty 20,
PathEntry mempty 30
]
(pathToPMap p) `shouldBe` mempty
specify "objects with unique single label" $ do
let p :: Path Int
p = Path
[ mkPE ["a"] 10,
mkPE ["b"] 20,
mkPE [] 30,
mkPE ["c"] 40
]
expected = pMapFromList
[ ("a", 10), ("b", 20), ("c", 40)
]
(pathToPMap p) `shouldBe` expected
specify "object with multiple labels" $ do
let p :: Path Int
p = Path
[ mkPE ["a", "b", "c"] 10,
mkPE ["d", "e"] 20,
mkPE [] 30
]
expected = pMapFromList
[ ("a", 10), ("b", 10), ("c", 10), ("d", 20), ("e", 20)
]
(pathToPMap p) `shouldBe` expected
specify "object with shared labels" $ do
let p :: Path Int
p = Path
[ mkPE ["a", "b", "c"] 10,
mkPE ["b", "c", "d"] 20,
mkPE ["d"] 30,
mkPE [] 40,
mkPE ["b"] 50
]
got = pathToPMap p
expected = pMapFromList
[ ("a", 10), ("b", 10), ("c", 10),
("b", 20), ("c", 20), ("d", 20),
("d", 30),
("b", 50)
]
got `shouldBe` expected
(lookupList ("a" :: AsLabel Int) got) `shouldBe` [10]
(lookupList ("b" :: AsLabel Int) got) `shouldBe` [10, 20, 50]
(lookupList ("c" :: AsLabel Int) got) `shouldBe` [10, 20]
(lookupList ("d" :: AsLabel Int) got) `shouldBe` [20, 30]
(lookupList ("e" :: AsLabel Int) got) `shouldBe` []