rdf4h 1.3.4 → 1.3.5
raw patch · 11 files changed
+1776/−23 lines, 11 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Data.RDF.TriplesGraph: instance GHC.Generics.Constructor Data.RDF.TriplesGraph.C1_0TriplesGraph
- Data.RDF.TriplesGraph: instance GHC.Generics.Datatype Data.RDF.TriplesGraph.D1TriplesGraph
- Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_0BaseUrl
- Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_0LValue
- Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_0Node
- Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_0PrefixMappings
- Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_0Triple
- Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_1LValue
- Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_1Node
- Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_2LValue
- Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_2Node
- Data.RDF.Types: instance GHC.Generics.Constructor Data.RDF.Types.C1_3Node
- Data.RDF.Types: instance GHC.Generics.Datatype Data.RDF.Types.D1BaseUrl
- Data.RDF.Types: instance GHC.Generics.Datatype Data.RDF.Types.D1LValue
- Data.RDF.Types: instance GHC.Generics.Datatype Data.RDF.Types.D1Node
- Data.RDF.Types: instance GHC.Generics.Datatype Data.RDF.Types.D1PrefixMappings
- Data.RDF.Types: instance GHC.Generics.Datatype Data.RDF.Types.D1Triple
- Data.RDF: hWriteH :: (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
+ Data.RDF: hWriteH :: forall rdf. (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
- Data.RDF: hWriteRdf :: (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
+ Data.RDF: hWriteRdf :: forall rdf. (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
- Data.RDF: parseFile :: (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
+ Data.RDF: parseFile :: forall rdf. (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
- Data.RDF: parseString :: (RdfParser p, RDF rdf) => p -> Text -> Either ParseFailure rdf
+ Data.RDF: parseString :: forall rdf. (RdfParser p, RDF rdf) => p -> Text -> Either ParseFailure rdf
- Data.RDF: parseURL :: (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
+ Data.RDF: parseURL :: forall rdf. (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
- Data.RDF: writeH :: (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
+ Data.RDF: writeH :: forall rdf. (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
- Data.RDF: writeRdf :: (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
+ Data.RDF: writeRdf :: forall rdf. (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
- Data.RDF.Query: isIsomorphic :: (RDF rdf1, RDF rdf2) => rdf1 -> rdf2 -> Bool
+ Data.RDF.Query: isIsomorphic :: forall rdf1 rdf2. (RDF rdf1, RDF rdf2) => rdf1 -> rdf2 -> Bool
- Data.RDF.Query: rdfContainsNode :: (RDF rdf) => rdf -> Node -> Bool
+ Data.RDF.Query: rdfContainsNode :: forall rdf. (RDF rdf) => rdf -> Node -> Bool
- Data.RDF.Types: hWriteH :: (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
+ Data.RDF.Types: hWriteH :: forall rdf. (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
- Data.RDF.Types: hWriteRdf :: (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
+ Data.RDF.Types: hWriteRdf :: forall rdf. (RdfSerializer s, RDF rdf) => s -> Handle -> rdf -> IO ()
- Data.RDF.Types: parseFile :: (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
+ Data.RDF.Types: parseFile :: forall rdf. (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
- Data.RDF.Types: parseString :: (RdfParser p, RDF rdf) => p -> Text -> Either ParseFailure rdf
+ Data.RDF.Types: parseString :: forall rdf. (RdfParser p, RDF rdf) => p -> Text -> Either ParseFailure rdf
- Data.RDF.Types: parseURL :: (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
+ Data.RDF.Types: parseURL :: forall rdf. (RdfParser p, RDF rdf) => p -> String -> IO (Either ParseFailure rdf)
- Data.RDF.Types: writeH :: (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
+ Data.RDF.Types: writeH :: forall rdf. (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
- Data.RDF.Types: writeRdf :: (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
+ Data.RDF.Types: writeRdf :: forall rdf. (RdfSerializer s, RDF rdf) => s -> rdf -> IO ()
Files
- rdf4h.cabal +10/−1
- src/Data/RDF/Types.hs +4/−22
- testsuite/tests/Data/RDF/GraphTestUtils.hs +418/−0
- testsuite/tests/Data/RDF/MGraph_Test.hs +25/−0
- testsuite/tests/Data/RDF/PatriciaTreeGraph_Test.hs +25/−0
- testsuite/tests/Data/RDF/TriplesGraph_Test.hs +25/−0
- testsuite/tests/Text/RDF/RDF4H/TurtleParser_ConformanceTest.hs +155/−0
- testsuite/tests/Text/RDF/RDF4H/XmlParser_Test.hs +690/−0
- testsuite/tests/W3C/Manifest.hs +304/−0
- testsuite/tests/W3C/NTripleTest.hs +58/−0
- testsuite/tests/W3C/RdfXmlTest.hs +62/−0
rdf4h.cabal view
@@ -1,5 +1,5 @@ name: rdf4h-version: 1.3.4+version: 1.3.5 synopsis: A library for RDF processing in Haskell description: 'RDF for Haskell' is a library for working with RDF in Haskell.@@ -96,6 +96,15 @@ test-suite test-rdf4h type: exitcode-stdio-1.0 main-is: Test.hs+ other-modules: Data.RDF.GraphTestUtils+ Data.RDF.MGraph_Test+ Data.RDF.PatriciaTreeGraph_Test+ Text.RDF.RDF4H.TurtleParser_ConformanceTest+ Text.RDF.RDF4H.XmlParser_Test+ Data.RDF.TriplesGraph_Test+ W3C.Manifest+ W3C.NTripleTest+ W3C.RdfXmlTest ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-orphans -fno-warn-name-shadowing -funbox-strict-fields extensions: RankNTypes MultiParamTypeClasses Arrows FlexibleContexts OverloadedStrings build-depends: base >= 4 && < 6
src/Data/RDF/Types.hs view
@@ -144,6 +144,10 @@ -- For background on 'unodeValidate', see: -- http://stackoverflow.com/questions/33250184/unescaping-unicode-literals-found-in-haskell-strings+--+-- Escaped literals are defined in the Turtle spec, and is+-- inherited by the NTriples and XML specification.+-- http://www.w3.org/TR/turtle/#sec-escapes -- |Validate a URI and return it in a @Just UNode@ if it is -- valid, otherwise @Nothing@ is returned. Performs the following:@@ -161,19 +165,6 @@ unicodeEscParser = do ss <- many ( try (do { _ <- char '\\'- ; _ <- char 'u'- ; pos1 <- digit- ; pos2 <- digit- ; pos3 <- digit- ; pos4 <- digit- ; pos5 <- digit- ; pos6 <- digit- ; pos7 <- digit- ; pos8 <- digit- ; let str = ['\\','x',pos1,pos2,pos3,pos4,pos5,pos6,pos7,pos8]- ; return (read ("\"" ++ str ++ "\"") :: String)})- <|>- try (do { _ <- char '\\' ; _ <- char 'U' ; pos1 <- digit ; pos2 <- digit@@ -188,15 +179,6 @@ <|> try (do { _ <- char '\\' ; _ <- char 'u'- ; pos1 <- digit- ; pos2 <- digit- ; pos3 <- digit- ; pos4 <- digit- ; let str = ['\\','x',pos1,pos2,pos3,pos4]- ; return (read ("\"" ++ str ++ "\"") :: String)})- <|>- try (do { _ <- char '\\'- ; _ <- char 'U' ; pos1 <- digit ; pos2 <- digit ; pos3 <- digit
+ testsuite/tests/Data/RDF/GraphTestUtils.hs view
@@ -0,0 +1,418 @@+module Data.RDF.GraphTestUtils where++import Control.Applicative ((<$>))+import Data.ByteString (pack)+import qualified Data.ByteString.Char8 as C+import Data.Knob+import Data.RDF.Types+import Data.RDF.Query+import Data.RDF.Namespace+import Text.RDF.RDF4H.NTriplesSerializer+import qualified Data.Text as T+import Test.QuickCheck+import Data.List+import qualified Data.Set as Set+import qualified Data.Map as Map+import Control.Monad+import System.IO.Unsafe(unsafePerformIO)+import System.IO++import Test.Framework (Test,TestName,testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.QuickCheck.Monadic (assert, monadicIO,run)++----------------------------------------------------+-- property based quick check test cases --+----------------------------------------------------++graphTests :: forall rdf. (Arbitrary rdf, RDF rdf, Show rdf)+ => TestName -> (rdf -> Triples) -> (rdf -> Triples) -> rdf -> (Triples -> Maybe BaseUrl -> PrefixMappings -> rdf) -> [Test]+graphTests testGroupName _triplesOf _uniqTriplesOf _empty _mkRdf = [ testGroup testGroupName+ [+ testProperty "empty" (p_empty _triplesOf _empty)+ , testProperty "mkRdf_triplesOf" (p_mkRdf_triplesOf _triplesOf _mkRdf)+ , testProperty "mkRdf_no_dupes" (p_mkRdf_no_dupes _uniqTriplesOf _mkRdf)+ , testProperty "query_match_none" (p_query_match_none _mkRdf)+ , testProperty "query_matched_spo" (p_query_matched_spo _triplesOf)+ -- see comment above p_query_matched_spo_no_dupes for why this is disabled+ -- , testProperty "query_matched_spo_no_dupes" (p_query_matched_spo_no_dupes _triplesOf _mkRdf)+ , testProperty "query_unmatched_spo" (p_query_unmatched_spo _triplesOf)+ , testProperty "query_match_s" (p_query_match_s _triplesOf)+ , testProperty "query_match_p" (p_query_match_p _triplesOf)+ , testProperty "query_match_o" (p_query_match_o _triplesOf)+ , testProperty "query_match_sp" (p_query_match_sp _triplesOf)+ , testProperty "query_match_so" (p_query_match_so _triplesOf)+ , testProperty "query_match_po" (p_query_match_po _triplesOf)+ , testProperty "select_match_none" (p_select_match_none _triplesOf)+ , testProperty "select_match_s" (p_select_match_s _triplesOf)+ , testProperty "select_match_p" (p_select_match_p _triplesOf)+ , testProperty "select_match_o" (p_select_match_o _triplesOf)+ , testProperty "select_match_sp" (p_select_match_sp _triplesOf)+ , testProperty "select_match_so" (p_select_match_so _triplesOf)+ , testProperty "select_match_po" (p_select_match_po _triplesOf)+ , testProperty "select_match_spo" (p_select_match_spo _triplesOf)+ , testProperty "reversed RDF handle write" (p_reverseRdfTest _mkRdf)+ ]+ ]+++instance Arbitrary BaseUrl where+ arbitrary = oneof $ map (return . BaseUrl . T.pack) ["http://example.com/a", "http://asdf.org/b"]+ --coarbitrary = undefined++instance Arbitrary PrefixMappings where+ arbitrary = oneof [return $ PrefixMappings Map.empty, return $ PrefixMappings $+ Map.fromAscList [(T.pack "eg1", T.pack "http://example.com/1"),+ (T.pack "eg2", T.pack "http://example.com/2")]]+ --coarbitrary = undefined++-- Test stubs, which just require the appropriate RDF impl function+-- passed in to determine the implementation to be tested.++-- empty RDF should have no triples+p_empty :: RDF rdf => (rdf -> Triples) -> rdf -> Bool+p_empty _triplesOf _empty = _triplesOf _empty == []++-- triplesOf any RDF should return unique triples used to create it+p_mkRdf_triplesOf :: RDF rdf => (rdf -> Triples) -> (Triples -> Maybe BaseUrl -> PrefixMappings -> rdf) -> Triples -> Maybe BaseUrl -> PrefixMappings -> Bool+p_mkRdf_triplesOf _triplesOf _mkRdf ts bUrl pms =+ uordered (_triplesOf (_mkRdf ts bUrl pms)) == uordered ts++-- duplicate input triples should not be returned when+-- uniqTriplesof is used+p_mkRdf_no_dupes :: RDF rdf => (rdf -> Triples) -> (Triples -> Maybe BaseUrl -> PrefixMappings -> rdf) -> Triples -> Maybe BaseUrl -> PrefixMappings -> Bool+p_mkRdf_no_dupes _uniqtriplesOf _mkRdf ts bUrl pms =+ null ts || (sort result == uordered ts)+ where+ tsWithDupe = head ts : ts+ result = _uniqtriplesOf $ _mkRdf tsWithDupe bUrl pms++-- Note: in TriplesGraph and PatriciaTreeGraph `query` expands triples+-- but `ts` here is not necessarily expanded. What is the correct+-- property this test should check?+--+-- query with all 3 wildcards should yield all triples in RDF+p_query_match_none :: RDF rdf => (Triples -> Maybe BaseUrl -> PrefixMappings -> rdf) -> Triples -> Maybe BaseUrl -> PrefixMappings -> Bool+p_query_match_none _mkRdf ts bUrl pms = uordered ts == uordered result+ where+ result = query (_mkRdf ts bUrl pms) Nothing Nothing Nothing++-- query with no wildcard and a triple in the RDF should yield+-- a singleton list with just the triple.+p_query_matched_spo :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_query_matched_spo _triplesOf rdf =+ classify (null ts) "trivial" $+ forAll (tripleFromGen _triplesOf rdf) f+ where+ ts = _triplesOf rdf+ f t = case t of+ Nothing -> True+ (Just t') -> [t'] == queryT rdf t'++{- disabled:+-- removing duplicates from `query` (and `select`) is deprecated, see+-- https://github.com/cordawyn/rdf4h/commit/9dd4729908db8d2f80088706592adac81a0f3016+--+-- query as in p_query_matched_spo after duplicating a triple in the+-- RDF, so that we can verify that the results just have 1, even+-- if the RDF itself doesn't ensure that there are no dupes internally.+p_query_matched_spo_no_dupes :: RDF rdf => (rdf -> Triples) -> (Triples -> Maybe BaseUrl -> PrefixMappings -> rdf) -> rdf -> Property+p_query_matched_spo_no_dupes _triplesOf _mkRdf rdf =+ classify (null ts) "trivial" $+ forAll (tripleFromGen _triplesOf rdf) f+ where+ ts = _triplesOf rdf+ f t = case t of+ Nothing -> True+ Just t' -> [t'] == queryT (mkRdfWithDupe _triplesOf _mkRdf rdf t') t'+-}++-- query with no wildcard and a triple no in the RDF should yield []+p_query_unmatched_spo :: RDF rdf => (rdf -> Triples) -> rdf -> Triple -> Property+p_query_unmatched_spo _triplesOf rdf t =+ classify (t `elem` ts) "ignored" $+ notElem t ts ==> [] == queryT rdf t+ where+ ts = _triplesOf rdf++-- query with fixed subject and wildcards for pred and obj should yield+-- a list with all triples having subject, and RDF minus result triples+-- should yield all triple with unequal subjects.+p_query_match_s :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_query_match_s = mk_query_match_fn sameSubj f+ where f t = (Just (subjectOf t), Nothing, Nothing)++-- query w/ fixed predicate and wildcards for subj and obj should yield+-- a list with all triples having predicate, and RDFgraph minus result triples+-- should yield all triple with unequal predicates.+p_query_match_p :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_query_match_p = mk_query_match_fn samePred f+ where f t = (Nothing, Just (predicateOf t), Nothing)++-- likewise for fixed subject and predicate with object wildcard+p_query_match_o :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_query_match_o = mk_query_match_fn sameObj f+ where f t = (Nothing, Nothing, Just (objectOf t))++-- verify likewise for fixed subject and predicate with wildcard object+p_query_match_sp :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_query_match_sp = mk_query_match_fn same f+ where same t1 t2 = sameSubj t1 t2 && samePred t1 t2+ f t = (Just $ subjectOf t, Just $ predicateOf t, Nothing)++-- fixed subject and object with wildcard predicate+p_query_match_so :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_query_match_so = mk_query_match_fn same f+ where same t1 t2 = sameSubj t1 t2 && sameObj t1 t2+ f t = (Just $ subjectOf t, Nothing, Just $ objectOf t)++-- fixed predicate and object with wildcard subject+p_query_match_po :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_query_match_po = mk_query_match_fn same f+ where same t1 t2 = samePred t1 t2 && sameObj t1 t2+ f t = (Nothing, Just $ predicateOf t, Just $ objectOf t)++mk_query_match_fn :: RDF rdf => (Triple -> Triple -> Bool)+ -> (Triple -> (Maybe Node, Maybe Node, Maybe Node))+ -> (rdf -> Triples) -> rdf -> Property+mk_query_match_fn tripleCompareFn mkPatternFn _triplesOf rdf =+ forAll (tripleFromGen _triplesOf rdf) f+ where+ f :: Maybe Triple -> Bool+ f Nothing = True+ f (Just t) =+ let+ all_ts = _triplesOf rdf+ all_ts_sorted = uordered all_ts+ results = uordered $ queryC rdf (mkPatternFn t)+ notResults = ldiff all_ts_sorted results+ in+ all (tripleCompareFn t) results &&+ all (not . tripleCompareFn t) notResults++p_select_match_none :: RDF rdf => (rdf -> Triples) -> rdf -> Bool+p_select_match_none _triplesOf_not_used rdf = sort ts1 == sort ts2+ where+ ts1 = select rdf Nothing Nothing Nothing+ -- ts2 = (nub . triplesOf) rdf++ -- may have duplicates, see comments in+ -- https://github.com/cordawyn/rdf4h/commit/9dd4729908db8d2f80088706592adac81a0f3016+ ts2 = triplesOf rdf++p_select_match_s :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_select_match_s =+ p_select_match_fn same mkPattern+ where+ same = equivNode (==) subjectOf+ mkPattern t = (Just (\n -> n == subjectOf t), Nothing, Nothing)++p_select_match_p :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_select_match_p =+ p_select_match_fn same mkPattern+ where+ same = equivNode equiv predicateOf+ equiv (UNode u1) (UNode u2) = T.last u1 == T.last u2+ equiv _ _ = error "GraphTestUtils.p_select_match_p.equiv"+ mkPattern t = (Nothing, Just (\n -> lastChar n == lastChar (predicateOf t)) , Nothing)+ lastChar (UNode uri) = T.last uri+ lastChar _ = error "GraphTestUtils.p_select_match_p.lastChar"+++p_select_match_o :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_select_match_o =+ p_select_match_fn same mkPattern+ where+ same = equivNode (/=) objectOf+ mkPattern t = (Nothing, Nothing, Just (\n -> n /= objectOf t))++p_select_match_sp :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_select_match_sp =+ p_select_match_fn same mkPattern+ where+ same t1 t2 = subjectOf t1 == subjectOf t2 && predicateOf t1 /= predicateOf t2+ mkPattern t = (Just (\n -> n == subjectOf t), Just (\n -> n /= predicateOf t), Nothing)++p_select_match_so :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_select_match_so =+ p_select_match_fn same mkPattern+ where+ same t1 t2 = subjectOf t1 /= subjectOf t2 && objectOf t1 == objectOf t2+ mkPattern t = (Just (\n -> n /= subjectOf t), Nothing, Just (\n -> n == objectOf t))++p_select_match_po :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_select_match_po =+ p_select_match_fn same mkPattern+ where+ same t1 t2 = predicateOf t1 == predicateOf t2 && objectOf t1 == objectOf t2+ mkPattern t = (Nothing, Just (\n -> n == predicateOf t), Just (\n -> n == objectOf t))++p_select_match_spo :: RDF rdf => (rdf -> Triples) -> rdf -> Property+p_select_match_spo =+ p_select_match_fn same mkPattern+ where+ same t1 t2 = subjectOf t1 == subjectOf t2 && predicateOf t1 == predicateOf t2 &&+ objectOf t1 /= objectOf t2+ mkPattern t = (Just (\n -> n == subjectOf t),+ Just (\n -> n == predicateOf t),+ Just (\n -> n /= objectOf t))++equivNode :: (Node -> Node -> Bool) -> (Triple -> Node) -> Triple -> Triple -> Bool+equivNode eqFn exFn t1 t2 = exFn t1 `eqFn` exFn t2++p_select_match_fn :: RDF rdf => (Triple -> Triple -> Bool)+ -> (Triple -> (NodeSelector, NodeSelector, NodeSelector))+ -> (rdf -> Triples) -> rdf -> Property+p_select_match_fn tripleCompareFn mkPatternFn _triplesOf rdf =+ forAll (tripleFromGen _triplesOf rdf) f+ where+ f :: Maybe Triple -> Bool+ f Nothing = True+ f (Just t) =+ let+ all_ts = triplesOf rdf+ all_ts_sorted = uordered all_ts+ results = uordered $ selectC rdf (mkPatternFn t)+ notResults = ldiff all_ts_sorted results+ in+ all (tripleCompareFn t) results &&+ all (not . tripleCompareFn t) notResults++mkRdfWithDupe :: RDF rdf => (rdf -> Triples) -> (Triples -> Maybe BaseUrl -> PrefixMappings -> rdf) -> rdf -> Triple -> rdf+mkRdfWithDupe _triplesOf _mkRdf rdf t = _mkRdf ts (baseUrl rdf) (prefixMappings rdf)+ where ts = t : _triplesOf rdf+++-- Utility functions and test data ... --++-- a curried version of query that delegates to the actual query after unpacking+-- curried maybe node pattern.+queryC :: RDF rdf => rdf -> (Maybe Node, Maybe Node, Maybe Node) -> Triples+queryC rdf (s, p, o) = query rdf s p o++selectC :: RDF rdf => rdf -> (NodeSelector, NodeSelector, NodeSelector) -> Triples+selectC rdf (s, p, o) = select rdf s p o++uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d+uncurry3 fn (x, y, z) = fn x y z++curry3 :: ((a, b, c) -> d) -> a -> b -> c -> d+curry3 fn x y z = fn (x, y, z)++debug :: String -> Triples -> Bool+debug msg ts =+ unsafePerformIO $+ putStrLn msg >> mapM print ts >> return True++ldiff :: Triples -> Triples -> Triples+ldiff l1 l2 = Set.toList $(Set.fromList l1) `Set.difference` Set.fromList l2++sameSubj :: Triple -> Triple -> Bool+sameSubj t1 t2 = subjectOf t1 == subjectOf t2++samePred :: Triple -> Triple -> Bool+samePred t1 t2 = predicateOf t1 == predicateOf t2++sameObj :: Triple -> Triple -> Bool+sameObj t1 t2 = objectOf t1 == objectOf t2++-- Convert a list of triples into a sorted list of unique triples.+uordered :: Triples -> Triples+uordered = sort . nub++tripleFromGen :: RDF rdf => (rdf -> Triples) -> rdf -> Gen (Maybe Triple)+tripleFromGen _triplesOf rdf =+ if null ts+ then return Nothing+ else oneof $ map (return . Just) ts+ where ts = _triplesOf rdf++queryT :: RDF rdf => rdf -> Triple -> Triples+queryT rdf t = query rdf (Just $ subjectOf t) (Just $ predicateOf t) (Just $ objectOf t)++languages :: [T.Text]+languages = [T.pack "fr", T.pack "en"]++datatypes :: [T.Text]+datatypes = map (mkUri xsd . T.pack) ["string", "int", "token"]++uris :: [T.Text]+uris = map (mkUri ex) [T.pack n `T.append` T.pack (show (i::Int)) | n <- ["foo", "bar", "quz", "zak"], i <- [0..9]]++plainliterals :: [LValue]+plainliterals = [plainLL lit lang | lit <- litvalues, lang <- languages]++typedliterals :: [LValue]+typedliterals = [typedL lit dtype | lit <- litvalues, dtype <- datatypes]++litvalues :: [T.Text]+litvalues = map T.pack ["hello", "world", "peace", "earth", "", "haskell"]++unodes :: [Node]+unodes = map UNode uris++bnodes :: [ Node]+bnodes = map (BNode . \i -> T.pack ":_genid" `T.append` T.pack (show (i::Int))) [1..5]++lnodes :: [Node]+lnodes = [LNode lit | lit <- plainliterals ++ typedliterals]++test_triples :: [Triple]+test_triples = [triple s p o | s <- unodes ++ bnodes, p <- unodes, o <- unodes ++ bnodes ++ lnodes]++maxN :: Int+maxN = min 100 (length test_triples - 1)++instance Arbitrary Triple where+ arbitrary = liftM3 triple arbitraryS arbitraryP arbitraryO+ --coarbitrary = undefined++instance Arbitrary Node where+ arbitrary = oneof $ map return unodes+ --coarbitrary = undefined++arbitraryTNum :: Gen Int+arbitraryTNum = choose (0, maxN - 1)++arbitraryTs :: Gen Triples+arbitraryTs = do+ n <- sized (\_ -> choose (0, maxN))+ sequence [arbitrary | _ <- [1..n]]++arbitraryT :: Gen Triple+arbitraryT = elements test_triples++arbitraryN :: Gen Int+arbitraryN = choose (0, maxN - 1)++arbitraryS, arbitraryP, arbitraryO :: Gen Node+arbitraryS = oneof $ map return $ unodes ++ bnodes+arbitraryP = oneof $ map return unodes+arbitraryO = oneof $ map return $ unodes ++ bnodes ++ lnodes++----------------------------------------------------+-- Unit test cases --+----------------------------------------------------++-- Reported by Daniel Bergey:+-- https://github.com/robstewart57/rdf4h/issues/4++p_reverseRdfTest :: RDF rdf => (Triples -> Maybe BaseUrl -> PrefixMappings -> rdf) -> Property+p_reverseRdfTest _mkRdf = monadicIO $ do+ fileContents <- run $ do+ knob <- newKnob (pack [])+ h <- newFileHandle knob "test.rdf" WriteMode+ hWriteRdf NTriplesSerializer h rdfGraph+ hClose h+ C.unpack <$> Data.Knob.getContents knob+ let expected = "<file:///this/is/not/a/palindrome> <file:///this/is/not/a/palindrome> \"literal string\" .\n"+ assert $ expected == fileContents++ where+ rdfGraph = _mkRdf ts (Just $ BaseUrl "file://") (ns_mappings [])++ ts :: [Triple]+ ts = [Triple+ (unode "file:///this/is/not/a/palindrome")+ (unode "file:///this/is/not/a/palindrome")+ (LNode . PlainL . T.pack $ "literal string")]
+ testsuite/tests/Data/RDF/MGraph_Test.hs view
@@ -0,0 +1,25 @@+module Data.RDF.MGraph_Test (triplesOf',uniqTriplesOf',empty',mkRdf') where++import Data.RDF.Types+import Data.RDF.MGraph (MGraph)+import Data.RDF.GraphTestUtils+import qualified Data.Map as Map+import Control.Monad++import Test.QuickCheck++instance Arbitrary MGraph where+ arbitrary = liftM3 mkRdf arbitraryTs (return Nothing) (return $ PrefixMappings Map.empty)+ --coarbitrary = undefined++empty' :: MGraph+empty' = empty++mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> MGraph+mkRdf' = mkRdf++triplesOf' :: MGraph -> Triples+triplesOf' = triplesOf++uniqTriplesOf' :: MGraph -> Triples+uniqTriplesOf' = uniqTriplesOf
+ testsuite/tests/Data/RDF/PatriciaTreeGraph_Test.hs view
@@ -0,0 +1,25 @@+module Data.RDF.PatriciaTreeGraph_Test (triplesOf',uniqTriplesOf',empty',mkRdf') where++import Data.RDF.Types+import Data.RDF.PatriciaTreeGraph (PatriciaTreeGraph)+import Data.RDF.GraphTestUtils+import qualified Data.Map as Map+import Control.Monad++import Test.QuickCheck++instance Arbitrary PatriciaTreeGraph where+ arbitrary = liftM3 mkRdf arbitraryTs (return Nothing) (return $ PrefixMappings Map.empty)+ --coarbitrary = undefined++empty' :: PatriciaTreeGraph+empty' = empty++mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> PatriciaTreeGraph+mkRdf' = mkRdf++triplesOf' :: PatriciaTreeGraph -> Triples+triplesOf' = triplesOf++uniqTriplesOf' :: PatriciaTreeGraph -> Triples+uniqTriplesOf' = uniqTriplesOf
+ testsuite/tests/Data/RDF/TriplesGraph_Test.hs view
@@ -0,0 +1,25 @@+module Data.RDF.TriplesGraph_Test (empty',triplesOf',uniqTriplesOf',mkRdf') where++import Control.Monad+import qualified Data.Map as Map+import Data.RDF.GraphTestUtils+import Data.RDF.Namespace+import Data.RDF.TriplesGraph+import Data.RDF.Types+import Test.QuickCheck.Arbitrary++instance Arbitrary TriplesGraph where+ arbitrary = liftM3 mkRdf arbitraryTs (return Nothing) (return $ PrefixMappings Map.empty)+ --coarbitrary = undefined++empty' :: TriplesGraph+empty' = empty++mkRdf' :: Triples -> Maybe BaseUrl -> PrefixMappings -> TriplesGraph+mkRdf' = mkRdf++triplesOf' :: TriplesGraph -> Triples+triplesOf' = triplesOf++uniqTriplesOf' :: TriplesGraph -> Triples+uniqTriplesOf' = uniqTriplesOf
+ testsuite/tests/Text/RDF/RDF4H/TurtleParser_ConformanceTest.hs view
@@ -0,0 +1,155 @@+module Text.RDF.RDF4H.TurtleParser_ConformanceTest where++-- Testing imports+import Test.Framework.Providers.API+import Test.Framework.Providers.HUnit+import qualified Test.HUnit as TU++-- Import common libraries to facilitate tests+import Control.Monad (liftM)+import Data.RDF.GraphTestUtils+import Data.RDF.Query+import Data.RDF.TriplesGraph+import Data.RDF.Types+import qualified Data.Text as T+import qualified Data.Text.IO as TIO+import Text.Printf+import Text.RDF.RDF4H.TurtleParser++tests :: [Test]+tests = [ testGroup "TurtleParser" allCTests ]++-- A list of other tests to run, each entry of which is (directory, fname_without_ext).+otherTestFiles :: [(String, String)]+otherTestFiles = [("data/ttl", "example1"),+ ("data/ttl", "example2"),+ ("data/ttl", "example3"),+ ("data/ttl", "example5"),+ ("data/ttl", "example6"),+-- ("data/ttl", "example7"), -- rdf4h URIs support RFC3986, not unicode IRIs in RFC3987+ ("data/ttl", "example8"),+ ("data/ttl", "fawlty1")+ ]++-- The Base URI to be used for all conformance tests:+testBaseUri :: String+testBaseUri = "http://www.w3.org/2001/sw/DataAccess/df1/tests/"++mtestBaseUri :: Maybe BaseUrl+mtestBaseUri = Just $ BaseUrl $ T.pack testBaseUri++fpath :: String -> Int -> String -> String+fpath name i ext = printf "data/ttl/conformance/%s-%02d.%s" name i ext :: String++allCTests :: [Test]+allCTests = ts1 ++ ts2 ++ ts3+ where+ ts1 = map (buildTest . checkGoodConformanceTest) [0..30]+ ts2 = map (buildTest . checkBadConformanceTest) [0..14]+ ts3 = map (buildTest . uncurry checkGoodOtherTest) otherTestFiles++checkGoodConformanceTest :: Int -> IO Test+checkGoodConformanceTest i =+ do+ expGr <- loadExpectedGraph "test" i+ inGr <- loadInputGraph "test" i+ doGoodConformanceTest expGr inGr (printf "test %d" i :: String)++checkGoodOtherTest :: String -> String -> IO Test+checkGoodOtherTest dir fname =+ do + expGr <- loadExpectedGraph1 (printf "%s/%s.out" dir fname :: String)+ inGr <- loadInputGraph1 dir fname+ doGoodConformanceTest expGr inGr $ printf "test using file \"%s\"" fname++doGoodConformanceTest :: Either ParseFailure TriplesGraph -> + Either ParseFailure TriplesGraph -> + String -> IO Test+doGoodConformanceTest expGr inGr testname = do+ let t1 = assertLoadSuccess (printf "expected (%s): " testname) expGr+ t2 = assertLoadSuccess (printf " input (%s): " testname) inGr+ t3 = assertEquivalent testname expGr inGr+ return $ testGroup (printf "Conformance %s" testname) $ map (uncurry testCase) [("Loading expected graph data", t1), ("Loading input graph data", t2), ("Comparing graphs", t3)]++checkBadConformanceTest :: Int -> IO Test+checkBadConformanceTest i = do+ let t = loadInputGraph "bad" i >>= assertLoadFailure (show i)+ return $ testCase (printf "Loading test %d (negative)" i) t++-- Determines if graphs are equivalent, returning Nothing if so or else a diagnostic message.+-- First graph is expected graph, second graph is actual.+equivalent :: RDF rdf => Either ParseFailure rdf -> Either ParseFailure rdf -> Maybe String+equivalent (Left _) _ = Nothing+equivalent _ (Left _) = Nothing+equivalent (Right gr1) (Right gr2) = test $! zip gr1ts gr2ts+ where+ gr1ts = uordered $ triplesOf gr1+ gr2ts = uordered $ triplesOf gr2+ test [] = Nothing+ test ((t1,t2):ts) =+ case compareTriple t1 t2 of+ Nothing -> test ts+ err -> err+ compareTriple t1 t2 =+ if equalNodes s1 s2 && equalNodes p1 p2 && equalNodes o1 o2+ then Nothing+ else Just ("Expected:\n " ++ show t1 ++ "\nFound:\n " ++ show t2 ++ "\n")+ where+ (s1, p1, o1) = f t1+ (s2, p2, o2) = f t2+ f t = (subjectOf t, predicateOf t, objectOf t)+ -- equalNodes (BNode fs1) (BNodeGen i) = T.reverse fs1 == T.pack ("_:genid" ++ show i)+ equalNodes (BNode fs1) (BNodeGen i) = fs1 == T.pack ("_:genid" ++ show i)+ equalNodes n1 n2 = n1 == n2++-- Returns a graph for a good ttl test that is intended to pass, and normalizes+-- triples into a format so that they can be compared with the expected output triples.+loadInputGraph :: String -> Int -> IO (Either ParseFailure TriplesGraph)+loadInputGraph name n =+ TIO.readFile (fpath name n "ttl") >>=+ return . parseString (TurtleParser mtestBaseUri (mkDocUrl testBaseUri name n)) >>= return . handleLoad++loadInputGraph1 :: String -> String -> IO (Either ParseFailure TriplesGraph)+loadInputGraph1 dir fname =+ TIO.readFile (printf "%s/%s.ttl" dir fname :: String) >>=+ return . parseString (TurtleParser mtestBaseUri (mkDocUrl1 testBaseUri fname)) >>= return . handleLoad++handleLoad :: Either ParseFailure TriplesGraph -> Either ParseFailure TriplesGraph+handleLoad res =+ case res of+ l@(Left _) -> l+ (Right gr) -> Right $ mkRdf (map normalize (triplesOf gr)) (baseUrl gr) (prefixMappings gr)++normalize :: Triple -> Triple+normalize t = let s' = normalizeN $ subjectOf t+ p' = normalizeN $ predicateOf t+ o' = normalizeN $ objectOf t+ in triple s' p' o'+normalizeN :: Node -> Node+normalizeN (BNodeGen i) = BNode (T.pack $ "_:genid" ++ show i)+normalizeN n = n++loadExpectedGraph :: String -> Int -> IO (Either ParseFailure TriplesGraph)+loadExpectedGraph name n = loadExpectedGraph1 (fpath name n "out")+loadExpectedGraph1 :: String -> IO (Either ParseFailure TriplesGraph)+loadExpectedGraph1 fname =+ liftM (parseString (TurtleParser mtestBaseUri (mkDocUrl1 testBaseUri fname))) (TIO.readFile fname)++assertLoadSuccess, assertLoadFailure :: String -> Either ParseFailure TriplesGraph -> TU.Assertion+assertLoadSuccess idStr (Left (ParseFailure err)) = TU.assertFailure $ idStr ++ err+assertLoadSuccess _ (Right _) = return ()+assertLoadFailure _ (Left _) = return ()+assertLoadFailure idStr _ = TU.assertFailure $ "Bad test " ++ idStr ++ " loaded successfully."++assertEquivalent :: RDF rdf => String -> Either ParseFailure rdf -> Either ParseFailure rdf -> TU.Assertion+assertEquivalent testname r1 r2 =+ case equiv of+ Nothing -> TU.assert True+ (Just msg) -> fail $ "Graph " ++ testname ++ " not equivalent to expected:\n" ++ msg+ where equiv = equivalent r1 r2++mkDocUrl :: String -> String -> Int -> Maybe T.Text+mkDocUrl baseDocUrl fname testNum = Just $ T.pack $ printf "%s%s-%02d.ttl" baseDocUrl fname testNum++mkDocUrl1 :: String -> String -> Maybe T.Text+mkDocUrl1 baseDocUrl fname = Just $ T.pack $ printf "%s%s.ttl" baseDocUrl fname
+ testsuite/tests/Text/RDF/RDF4H/XmlParser_Test.hs view
@@ -0,0 +1,690 @@+module Text.RDF.RDF4H.XmlParser_Test where++-- todo: QuickCheck tests++-- Testing imports+import Test.Framework (Test,testGroup)+import Test.Framework.Providers.HUnit+import Test.HUnit (Assertion,assertBool,assertFailure)++-- Import common libraries to facilitate tests+import qualified Data.Map as Map+import Data.RDF.Query+import Data.RDF.TriplesGraph (TriplesGraph)+import Data.RDF.Types+import qualified Data.Text as T (Text, unlines)+import Text.RDF.RDF4H.XmlParser+ +tests :: [Test]+tests = [ testGroup "XmlParser:parseXmlRDF" [ testCase "simpleStriping1" test_simpleStriping1+ , testCase "simpleStriping2" test_simpleStriping2+ , testCase "simpleSingleton1" test_simpleSingleton1+ , testCase "simpleSingleton2" test_simpleSingleton2+ , testCase "example07" test_parseXmlRDF_example07+ , testCase "example08" test_parseXmlRDF_example08+ , testCase "example09" test_parseXmlRDF_example09+ , testCase "example10" test_parseXmlRDF_example10+ , testCase "example11" test_parseXmlRDF_example11+ , testCase "example12" test_parseXmlRDF_example12+ , testCase "example13" test_parseXmlRDF_example13+ , testCase "example14" test_parseXmlRDF_example14+ , testCase "example15" test_parseXmlRDF_example15+ , testCase "example16" test_parseXmlRDF_example16+ , testCase "example17" test_parseXmlRDF_example17+ , testCase "example18" test_parseXmlRDF_example18+ , testCase "example19" test_parseXmlRDF_example19+ , testCase "example20" test_parseXmlRDF_example20+ , testCase "vCardPersonal" test_parseXmlRDF_vCardPersonal+ , testCase "NML" test_parseXmlRDF_NML+ , testCase "NML2" test_parseXmlRDF_NML2+ , testCase "NML3" test_parseXmlRDF_NML3+ ]+ ]+++mkTextNode :: T.Text -> Node+mkTextNode = lnode . plainL++testParse :: T.Text -> TriplesGraph -> Assertion+testParse exRDF ex =+ case parsed of+ Right result ->+ assertBool+ ("expected: " ++ show ex ++ "but got: " ++ show result)+ (isIsomorphic (result :: TriplesGraph) (ex :: TriplesGraph))+ Left (ParseFailure err) ->+ assertFailure err+ where parsed = parseString (XmlParser Nothing Nothing) exRDF++test_simpleStriping1 :: Assertion+test_simpleStriping1 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\+ \<rdf:Description rdf:about=\"http://www.w3.org/TR/rdf-syntax-grammar\">\+ \<dc:title>RDF/XML Syntax Specification (Revised)</dc:title>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:title")+ (mkTextNode "RDF/XML Syntax Specification (Revised)") ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("dc", "http://purl.org/dc/elements/1.1/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++test_simpleStriping2 :: Assertion+test_simpleStriping2 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\+ \<rdf:Description rdf:about=\"http://www.w3.org/TR/rdf-syntax-grammar\">\+ \<dc:title>RDF/XML Syntax Specification (Revised)</dc:title>\+ \</rdf:Description>\+ \<rdf:Description rdf:about=\"http://example.org/buecher/baum\">\+ \<dc:title>Der Baum</dc:title>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:title")+ (mkTextNode "RDF/XML Syntax Specification (Revised)") + , Triple (unode "http://example.org/buecher/baum")+ (unode "dc:title")+ (mkTextNode "Der Baum")+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("dc", "http://purl.org/dc/elements/1.1/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++test_simpleSingleton1 :: Assertion+test_simpleSingleton1 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\+ \<rdf:Description rdf:about=\"http://www.w3.org/TR/rdf-syntax-grammar\"\+ \ dc:title=\"RDF/XML Syntax Specification (Revised)\"/>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:title")+ (mkTextNode "RDF/XML Syntax Specification (Revised)") ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("dc", "http://purl.org/dc/elements/1.1/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++test_simpleSingleton2 :: Assertion+test_simpleSingleton2 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\+ \<rdf:Description rdf:about=\"http://www.w3.org/TR/rdf-syntax-grammar\"\+ \ dc:title=\"RDF/XML Syntax Specification (Revised)\"\+ \ dc:subject=\"RDF\"/>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:title")+ (mkTextNode "RDF/XML Syntax Specification (Revised)")+ , Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:subject")+ (mkTextNode "RDF") ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("dc", "http://purl.org/dc/elements/1.1/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++-- * Document Element and XML Declaration+test_parseXmlRDF_example07 :: Assertion+test_parseXmlRDF_example07 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\+ \ xmlns:ex=\"http://example.org/stuff/1.0/\">\+ \<rdf:Description rdf:about=\"http://www.w3.org/TR/rdf-syntax-grammar\"\+ \ dc:title=\"RDF/XML Syntax Specification (Revised)\">\+ \<ex:editor>\+ \<rdf:Description ex:fullName=\"Dave Beckett\">\+ \<ex:homePage rdf:resource=\"http://purl.org/net/dajobe/\" />\+ \</rdf:Description>\+ \</ex:editor>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:title")+ (mkTextNode "RDF/XML Syntax Specification (Revised)")+ , Triple (BNodeGen 1) (unode "ex:fullName") (mkTextNode "Dave Beckett")+ , Triple (BNodeGen 1) (unode "ex:homePage") (unode "http://purl.org/net/dajobe/")+ , Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar") (unode "ex:editor") (BNodeGen 1)+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("dc", "http://purl.org/dc/elements/1.1/")+ , ("ex", "http://example.org/stuff/1.0/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++-- * Languages: xml:lang+test_parseXmlRDF_example08 :: Assertion+test_parseXmlRDF_example08 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\+ \<rdf:Description rdf:about=\"http://www.w3.org/TR/rdf-syntax-grammar\">\+ \<dc:title>RDF/XML Syntax Specification (Revised)</dc:title>\+ \<dc:title xml:lang=\"en\">RDF/XML Syntax Specification (Revised)</dc:title>\+ \<dc:title xml:lang=\"en-US\">RDF/XML Syntax Specification (Revised)</dc:title>\+ \</rdf:Description>\+ \<rdf:Description rdf:about=\"http://example.org/buecher/baum\" xml:lang=\"de\">\+ \<dc:title>Der Baum</dc:title>\+ \<dc:description>Das Buch ist außergewöhnlich</dc:description>\+ \<dc:title xml:lang=\"en\">The Tree</dc:title>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:title")+ (mkTextNode "RDF/XML Syntax Specification (Revised)")+ , Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:title")+ (lnode (plainLL ("RDF/XML Syntax Specification (Revised)") ("en")))+ , Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:title")+ (lnode (plainLL ("RDF/XML Syntax Specification (Revised)") ("en-US")))+ , Triple (unode "http://example.org/buecher/baum")+ (unode "dc:title")+ (lnode (plainLL ("Der Baum") ("de")))+ , Triple (unode "http://example.org/buecher/baum")+ (unode "dc:description")+ (lnode (plainLL ("Das Buch ist außergewöhnlich") ("de")))+ , Triple (unode "http://example.org/buecher/baum")+ (unode "dc:title")+ (lnode (plainLL ("The Tree") ("en")))+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("dc", "http://purl.org/dc/elements/1.1/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++-- * XML Literals: rdf:parseType="Literal"+test_parseXmlRDF_example09 :: Assertion+test_parseXmlRDF_example09 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:ex=\"http://example.org/stuff/1.0/\">\+ \<rdf:Description rdf:about=\"http://example.org/item01\">\+ \<ex:prop rdf:parseType=\"Literal\"\+ \ xmlns:a=\"http://example.org/a#\"><a:Box required=\"true\">\+ \<a:widget size=\"10\" />\+ \<a:grommit id=\"23\" /></a:Box>\+ \</ex:prop>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://example.org/item01")+ (unode "ex:prop")+ (lnode (typedL ("<a:Box required=\"true\">\+ \<a:widget size=\"10\"/>\+ \<a:grommit id=\"23\"/>\+ \</a:Box>")+ ("http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral")))+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("ex", "http://example.org/stuff/1.0/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++-- * Typed Literals: rdf:datatype+test_parseXmlRDF_example10 :: Assertion+test_parseXmlRDF_example10 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:ex=\"http://example.org/stuff/1.0/\">\+ \<rdf:Description rdf:about=\"http://example.org/item01\">\+ \<ex:size rdf:datatype=\"http://www.w3.org/2001/XMLSchema#int\">123</ex:size>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://example.org/item01")+ (unode "ex:size")+ (lnode (typedL ("123")+ ("http://www.w3.org/2001/XMLSchema#int")))+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("ex", "http://example.org/stuff/1.0/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++-- * Identifying Blank Nodes: rdf:nodeID+test_parseXmlRDF_example11 :: Assertion+test_parseXmlRDF_example11 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\+ \ xmlns:ex=\"http://example.org/stuff/1.0/\">\+ \<rdf:Description rdf:about=\"http://www.w3.org/TR/rdf-syntax-grammar\"\+ \ dc:title=\"RDF/XML Syntax Specification (Revised)\">\+ \<ex:editor rdf:nodeID=\"abc\"/>\+ \</rdf:Description>\+ \<rdf:Description rdf:nodeID=\"abc\"\+ \ ex:fullName=\"Dave Beckett\">\+ \<ex:homePage rdf:resource=\"http://purl.org/net/dajobe/\"/>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:title")+ (mkTextNode "RDF/XML Syntax Specification (Revised)")+ , Triple (mkBNode "abc") (unode "ex:fullName") (mkTextNode "Dave Beckett")+ , Triple (mkBNode "abc") (unode "ex:homePage") (unode "http://purl.org/net/dajobe/")+ , Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "ex:editor")+ (mkBNode "abc")+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("dc", "http://purl.org/dc/elements/1.1/")+ , ("ex", "http://example.org/stuff/1.0/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )+ where mkBNode = BNode++-- * Omitting Blank Nodes: rdf:parseType="Resource"+test_parseXmlRDF_example12 :: Assertion+test_parseXmlRDF_example12 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\+ \ xmlns:ex=\"http://example.org/stuff/1.0/\">\+ \<rdf:Description rdf:about=\"http://www.w3.org/TR/rdf-syntax-grammar\"\+ \ dc:title=\"RDF/XML Syntax Specification (Revised)\">\+ \<ex:editor rdf:parseType=\"Resource\">\+ \<ex:fullName>Dave Beckett</ex:fullName>\+ \<ex:homePage rdf:resource=\"http://purl.org/net/dajobe/\"/>\+ \</ex:editor>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:title")+ (mkTextNode "RDF/XML Syntax Specification (Revised)")+ , Triple (BNodeGen 1) (unode "ex:fullName") (mkTextNode "Dave Beckett")+ , Triple (BNodeGen 1) (unode "ex:homePage") (unode "http://purl.org/net/dajobe/")+ , Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "ex:editor")+ (BNodeGen 1)+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("dc", "http://purl.org/dc/elements/1.1/")+ , ("ex", "http://example.org/stuff/1.0/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++-- * Omitting Nodes: Property Attributes on an empty Property Element+test_parseXmlRDF_example13 :: Assertion+test_parseXmlRDF_example13 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\+ \ xmlns:ex=\"http://example.org/stuff/1.0/\">\+ \<rdf:Description rdf:about=\"http://www.w3.org/TR/rdf-syntax-grammar\"\+ \ dc:title=\"RDF/XML Syntax Specification (Revised)\">\+ \<ex:editor ex:fullName=\"Dave Beckett\" />\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "dc:title")+ (mkTextNode "RDF/XML Syntax Specification (Revised)")+ , Triple (BNodeGen 1)+ (unode "ex:fullName")+ (mkTextNode "Dave Beckett")+ , Triple (unode "http://www.w3.org/TR/rdf-syntax-grammar")+ (unode "ex:editor")+ (BNodeGen 1)+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("dc", "http://purl.org/dc/elements/1.1/")+ , ("ex", "http://example.org/stuff/1.0/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++-- * Typed Node Elements+test_parseXmlRDF_example14 :: Assertion+test_parseXmlRDF_example14 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\+ \ xmlns:ex=\"http://example.org/stuff/1.0/\">\+ \<rdf:Description rdf:about=\"http://example.org/thing\">\+ \<rdf:type rdf:resource=\"http://example.org/stuff/1.0/Document\"/>\+ \<dc:title>A marvelous thing</dc:title>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://example.org/thing")+ (unode "rdf:type")+ (unode "http://example.org/stuff/1.0/Document")+ , Triple (unode "http://example.org/thing")+ (unode "dc:title")+ (mkTextNode "A marvelous thing")+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("dc", "http://purl.org/dc/elements/1.1/")+ , ("ex", "http://example.org/stuff/1.0/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++test_parseXmlRDF_example15 :: Assertion+test_parseXmlRDF_example15 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\+ \ xmlns:ex=\"http://example.org/stuff/1.0/\">\+ \<ex:Document rdf:about=\"http://example.org/thing\">\+ \<dc:title>A marvelous thing</dc:title>\+ \</ex:Document>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://example.org/thing")+ (unode "rdf:type")+ (unode "ex:Document")+ , Triple (unode "http://example.org/thing")+ (unode "dc:title")+ (mkTextNode "A marvelous thing")+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("dc", "http://purl.org/dc/elements/1.1/")+ , ("ex", "http://example.org/stuff/1.0/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++-- * Abbreviating URIs: rdf:ID and xml:base+test_parseXmlRDF_example16 :: Assertion+test_parseXmlRDF_example16 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:ex=\"http://example.org/stuff/1.0/\"\+ \ xml:base=\"http://example.org/here/\">\+ \<rdf:Description rdf:ID=\"snack\">\+ \<ex:prop rdf:resource=\"fruit/apple\"/>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://example.org/here/#snack") (unode "ex:prop") (unode "http://example.org/here/fruit/apple") ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("base", "http://example.org/here/")+ , ("ex", "http://example.org/stuff/1.0/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++-- * Container Membership Property Elements: rdf:li and rdf:_n+test_parseXmlRDF_example17 :: Assertion+test_parseXmlRDF_example17 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\+ \<rdf:Seq rdf:about=\"http://example.org/favourite-fruit\">\+ \<rdf:_1 rdf:resource=\"http://example.org/banana\"/>\+ \<rdf:_2 rdf:resource=\"http://example.org/apple\"/>\+ \<rdf:_3 rdf:resource=\"http://example.org/pear\"/>\+ \</rdf:Seq>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://example.org/favourite-fruit")+ (unode "rdf:type")+ (unode "rdf:Seq")+ , Triple (unode "http://example.org/favourite-fruit")+ (unode "rdf:_1")+ (unode "http://example.org/banana")+ , Triple (unode "http://example.org/favourite-fruit")+ (unode "rdf:_2")+ (unode "http://example.org/apple")+ , Triple (unode "http://example.org/favourite-fruit")+ (unode "rdf:_3")+ (unode "http://example.org/pear")+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++test_parseXmlRDF_example18 :: Assertion+test_parseXmlRDF_example18 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\+ \<rdf:Seq rdf:about=\"http://example.org/favourite-fruit\">\+ \<rdf:li rdf:resource=\"http://example.org/banana\"/>\+ \<rdf:li rdf:resource=\"http://example.org/apple\"/>\+ \<rdf:li rdf:resource=\"http://example.org/pear\"/>\+ \</rdf:Seq>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://example.org/favourite-fruit")+ (unode "rdf:type")+ (unode "rdf:Seq")+ , Triple (unode "http://example.org/favourite-fruit")+ (unode "rdf:_1")+ (unode "http://example.org/banana")+ , Triple (unode "http://example.org/favourite-fruit")+ (unode "rdf:_2")+ (unode "http://example.org/apple")+ , Triple (unode "http://example.org/favourite-fruit")+ (unode "rdf:_3")+ (unode "http://example.org/pear")+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++-- * Collections: rdf:parseType="Collection"+test_parseXmlRDF_example19 :: Assertion+test_parseXmlRDF_example19 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:ex=\"http://example.org/stuff/1.0/\">\+ \<rdf:Description rdf:about=\"http://example.org/basket\">\+ \<ex:hasFruit rdf:parseType=\"Collection\">\+ \<rdf:Description rdf:about=\"http://example.org/banana\"/>\+ \<rdf:Description rdf:about=\"http://example.org/apple\"/>\+ \<rdf:Description rdf:about=\"http://example.org/pear\"/>\+ \</ex:hasFruit>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://example.org/basket") (unode "ex:hasFruit") (BNodeGen 1)+ , Triple (BNodeGen 1)+ (unode "rdf:first")+ (unode "http://example.org/banana")+ , Triple (BNodeGen 1)+ (unode "rdf:rest")+ (BNodeGen 2)+ , Triple (BNodeGen 2)+ (unode "rdf:first")+ (unode "http://example.org/apple")+ , Triple (BNodeGen 2)+ (unode "rdf:rest")+ (BNodeGen 3)+ , Triple (BNodeGen 3)+ (unode "rdf:first")+ (unode "http://example.org/pear")+ , Triple (BNodeGen 3)+ (unode "rdf:rest")+ (unode "rdf:nil")+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("ex", "http://example.org/stuff/1.0/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++-- * Reifying Statements: rdf:ID+test_parseXmlRDF_example20 :: Assertion+test_parseXmlRDF_example20 = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:ex=\"http://example.org/stuff/1.0/\"\+ \ xml:base=\"http://example.org/triples/\">\+ \<rdf:Description rdf:about=\"http://example.org/\">\+ \<ex:prop rdf:ID=\"triple1\">blah</ex:prop>\+ \</rdf:Description>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://example.org/")+ (unode "ex:prop")+ (mkTextNode "blah")+ , Triple (unode "http://example.org/triples/#triple1")+ (unode "rdf:type")+ (unode "rdf:Statement")+ , Triple (unode "http://example.org/triples/#triple1")+ (unode "rdf:subject")+ (unode "http://example.org/")+ , Triple (unode "http://example.org/triples/#triple1")+ (unode "rdf:predicate")+ (unode "ex:prop")+ , Triple (unode "http://example.org/triples/#triple1")+ (unode "rdf:object")+ (mkTextNode "blah")+ ]+ ( Just (BaseUrl ("http://example.org/here/")) )+ ( PrefixMappings (Map.fromList [ ("ex", "http://example.org/stuff/1.0/")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++test_parseXmlRDF_vCardPersonal :: Assertion+test_parseXmlRDF_vCardPersonal = testParse+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \ xmlns:v=\"http://www.w3.org/2006/vcard/ns#\">\+ \<v:VCard rdf:about = \"http://example.com/me/corky\" >\+ \<v:fn>Corky Crystal</v:fn>\+ \<v:nickname>Corks</v:nickname>\+ \<v:tel>\+ \<rdf:Description>\+ \<rdf:value>+61 7 5555 5555</rdf:value>\+ \<rdf:type rdf:resource=\"http://www.w3.org/2006/vcard/ns#Home\"/>\+ \<rdf:type rdf:resource=\"http://www.w3.org/2006/vcard/ns#Voice\"/>\+ \</rdf:Description>\+ \</v:tel>\+ \<v:email rdf:resource=\"mailto:corky@example.com\"/>\+ \<v:adr>\+ \<rdf:Description>\+ \<v:street-address>111 Lake Drive</v:street-address>\+ \<v:locality>WonderCity</v:locality>\+ \<v:postal-code>5555</v:postal-code>\+ \<v:country-name>Australia</v:country-name>\+ \<rdf:type rdf:resource=\"http://www.w3.org/2006/vcard/ns#Home\"/>\+ \</rdf:Description>\+ \</v:adr>\+ \</v:VCard>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "http://example.com/me/corky")+ (unode "rdf:type")+ (unode "v:VCard")+ , Triple (unode "http://example.com/me/corky")+ (unode "v:fn")+ (mkTextNode "Corky Crystal")+ , Triple (unode "http://example.com/me/corky")+ (unode "v:nickname")+ (mkTextNode "Corks")+ , Triple (unode "http://example.com/me/corky")+ (unode "v:tel")+ (BNodeGen 1)+ , Triple (BNodeGen 1)+ (unode "rdf:value")+ (mkTextNode "+61 7 5555 5555")+ , Triple (BNodeGen 1)+ (unode "rdf:type")+ (unode "http://www.w3.org/2006/vcard/ns#Home")+ , Triple (BNodeGen 1)+ (unode "rdf:type")+ (unode "http://www.w3.org/2006/vcard/ns#Voice")+ , Triple (unode "http://example.com/me/corky")+ (unode "v:email")+ (unode "mailto:corky@example.com")+ , Triple (unode "http://example.com/me/corky")+ (unode "v:adr")+ (BNodeGen 2)+ , Triple (BNodeGen 2)+ (unode "v:street-address")+ (mkTextNode "111 Lake Drive")+ , Triple (BNodeGen 2)+ (unode "v:locality")+ (mkTextNode "WonderCity")+ , Triple (BNodeGen 2)+ (unode "v:postal-code")+ (mkTextNode "5555")+ , Triple (BNodeGen 2)+ (unode "v:country-name")+ (mkTextNode "Australia")+ , Triple (BNodeGen 2)+ (unode "rdf:type")+ (unode "http://www.w3.org/2006/vcard/ns#Home")+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("v", "http://www.w3.org/2006/vcard/ns#")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++test_parseXmlRDF_NML :: Assertion+test_parseXmlRDF_NML = testParse+ (T.unlines+ ["<?xml version=\"1.0\" encoding=\"utf-8\"?>"+ ,"<rdf:RDF"+ ," xmlns:nml=\"http://schemas.ogf.org/nml/2013/05/base#\""+ ," xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\""+ ,">"+ ," <nml:Node rdf:about=\"urn:ogf:network:example.org:2014:foo\">"+ ," <nml:hasInboundPort>"+ ," <nml:Port rdf:about=\"urn:ogf:network:example.org:2014:foo:A1:in\">"+ ," <nml:isSink rdf:resource=\"urn:ogf:network:example.org:2014:link:1\"/>"+ ," </nml:Port>"+ ," </nml:hasInboundPort>"+ ," </nml:Node>"+ ,"</rdf:RDF>"+ ])+ ( mkRdf [ Triple (unode "urn:ogf:network:example.org:2014:foo")+ (unode "rdf:type")+ (unode "nml:Node")+ , Triple (unode "urn:ogf:network:example.org:2014:foo")+ (unode "nml:hasInboundPort")+ (unode "urn:ogf:network:example.org:2014:foo:A1:in")+ , Triple (unode "urn:ogf:network:example.org:2014:foo:A1:in")+ (unode "rdf:type")+ (unode "nml:Port")+ , Triple (unode "urn:ogf:network:example.org:2014:foo:A1:in")+ (unode "nml:isSink")+ (unode "urn:ogf:network:example.org:2014:link:1")+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("nml", "http://schemas.ogf.org/nml/2013/05/base#")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++test_parseXmlRDF_NML2 :: Assertion+test_parseXmlRDF_NML2 = testParse+ (T.unlines+ ["<?xml version=\"1.0\" encoding=\"utf-8\"?>"+ ,"<rdf:RDF"+ ," xmlns:nml=\"http://schemas.ogf.org/nml/2013/05/base#\""+ ," xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\""+ ,">"+ ," <nml:Node rdf:about=\"urn:ogf:network:example.org:2014:foo\">"+ ," <nml:hasInboundPort rdf:resource=\"urn:ogf:network:example.org:2014:foo:A1:in\"/>"+ ," </nml:Node>"+ ," <nml:Port rdf:about=\"urn:ogf:network:example.org:2014:foo:A1:in\">"+ ," <nml:isSink rdf:resource=\"urn:ogf:network:example.org:2014:link:1\"/>"+ ," </nml:Port>"+ ,"</rdf:RDF>"+ ])+ ( mkRdf [ Triple (unode "urn:ogf:network:example.org:2014:foo")+ (unode "rdf:type")+ (unode "nml:Node")+ , Triple (unode "urn:ogf:network:example.org:2014:foo")+ (unode "nml:hasInboundPort")+ (unode "urn:ogf:network:example.org:2014:foo:A1:in")+ , Triple (unode "urn:ogf:network:example.org:2014:foo:A1:in")+ (unode "rdf:type")+ (unode "nml:Port")+ , Triple (unode "urn:ogf:network:example.org:2014:foo:A1:in")+ (unode "nml:isSink")+ (unode "urn:ogf:network:example.org:2014:link:1")+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("nml", "http://schemas.ogf.org/nml/2013/05/base#")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )++test_parseXmlRDF_NML3 :: Assertion+test_parseXmlRDF_NML3 = testParse+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\+ \<rdf:RDF\+ \ xmlns:nml=\"http://schemas.ogf.org/nml/2013/05/base#\"\+ \ xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\+ \>\+ \ <nml:Node rdf:about=\"urn:ogf:network:example.org:2014:foo\">\+ \ <nml:hasInboundPort rdf:resource=\"urn:ogf:network:example.org:2014:foo:A1:in\"/>\+ \ </nml:Node>\+ \ <nml:Port rdf:about=\"urn:ogf:network:example.org:2014:foo:A1:in\">\+ \ <nml:isSink rdf:resource=\"urn:ogf:network:example.org:2014:link:1\"/>\+ \ </nml:Port>\+ \</rdf:RDF>"+ ( mkRdf [ Triple (unode "urn:ogf:network:example.org:2014:foo")+ (unode "rdf:type")+ (unode "nml:Node")+ , Triple (unode "urn:ogf:network:example.org:2014:foo")+ (unode "nml:hasInboundPort")+ (unode "urn:ogf:network:example.org:2014:foo:A1:in")+ , Triple (unode "urn:ogf:network:example.org:2014:foo:A1:in")+ (unode "rdf:type")+ (unode "nml:Port")+ , Triple (unode "urn:ogf:network:example.org:2014:foo:A1:in")+ (unode "nml:isSink")+ (unode "urn:ogf:network:example.org:2014:link:1")+ ]+ Nothing+ ( PrefixMappings (Map.fromList [ ("nml", "http://schemas.ogf.org/nml/2013/05/base#")+ , ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") ]) )+ )
+ testsuite/tests/W3C/Manifest.hs view
@@ -0,0 +1,304 @@+module W3C.Manifest (+ loadManifest,++ Manifest(..),+ TestEntry(..)+) where++import Data.RDF.TriplesGraph+import Data.RDF.Query+import Data.RDF.Types+import Data.RDF.Namespace+import Safe+import Text.RDF.RDF4H.TurtleParser++import qualified Data.Text as T+import qualified Data.List as L (find)+import Data.Maybe (fromJust)++-- | Manifest data as represented in W3C test files.+data Manifest =+ Manifest {+ description :: T.Text,+ entries :: [TestEntry]+ }++-- TODO: Fields `name` and `action` are mandatory for all tests,+-- `result` is mandatory for positive *Eval tests,+-- the rest are optional, so we should use "Maybe" for them.+data TestEntry =+ TestTurtleEval {+ name :: T.Text,+ comment :: T.Text,+ approval :: Node,+ action :: Node,+ result :: Node+ } |+ TestTurtleNegativeEval {+ name :: T.Text,+ comment :: T.Text,+ approval :: Node,+ action :: Node+ } |+ TestTurtlePositiveSyntax {+ name :: T.Text,+ comment :: T.Text,+ approval :: Node,+ action :: Node+ } |+ TestTurtleNegativeSyntax {+ name :: T.Text,+ comment :: T.Text,+ approval :: Node,+ action :: Node+ } |+ PositiveEntailmentTest {+ name :: T.Text,+ comment :: T.Text,+ approval :: Node,+ action :: Node,+ result :: Node,+ entailmentRegime :: T.Text,+ recognizedDatatypes :: [Node],+ unrecognizedDatatypes :: [Node]+ } |+ NegativeEntailmentTest {+ name :: T.Text,+ comment :: T.Text,+ approval :: Node,+ action :: Node,+ result :: Node,+ entailmentRegime :: T.Text,+ recognizedDatatypes :: [Node],+ unrecognizedDatatypes :: [Node]+ } |+ TestXMLEval {+ name :: T.Text,+ comment :: T.Text,+ approval :: Node,+ action :: Node,+ result :: Node+ } |+ TestXMLNegativeSyntax {+ name :: T.Text,+ comment :: T.Text,+ approval :: Node,+ action :: Node+ } |+ TestNTriplesPositiveSyntax {+ name :: T.Text,+ comment :: T.Text,+ approval :: Node,+ action :: Node+ } |+ TestNTriplesNegativeSyntax {+ name :: T.Text,+ comment :: T.Text,+ approval :: Node,+ action :: Node+ }+ deriving (Show)++-- TODO: Perhaps these should be pulled from the manifest graph+rdfType = unode $ mkUri rdf "type"+rdfsComment = unode $ mkUri rdfs "comment"+rdftTestTurtleEval = unode "http://www.w3.org/ns/rdftest#TestTurtleEval"+rdftTestTurtleNegativeEval = unode "http://www.w3.org/ns/rdftest#TestTurtleNegativeEval"+rdftApproval = unode "http://www.w3.org/ns/rdftest#approval"+rdfsApproval = unode $ mkUri rdfs "approval" -- FIXME: incorrect namespace "rdfs:approval" in rdf-mt/manifest.ttl, must be "rdft:approval"+mfName = unode "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#name"+mfManifest = unode "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#Manifest"+mfAction = unode "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#action"+mfResult = unode "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#result"+mfEntries = unode "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#entries"+mfEntailmentRegime = unode "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#entailmentRegime"+mfRecognizedDatatypes = unode "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#recognizedDatatypes"+mfUnrecognizedDatatypes = unode "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#unrecognizedDatatypes"++-- | Load the manifest from the given file;+-- apply the given namespace as the base IRI of the manifest.+loadManifest :: T.Text -> T.Text -> IO Manifest+loadManifest manifestPath baseIRI = do+ parseFile testParser (T.unpack manifestPath) >>= return . rdfToManifest . fromEither+ where testParser = TurtleParser (Just $ BaseUrl baseIRI) Nothing++rdfToManifest :: TriplesGraph -> Manifest+rdfToManifest rdf = Manifest desc tpls+ where desc = lnodeText $ objectOf $ headDef (error ("query empty: subject mf:node & predicate mf:name in:\n\n" ++ show (triplesOf rdf))) descNode+ -- FIXME: Inconsistent use of nodes for describing the manifest (W3C bug)+ descNode = query rdf (Just manifestNode) (Just rdfsComment) Nothing+ ++ query rdf (Just manifestNode) (Just mfName) Nothing+-- descNode = query rdf (Just manifestNode) (Just mfName) Nothing+ tpls = map (rdfToTestEntry rdf) $ rdfCollectionToList rdf collectionHead+ collectionHead = objectOf $ headDef (error "query: mf:node & mf:entries") $ query rdf (Just manifestNode) (Just mfEntries) Nothing+ manifestNode = headDef (error "manifestSubjectNodes yielding empty list") $ manifestSubjectNodes rdf++rdfToTestEntry :: TriplesGraph -> Node -> TestEntry+rdfToTestEntry rdf teSubject = triplesToTestEntry rdf $ query rdf (Just teSubject) Nothing Nothing++triplesToTestEntry :: TriplesGraph -> Triples -> TestEntry+triplesToTestEntry rdf ts =+ case objectByPredicate rdfType ts of+ (UNode "http://www.w3.org/ns/rdftest#TestTurtleEval") -> mkTestTurtleEval ts+ (UNode "http://www.w3.org/ns/rdftest#TestTurtleNegativeEval") -> mkTestTurtleNegativeEval ts+ (UNode "http://www.w3.org/ns/rdftest#TestTurtlePositiveSyntax") -> mkTestTurtlePositiveSyntax ts+ (UNode "http://www.w3.org/ns/rdftest#TestTurtleNegativeSyntax") -> mkTestTurtleNegativeSyntax ts+ (UNode "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#PositiveEntailmentTest") -> mkPositiveEntailmentTest ts rdf+ (UNode "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#NegativeEntailmentTest") -> mkNegativeEntailmentTest ts rdf+ (UNode "http://www.w3.org/ns/rdftest#TestXMLEval") -> mkTestXMLEval ts+ (UNode "http://www.w3.org/ns/rdftest#TestXMLNegativeSyntax") -> mkTestXMLNegativeSyntax ts+ (UNode "http://www.w3.org/ns/rdftest#TestNTriplesPositiveSyntax") -> mkTestNTriplesPositiveSyntax ts+ (UNode "http://www.w3.org/ns/rdftest#TestNTriplesNegativeSyntax") -> mkTestNTriplesNegativeSyntax ts+ n -> error ("Unknown test case: " ++ show n)++mkTestTurtleEval :: Triples -> TestEntry+mkTestTurtleEval ts = TestTurtleEval {+ name = lnodeText $ objectByPredicate mfName ts,+ comment = lnodeText $ objectByPredicate rdfsComment ts,+ approval = objectByPredicate rdftApproval ts,+ action = objectByPredicate mfAction ts,+ result = objectByPredicate mfResult ts+ }++mkTestTurtleNegativeEval :: Triples -> TestEntry+mkTestTurtleNegativeEval ts = TestTurtleNegativeEval {+ name = lnodeText $ objectByPredicate mfName ts,+ comment = lnodeText $ objectByPredicate rdfsComment ts,+ approval = objectByPredicate rdftApproval ts,+ action = objectByPredicate mfAction ts+ }++mkTestTurtlePositiveSyntax :: Triples -> TestEntry+mkTestTurtlePositiveSyntax ts = TestTurtlePositiveSyntax {+ name = lnodeText $ objectByPredicate mfName ts,+ comment = lnodeText $ objectByPredicate rdfsComment ts,+ approval = objectByPredicate rdftApproval ts,+ action = objectByPredicate mfAction ts+ }++mkTestTurtleNegativeSyntax :: Triples -> TestEntry+mkTestTurtleNegativeSyntax ts = TestTurtleNegativeSyntax {+ name = lnodeText $ objectByPredicate mfName ts,+ comment = lnodeText $ objectByPredicate rdfsComment ts,+ approval = objectByPredicate rdftApproval ts,+ action = objectByPredicate mfAction ts+ }++mkPositiveEntailmentTest :: Triples -> TriplesGraph -> TestEntry+mkPositiveEntailmentTest ts rdf = PositiveEntailmentTest {+ name = lnodeText $ objectByPredicate mfName ts,+ comment = lnodeText $ objectByPredicate rdfsComment ts,+ -- FIXME: incorrect namespace "rdfs:approval" in rdf-mt/manifest.ttl+ -- approval = objectByPredicate rdftApproval ts,+ approval = objectByPredicate rdfsApproval ts,+ action = objectByPredicate mfAction ts,+ result = objectByPredicate mfResult ts,+ entailmentRegime = lnodeText $ objectByPredicate mfEntailmentRegime ts,+ recognizedDatatypes = rDT,+ unrecognizedDatatypes = uDT+ }+ where rDT = rdfCollectionToList rdf rDTCollectionHead+ rDTCollectionHead = objectByPredicate mfRecognizedDatatypes ts+ uDT = rdfCollectionToList rdf uDTCollectionHead+ uDTCollectionHead = objectByPredicate mfUnrecognizedDatatypes ts++mkNegativeEntailmentTest :: Triples -> TriplesGraph -> TestEntry+mkNegativeEntailmentTest ts rdf = NegativeEntailmentTest {+ name = lnodeText $ objectByPredicate mfName ts,+ comment = lnodeText $ objectByPredicate rdfsComment ts,+ -- FIXME: incorrect namespace "rdfs:approval" in rdf-mt/manifest.ttl+ -- approval = objectByPredicate rdftApproval ts,+ approval = objectByPredicate rdfsApproval ts,+ action = objectByPredicate mfAction ts,+ result = objectByPredicate mfResult ts,+ entailmentRegime = lnodeText $ objectByPredicate mfEntailmentRegime ts,+ recognizedDatatypes = rDT,+ unrecognizedDatatypes = uDT+ }+ where rDT = rdfCollectionToList rdf rDTCollectionHead+ rDTCollectionHead = objectByPredicate mfRecognizedDatatypes ts+ uDT = rdfCollectionToList rdf uDTCollectionHead+ uDTCollectionHead = objectByPredicate mfUnrecognizedDatatypes ts++mkTestXMLEval :: Triples -> TestEntry+mkTestXMLEval ts = TestXMLEval {+ name = lnodeText $ objectByPredicate mfName ts,+ comment = lnodeText $ objectByPredicate rdfsComment ts,+ -- FIXME: incorrect namespace "rdfs:approval" in rdf-mt/manifest.ttl+ -- approval = objectByPredicate rdftApproval ts,+ approval = objectByPredicate rdfsApproval ts,+ action = objectByPredicate mfAction ts,+ result = objectByPredicate mfResult ts+ }++mkTestXMLNegativeSyntax :: Triples -> TestEntry+mkTestXMLNegativeSyntax ts = TestXMLNegativeSyntax {+ name = lnodeText $ objectByPredicate mfName ts,+ comment = lnodeText $ objectByPredicate rdfsComment ts,+ -- FIXME: incorrect namespace "rdfs:approval" in rdf-mt/manifest.ttl+ -- approval = objectByPredicate rdftApproval ts+ approval = objectByPredicate rdfsApproval ts,+ action = objectByPredicate mfAction ts+ }++mkTestNTriplesPositiveSyntax :: Triples -> TestEntry+mkTestNTriplesPositiveSyntax ts = TestNTriplesPositiveSyntax {+ name = lnodeText $ objectByPredicate mfName ts,+ comment = lnodeText $ objectByPredicate rdfsComment ts,+ approval = objectByPredicate rdftApproval ts,+ action = objectByPredicate mfAction ts+ }++mkTestNTriplesNegativeSyntax :: Triples -> TestEntry+mkTestNTriplesNegativeSyntax ts = TestNTriplesPositiveSyntax {+ name = lnodeText $ objectByPredicate mfName ts,+ comment = lnodeText $ objectByPredicate rdfsComment ts,+ approval = objectByPredicate rdftApproval ts,+ action = objectByPredicate mfAction ts+ }++-- Filter the triples by given predicate and return the object of the first found triple.+-- Raises an exception on errors.+objectByPredicate :: Predicate -> Triples -> Object+objectByPredicate p = objectOf . fromJust . L.find (\t -> predicateOf t == p)++manifestSubjectNodes :: TriplesGraph -> [Subject]+manifestSubjectNodes rdf = subjectNodes rdf [mfManifest]++subjectNodes :: TriplesGraph -> [Object] -> [Subject]+subjectNodes rdf = (map subjectOf) . concatMap queryType+ where queryType n = query rdf Nothing (Just rdfType) (Just n)++-- | Text of the literal node.+-- Note that it doesn't perform type conversion for TypedL.+-- TODO: Looks useful. Move it to RDF4H lib?+lnodeText :: Node -> T.Text+lnodeText (LNode(PlainL t)) = t+lnodeText (LNode(PlainLL t _)) = t+lnodeText (LNode(TypedL t _)) = t+lnodeText _ = error "Not a literal node"++-- | Convert an RDF collection to a List of its objects.+-- | Given a list of RDF triples as shown:+-- | <x> <collection> <c1>+-- | <c1> <rdf:first> <i1>+-- | <c1> <rdf:rest> <c2>+-- | <c2> <rdf:first> <i2>+-- | <c2> <rdf:rest> <rdf:nil>+-- | ... it extracts a list of nodes [i1, i2].+-- | First argument (`rdf`) is the RDF graph;+-- | second argument (`tip`) is the "collection head" (<c1> in the example above),+-- | (all triples with <rdf:first> and <rdf:rest> pairs).+-- TODO: Looks useful. Move it to RDF4H lib?+rdfCollectionToList :: TriplesGraph -> Node -> [Node]+rdfCollectionToList _ (UNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil")) = []+rdfCollectionToList rdf tip = concatMap (tripleToList rdf) $ nextCollectionTriples rdf tip++tripleToList :: TriplesGraph -> Triple -> [Node]+tripleToList _ (Triple _ (UNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#first")) n@(UNode _)) = [n]+tripleToList rdf (Triple _ (UNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest")) tip) = rdfCollectionToList rdf tip+tripleToList _ _ = error "Invalid collection format"++nextCollectionTriples :: TriplesGraph -> Node -> Triples+nextCollectionTriples rdf tip@(BNodeGen _) = query rdf (Just tip) Nothing Nothing+nextCollectionTriples _ _ = error "Invalid collection format"
+ testsuite/tests/W3C/NTripleTest.hs view
@@ -0,0 +1,58 @@+module W3C.NTripleTest where++import Data.Maybe (fromJust)+import Test.Framework.Providers.API+import Test.Framework.Providers.HUnit+import qualified Test.HUnit as TU+import qualified Data.Text as T+import System.Directory++import W3C.Manifest++import Data.RDF.Types+import Text.RDF.RDF4H.NTriplesParser+import Data.RDF.TriplesGraph++suiteFilesDir = "data/w3c/n3/"++mfPath = T.concat [suiteFilesDir, "manifest.ttl"]+mfBaseURI = BaseUrl "http://www.w3.org/2013/N-TriplesTests/"++tests :: [Test]+tests = [ buildTest allNTripleTests ]++allNTripleTests :: IO Test+allNTripleTests = do+ dir <- getCurrentDirectory+ let fileSchemeURI = T.pack ("file://" ++ dir ++ "/" ++ T.unpack suiteFilesDir)+ m <- loadManifest mfPath fileSchemeURI+ return $ testGroup (T.unpack $ description m) $ map (buildTest . mfEntryToTest) $ entries m++-- Functions to map manifest test entries to unit tests.+-- They are defined here to avoid cluttering W3C.Manifest+-- with functions that may not be needed to those who+-- just want to parse Manifest files.+-- TODO: They should probably be moved to W3C.Manifest after all.+mfEntryToTest :: TestEntry -> IO Test+mfEntryToTest (TestNTriplesPositiveSyntax nm _ _ act') = do+ let act = (UNode . fromJust . fileSchemeToFilePath) act'+ rdf <- parseFile testParser (nodeURI act) :: IO (Either ParseFailure TriplesGraph)+ return $ testCase (T.unpack nm) $ TU.assert $ isParsed rdf+mfEntryToTest (TestNTriplesNegativeSyntax nm _ _ act') = do+ let act = (UNode . fromJust . fileSchemeToFilePath) act'+ rdf <- parseFile testParser (nodeURI act) :: IO (Either ParseFailure TriplesGraph)+ return $ testCase (T.unpack nm) $ TU.assert $ isNotParsed rdf+mfEntryToTest x = error $ "unknown TestEntry pattern in mfEntryToTest: " ++ show x++isParsed :: Either a b -> Bool+isParsed (Left _) = False+isParsed (Right _) = True++isNotParsed :: Either a b -> Bool+isNotParsed = not . isParsed++nodeURI :: Node -> String+nodeURI = \(UNode u) -> T.unpack u++testParser :: NTriplesParser+testParser = NTriplesParser
+ testsuite/tests/W3C/RdfXmlTest.hs view
@@ -0,0 +1,62 @@+module W3C.RdfXmlTest where++import Data.Maybe (fromJust)+import Test.Framework.Providers.API+import Test.Framework.Providers.HUnit+import qualified Test.HUnit as TU+import qualified Data.Text as T+import System.Directory++import W3C.Manifest++import Data.RDF.Types+import Data.RDF.Query+import Text.RDF.RDF4H.XmlParser+import Text.RDF.RDF4H.NTriplesParser+import Data.RDF.TriplesGraph++suiteFilesDir = "data/w3c/rdf-xml/"++mfPath = T.concat [suiteFilesDir, "manifest.ttl"]+mfBaseURI = BaseUrl "http://www.w3.org/2013/RDFXMLTests/"++tests :: [Test]+tests = [ buildTest allRdfXmlTests ]++allRdfXmlTests :: IO Test+allRdfXmlTests = do+ dir <- getCurrentDirectory+ let fileSchemeURI = T.pack ("file://" ++ dir ++ "/" ++ T.unpack suiteFilesDir)+ m <- loadManifest mfPath fileSchemeURI+ return $ testGroup (T.unpack $ description m) $ map (buildTest . mfEntryToTest) $ entries m++-- Functions to map manifest test entries to unit tests.+-- They are defined here to avoid cluttering W3C.Manifest+-- with functions that may not be needed to those who+-- just want to parse Manifest files.+-- TODO: They should probably be moved to W3C.Manifest after all.+mfEntryToTest :: TestEntry -> IO Test+mfEntryToTest (TestXMLEval nm _ _ act' res') = do+ let act = (UNode . fromJust . fileSchemeToFilePath) act'+ let res = (UNode . fromJust . fileSchemeToFilePath) res'+ parsedRDF <- parseFile testParser (nodeURI act) >>= return . fromEither :: IO TriplesGraph+ expectedRDF <- parseFile NTriplesParser (nodeURI res) >>= return . fromEither :: IO TriplesGraph+ return $ testCase (T.unpack nm) $ TU.assert $ isIsomorphic parsedRDF expectedRDF+mfEntryToTest (TestXMLNegativeSyntax nm _ _ act') = do+ let act = (UNode . fromJust . fileSchemeToFilePath) act'+ rdf <- parseFile testParser (nodeURI act) :: IO (Either ParseFailure TriplesGraph)+ return $ testCase (T.unpack nm) $ TU.assert $ isNotParsed rdf+mfEntryToTest x = error $ "unknown TestEntry pattern in mfEntryToTest: " ++ show x++isParsed :: Either a b -> Bool+isParsed (Left _) = False+isParsed (Right _) = True++isNotParsed :: Either a b -> Bool+isNotParsed = not . isParsed++nodeURI :: Node -> String+nodeURI = \(UNode u) -> T.unpack u++testParser :: XmlParser+testParser = XmlParser (Just mfBaseURI) Nothing