<commit_before>module GraphTestUtils where

import RDF
import Namespace

import Data.Char
import Data.List
import qualified Data.Set.AVL as S
import Control.Monad
import System.Random
import Test.QuickCheck
import Foreign(unsafePerformIO)

-- Test stubs, which just require the appropriate graph impl function
-- passed in to determine the graph implementation to be tested.

-- empty graph should have no triples
p_empty :: Graph g => (g -> Triples) -> g -> Bool
p_empty _triplesOf _empty = _triplesOf _empty == []


-- triplesOf any graph should return unique triples used to create it
p_mkGraph_triplesOf :: Graph g => (g -> Triples) -> (Triples -> g) -> Triples -> Bool
p_mkGraph_triplesOf _triplesOf _mkGraph ts = 
  ordered (_triplesOf (_mkGraph ts)) == uordered ts

-- duplicate input triples should not be returned
p_mkGraph_no_dupes :: Graph g => (g -> Triples) -> (Triples -> g) -> Triples -> Bool
p_mkGraph_no_dupes _triplesOf _mkGraph ts = 
  case null ts of
    True  -> True
    False -> ordered result == uordered ts
  where 
    tsWithDupe = head ts : ts
    result = _triplesOf $ _mkGraph tsWithDupe

-- query with all 3 wildcards should yield all triples in graph
p_query_all_wildcard :: Graph g => (Triples -> g) -> Triples -> Bool
p_query_all_wildcard  _mkGraph ts = uordered ts == ordered result
  where 
    result = query (_mkGraph ts) Nothing Nothing Nothing

-- query with no wildcard and a triple in the graph should yield
-- a singleton list with just the triple.
p_query_matched_no_wildcards :: Graph g => (g -> Triples) -> g -> Property
p_query_matched_no_wildcards _triplesOf gr = 
  classify (null ts) "trivial" $ 
    forAll (tripleFromGen _triplesOf gr) f
  where 
    ts = _triplesOf gr
    f t = case t of 
            Nothing   ->  True
            (Just t') ->  [t'] == queryT gr t'

-- query with no wildcard and a triple no in the graph should yield []
p_query_unmatched_no_wildcards :: Graph g => (g -> Triples) -> g -> Triple -> Property
p_query_unmatched_no_wildcards _triplesOf gr t = 
  classify (t `elem` ts) "ignored" $
    not (t `elem` ts) ==> [] == queryT gr t
  where 
    ts = _triplesOf gr

-- query with fixed subject and wildcards for pred and obj should yield
-- a list with all triples having subject, and graph minus result triples
-- should yield all triple with unequal subjects.
p_query_matched_po_wildcards :: Graph g => (g -> Triples) -> g -> Property
p_query_matched_po_wildcards _triplesOf gr =
  forAll (tripleFromGen _triplesOf gr) f
  where
    f :: Maybe Triple -> Bool
    f Nothing   = True
    f (Just t)  =
      let 
        all_ts = _triplesOf gr
        all_ts_sorted = ordered all_ts
        results = ordered (query gr (Just $ subjectOf t) Nothing Nothing)
        notResults = ldiff all_ts_sorted results        
      in
        all (sameSubj t) results &&
        all (not . sameSubj t) notResults

-- Utility functions and test data ... --

debug :: String -> Triples -> Bool
debug msg ts = unsafePerformIO $ 
                 putStrLn msg >> mapM (putStrLn . show) ts >> return True

ldiff :: Triples -> Triples -> Triples
ldiff l1 l2 = S.toList $(S.fromList l1) `S.difference` (S.fromList l2)

sameSubj t1 t2 = subjectOf t1 == subjectOf t2
samePred t1 t2 = predicateOf t1 == predicateOf t2
sameObj  t1 t2 = objectOf t1 == objectOf t2

tripleFromGen :: Graph g => (g -> Triples) -> g -> Gen (Maybe Triple)
tripleFromGen _triplesOf gr = 
  case null ts of
    True  -> return Nothing
    False -> oneof $ map (return . Just) ts
  where ts = _triplesOf gr

queryT :: Graph g => g -> Triple -> Triples
queryT gr t = query gr (Just $ subjectOf t) (Just $ predicateOf t) (Just $ objectOf t)


languages = [Nothing, Just "fr", Just "en"]
datatypes = [makeUri xsd "string", makeUri xsd "int", makeUri xsd "token"]
uris = map (makeUri ex) [n ++ show i | n <- ["foo", "bar", "quz", "zak"], i <- [0..9]]
plainliterals = [PlainL lit lang | lit <- litvalues, lang <- languages]
typedliterals = [TypedL lit dtype | lit <- litvalues, dtype <- datatypes]<commit_msg>GraphtTestUtils.hs: added more tests.<commit_after>module GraphTestUtils where

import RDF
import Namespace

import Data.Char
import Data.List
import qualified Data.Set.AVL as S
import Control.Monad
import System.Random
import Test.QuickCheck
import Foreign(unsafePerformIO)

-- Test stubs, which just require the appropriate graph impl function
-- passed in to determine the graph implementation to be tested.

-- empty graph should have no triples
p_empty :: Graph g => (g -> Triples) -> g -> Bool
p_empty _triplesOf _empty = _triplesOf _empty == []


-- triplesOf any graph should return unique triples used to create it
p_mkGraph_triplesOf :: Graph g => (g -> Triples) -> (Triples -> g) -> Triples -> Bool
p_mkGraph_triplesOf _triplesOf _mkGraph ts = 
  ordered (_triplesOf (_mkGraph ts)) == uordered ts

-- duplicate input triples should not be returned
p_mkGraph_no_dupes :: Graph g => (g -> Triples) -> (Triples -> g) -> Triples -> Bool
p_mkGraph_no_dupes _triplesOf _mkGraph ts = 
  case null ts of
    True  -> True
    False -> ordered result == uordered ts
  where 
    tsWithDupe = head ts : ts
    result = _triplesOf $ _mkGraph tsWithDupe

-- query with all 3 wildcards should yield all triples in graph
p_query_all_wildcard :: Graph g => (Triples -> g) -> Triples -> Bool
p_query_all_wildcard  _mkGraph ts = uordered ts == ordered result
  where 
    result = query (_mkGraph ts) Nothing Nothing Nothing

-- query with no wildcard and a triple in the graph should yield
-- a singleton list with just the triple.
p_query_matched_spo :: Graph g => (g -> Triples) -> g -> Property
p_query_matched_spo _triplesOf gr = 
  classify (null ts) "trivial" $ 
    forAll (tripleFromGen _triplesOf gr) f
  where 
    ts = _triplesOf gr
    f t = case t of 
            Nothing   ->  True
            (Just t') ->  [t'] == queryT gr t'

-- query with no wildcard and a triple no in the graph should yield []
p_query_unmatched_spo :: Graph g => (g -> Triples) -> g -> Triple -> Property
p_query_unmatched_spo _triplesOf gr t = 
  classify (t `elem` ts) "ignored" $
    not (t `elem` ts) ==> [] == queryT gr t
  where 
    ts = _triplesOf gr

-- query with fixed subject and wildcards for pred and obj should yield
-- a list with all triples having subject, and graph minus result triples
-- should yield all triple with unequal subjects.
p_query_match_s :: Graph g => (g -> Triples) -> g -> 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 graph minus result triples
-- should yield all triple with unequal predicates.
p_query_match_p :: Graph g => (g -> Triples) -> g -> 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 :: Graph g => (g -> Triples) -> g -> 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 :: Graph g => (g -> Triples) -> g -> 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 :: Graph g => (g -> Triples) -> g -> 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 :: Graph g => (g -> Triples) -> g -> 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 :: Graph g => (Triple -> Triple -> Bool)
  -> (Triple -> (Maybe Node, Maybe Node, Maybe Node))
  -> (g -> Triples) -> g -> Property
mk_query_match_fn tripleCompareFn  mkPatternFn _triplesOf gr =
  forAll (tripleFromGen _triplesOf gr) f
  where
    f :: Maybe Triple -> Bool
    f Nothing   = True
    f (Just t)  =
      let 
        all_ts = _triplesOf gr
        all_ts_sorted = ordered all_ts
        results = ordered $ queryC gr (mkPatternFn t)
        notResults = ldiff all_ts_sorted results        
      in
        all (tripleCompareFn t) results &&
        all (not . tripleCompareFn t) notResults
 
-- Utility functions and test data ... --

-- a curried version of query that delegates to the actual query after unpacking
-- curried maybe node pattern.
queryC :: Graph g => g -> (Maybe Node, Maybe Node, Maybe Node) -> Triples
queryC gr (s, p, o) = query gr 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 (putStrLn . show) ts >> return True

ldiff :: Triples -> Triples -> Triples
ldiff l1 l2 = S.toList $(S.fromList l1) `S.difference` (S.fromList l2)

sameSubj t1 t2 = subjectOf t1 == subjectOf t2
samePred t1 t2 = predicateOf t1 == predicateOf t2
sameObj  t1 t2 = objectOf t1 == objectOf t2

tripleFromGen :: Graph g => (g -> Triples) -> g -> Gen (Maybe Triple)
tripleFromGen _triplesOf gr = 
  case null ts of
    True  -> return Nothing
    False -> oneof $ map (return . Just) ts
  where ts = _triplesOf gr

queryT :: Graph g => g -> Triple -> Triples
queryT gr t = query gr (Just $ subjectOf t) (Just $ predicateOf t) (Just $ objectOf t)


languages = [Nothing, Just "fr", Just "en"]
datatypes = [makeUri xsd "string", makeUri xsd "int", makeUri xsd "token"]
uris = map (makeUri ex) [n ++ show i | n <- ["foo", "bar", "quz", "zak"], i <- [0..9]]
plainliterals = [PlainL lit lang | lit <- litvalues, lang <- languages]
typedliterals = [TypedL lit dtype | lit <- litvalues, dtype <- datatypes]
{'fraction_non_alphanumeric': 0.10305118110236221, 'fraction_numerical': 0.005905511811023622, 'mean_word_length': 3.113765182186235, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 161, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4846386', 'n_tokens_mistral': 3373, 'n_tokens_neox': 3270, 'n_words': 1288}