{-# 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` []