diff options
author | Natanael Arndt <arndtn@gmail.com> | 2020-05-02 00:26:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-02 00:26:19 +0200 |
commit | 7c28713fad45d9e0403304c12a0928704e5f063b (patch) | |
tree | 3bfc3a6c383d98fba1dc6b2806380aa1b1eb7d29 /test | |
parent | 88ba5748e502792899b7763276dc3cab7b0b68cb (diff) | |
parent | 827eabd437e0a0b4404559b6acacdf696f700593 (diff) | |
download | rdflib-7c28713fad45d9e0403304c12a0928704e5f063b.tar.gz |
Merge branch 'master' into 357-batch-add-graph
Diffstat (limited to 'test')
-rw-r--r-- | test/test_hex_binary.py | 62 | ||||
-rw-r--r-- | test/test_issue1003.py | 117 | ||||
-rw-r--r-- | test/test_literal.py | 51 | ||||
-rw-r--r-- | test/test_n3.py | 47 | ||||
-rw-r--r-- | test/test_sparql_construct_bindings.py | 40 | ||||
-rw-r--r-- | test/test_sparqlstore.py | 78 | ||||
-rw-r--r-- | test/test_term.py | 81 |
7 files changed, 472 insertions, 4 deletions
diff --git a/test/test_hex_binary.py b/test/test_hex_binary.py new file mode 100644 index 00000000..419a47e2 --- /dev/null +++ b/test/test_hex_binary.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +import unittest +import binascii +from rdflib import Literal, XSD +import six + + +class HexBinaryTestCase(unittest.TestCase): + + def test_int(self): + self._test_integer(5) + self._test_integer(3452) + self._test_integer(4886) + + def _test_integer(self, i): + hex_i = format(i, "x") + # Make it has a even-length (Byte) + len_hex_i = len(hex_i) + hex_i = hex_i.zfill(len_hex_i + len_hex_i % 2) + + l = Literal(hex_i, datatype=XSD.hexBinary) + bin_i = l.toPython() + self.assertEquals(int(binascii.hexlify(bin_i), 16), i) + + if six.PY2: + self.assertEquals(unicode(l), hex_i) + else: + self.assertEquals(str(l), hex_i) + self.assertEquals(int(hex_i, 16), i) + if six.PY2: + self.assertEquals(int(unicode(l), 16), i) + else: + self.assertEquals(int(l, 16), i) + self.assertEquals(int(str(l), 16), i) + + def test_unicode(self): + str1 = u"Test utf-8 string éàë" + # u hexstring + hex_str1 = binascii.hexlify(str1.encode('utf-8')).decode() + l1 = Literal(hex_str1, datatype=XSD.hexBinary) + b_str1 = l1.toPython() + self.assertEquals(b_str1.decode('utf-8'), str1) + if six.PY2: + self.assertEquals(unicode(l1), hex_str1) + else: + self.assertEquals(str(l1), hex_str1) + + # b hexstring + hex_str1b = binascii.hexlify(str1.encode('utf-8')) + l1b = Literal(hex_str1b, datatype=XSD.hexBinary) + b_str1b = l1b.toPython() + self.assertEquals(b_str1, b_str1b) + self.assertEquals(b_str1b.decode('utf-8'), str1) + if six.PY2: + self.assertEquals(unicode(l1b), hex_str1) + else: + self.assertEquals(str(l1b), hex_str1) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_issue1003.py b/test/test_issue1003.py new file mode 100644 index 00000000..fdc56c82 --- /dev/null +++ b/test/test_issue1003.py @@ -0,0 +1,117 @@ +from rdflib import Graph, Dataset, Literal, Namespace, RDF, URIRef +from rdflib.namespace import SKOS, DCTERMS + +""" +Testing scenarios: + 1. no base set + 2. base set at graph creation + 3. base set at serialization + 4. base set at both graph creation & serialization, serialization overrides + 5. multiple serialization side effect checking + 6. checking results for RDF/XML + 7. checking results for N3 + 8. checking results for TriX & TriG +""" + +# variables +base_one = Namespace("http://one.org/") +base_two = Namespace("http://two.org/") +title = Literal("Title", lang="en") +description = Literal("Test Description", lang="en") +creator = URIRef("https://creator.com") +cs = URIRef("") + +# starting graph +g = Graph() +g.add((cs, RDF.type, SKOS.ConceptScheme)) +g.add((cs, DCTERMS.creator, creator)) +g.add((cs, DCTERMS.source, URIRef("nick"))) +g.bind("dct", DCTERMS) +g.bind("skos", SKOS) + + +# 1. no base set for graph, no base set for serialization +g1 = Graph() +g1 += g +# @base should not be in output +assert "@base" not in g.serialize(format='turtle').decode("utf-8") + + +# 2. base one set for graph, no base set for serialization +g2 = Graph(base=base_one) +g2 += g +# @base should be in output, from Graph (one) +assert "@base <http://one.org/> ." in g2.serialize(format='turtle').decode("utf-8") + + +# 3. no base set for graph, base two set for serialization +g3 = Graph() +g3 += g +# @base should be in output, from serialization (two) +assert "@base <http://two.org/> ." in g3.serialize(format='turtle', base=base_two).decode("utf-8") + + +# 4. base one set for graph, base two set for serialization, Graph one overrides +g4 = Graph(base=base_one) +g4 += g +# @base should be in output, from graph (one) +assert "@base <http://two.org/> ." in g4.serialize(format='turtle', base=base_two).decode("utf-8") +# just checking that the serialization setting (two) hasn't snuck through +assert "@base <http://one.org/> ." not in g4.serialize(format='turtle', base=base_two).decode("utf-8") + + +# 5. multiple serialization side effect checking +g5 = Graph() +g5 += g +# @base should be in output, from serialization (two) +assert "@base <http://two.org/> ." in g5.serialize(format='turtle', base=base_two).decode("utf-8") + +# checking for side affects - no base now set for this serialization +# @base should not be in output +assert "@base" not in g5.serialize(format='turtle').decode("utf-8") + + +# 6. checking results for RDF/XML +g6 = Graph() +g6 += g +g6.bind("dct", DCTERMS) +g6.bind("skos", SKOS) +assert "@xml:base" not in g6.serialize(format='xml').decode("utf-8") +assert 'xml:base="http://one.org/"' in g6.serialize(format='xml', base=base_one).decode("utf-8") +g6.base = base_two +assert 'xml:base="http://two.org/"' in g6.serialize(format='xml').decode("utf-8") +assert 'xml:base="http://one.org/"' in g6.serialize(format='xml', base=base_one).decode("utf-8") + +# 7. checking results for N3 +g7 = Graph() +g7 += g +g7.bind("dct", DCTERMS) +g7.bind("skos", SKOS) +assert "@xml:base" not in g7.serialize(format='xml').decode("utf-8") +assert "@base <http://one.org/> ." in g7.serialize(format='n3', base=base_one).decode("utf-8") +g7.base = base_two +assert "@base <http://two.org/> ." in g7.serialize(format='n3').decode("utf-8") +assert "@base <http://one.org/> ." in g7.serialize(format='n3', base=base_one).decode("utf-8") + +# 8. checking results for TriX & TriG +# TriX can specify a base per graph but setting a base for the whole +base_three = Namespace("http://three.org/") +ds1 = Dataset() +ds1.bind("dct", DCTERMS) +ds1.bind("skos", SKOS) +g8 = ds1.graph(URIRef('http://g8.com/'), base=base_one) +g9 = ds1.graph(URIRef('http://g9.com/')) +g8 += g +g9 += g +g9.base = base_two +ds1.base = base_three + +trix = ds1.serialize(format='trix', base=Namespace("http://two.org/")).decode("utf-8") +assert '<graph xml:base="http://one.org/">' in trix +assert '<graph xml:base="http://two.org/">' in trix +assert '<TriX xml:base="http://two.org/"' in trix + +trig = ds1.serialize(format='trig', base=Namespace("http://two.org/")).decode("utf-8") +assert '@base <http://one.org/> .' not in trig +assert '@base <http://three.org/> .' not in trig +assert '@base <http://two.org/> .' in trig diff --git a/test/test_literal.py b/test/test_literal.py index feb9d72d..3ed62d11 100644 --- a/test/test_literal.py +++ b/test/test_literal.py @@ -1,8 +1,8 @@ import unittest import rdflib # needed for eval(repr(...)) below -from rdflib.term import Literal, URIRef, _XSD_DOUBLE, bind -from six import integer_types, PY3 +from rdflib.term import Literal, URIRef, _XSD_DOUBLE, bind, _XSD_BOOLEAN +from six import integer_types, PY3, string_types def uformat(s): @@ -100,6 +100,29 @@ class TestDoubleOutput(unittest.TestCase): out = vv._literal_n3(use_plain=True) self.assertTrue(out in ["8.8e-01", "0.88"], out) +class TestParseBoolean(unittest.TestCase): + """confirms the fix for https://github.com/RDFLib/rdflib/issues/913""" + def testTrueBoolean(self): + test_value = Literal("tRue", datatype = _XSD_BOOLEAN) + self.assertTrue(test_value.value) + test_value = Literal("1",datatype = _XSD_BOOLEAN) + self.assertTrue(test_value.value) + + def testFalseBoolean(self): + test_value = Literal("falsE", datatype = _XSD_BOOLEAN) + self.assertFalse(test_value.value) + test_value = Literal("0",datatype = _XSD_BOOLEAN) + self.assertFalse(test_value.value) + + def testNonFalseBoolean(self): + test_value = Literal("abcd", datatype = _XSD_BOOLEAN) + self.assertRaises(DeprecationWarning) + self.assertFalse(test_value.value) + test_value = Literal("10",datatype = _XSD_BOOLEAN) + self.assertRaises(DeprecationWarning) + self.assertFalse(test_value.value) + + class TestBindings(unittest.TestCase): @@ -139,6 +162,30 @@ class TestBindings(unittest.TestCase): self.assertEqual(lb.value, vb) self.assertEqual(lb.datatype, dtB) + def testSpecificBinding(self): + + def lexify(s): + return "--%s--" % s + + def unlexify(s): + return s[2:-2] + + datatype = rdflib.URIRef('urn:dt:mystring') + + #Datatype-specific rule + bind(datatype, string_types, unlexify, lexify, datatype_specific=True) + + s = "Hello" + normal_l = Literal(s) + self.assertEqual(str(normal_l), s) + self.assertEqual(normal_l.toPython(), s) + self.assertEqual(normal_l.datatype, None) + + specific_l = Literal("--%s--" % s, datatype=datatype) + self.assertEqual(str(specific_l), lexify(s)) + self.assertEqual(specific_l.toPython(), s) + self.assertEqual(specific_l.datatype, datatype) + if __name__ == "__main__": unittest.main() diff --git a/test/test_n3.py b/test/test_n3.py index 5d447732..5cdc74b5 100644 --- a/test/test_n3.py +++ b/test/test_n3.py @@ -1,7 +1,8 @@ from rdflib.graph import Graph, ConjunctiveGraph import unittest from rdflib.term import Literal, URIRef -from rdflib.plugins.parsers.notation3 import BadSyntax +from rdflib.plugins.parsers.notation3 import BadSyntax, exponent_syntax +import itertools from six import b from six.moves.urllib.error import URLError @@ -164,6 +165,31 @@ foo-bar:Ex foo-bar:name "Test" . """ g = Graph() g.parse("test/n3/issue156.n3", format="n3") + def testIssue999(self): + """ + Make sure the n3 parser does recognize exponent and leading dot in ".171e-11" + """ + data = """ +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . + +<http://qudt.org/vocab/unit/MilliM-PER-YR> + a <http://qudt.org/schema/qudt/Unit> ; + <http://qudt.org/schema/qudt/conversionMultiplier> .171e-11 ; + <http://qudt.org/schema/qudt/conversionOffset> 0e+00 ; + <http://qudt.org/schema/qudt/description> "0.001-fold of the SI base unit metre divided by the unit year" ; + <http://qudt.org/schema/qudt/hasQuantityKind> <http://qudt.org/vocab/quantitykind/Velocity> ; + <http://qudt.org/schema/qudt/iec61360Code> "0112/2///62720#UAA868" ; + <http://qudt.org/schema/qudt/uneceCommonCode> "H66" ; + rdfs:isDefinedBy <http://qudt.org/2.1/vocab/unit> ; + rdfs:isDefinedBy <http://qudt.org/vocab/unit> ; + rdfs:label "MilliM PER YR" ; + <http://www.w3.org/2004/02/skos/core#prefLabel> "millimetre per year" ; +. + """ + g = Graph() + g.parse(data=data, format="n3") + g.parse(data=data, format="turtle") + def testDotInPrefix(self): g = Graph() g.parse( @@ -226,5 +252,24 @@ foo-bar:Ex foo-bar:name "Test" . """ g2), 'Document with declared empty prefix must match default #' +class TestRegularExpressions(unittest.TestCase): + def testExponents(self): + signs = ("", "+", "-") + mantissas = ("1", "1.", ".1", + "12", "12.", "1.2", ".12", + "123", "123.", "12.3", "1.23", ".123") + es = "eE" + exps = ("1", "12", "+1", "-1", "+12", "-12") + for parts in itertools.product(signs, mantissas, es, exps): + expstring = "".join(parts) + self.assertTrue(exponent_syntax.match(expstring)) + + def testInvalidExponents(self): + # Add test cases as needed + invalid = (".e1",) + for expstring in invalid: + self.assertFalse(exponent_syntax.match(expstring)) + + if __name__ == '__main__': unittest.main() diff --git a/test/test_sparql_construct_bindings.py b/test/test_sparql_construct_bindings.py new file mode 100644 index 00000000..d5a68b94 --- /dev/null +++ b/test/test_sparql_construct_bindings.py @@ -0,0 +1,40 @@ +from rdflib import Graph, URIRef, Literal, BNode +from rdflib.plugins.sparql import prepareQuery +from rdflib.compare import isomorphic + +import unittest +from nose.tools import eq_ + +class TestConstructInitBindings(unittest.TestCase): + + def test_construct_init_bindings(self): + """ + This is issue https://github.com/RDFLib/rdflib/issues/1001 + """ + + g1 = Graph() + + q_str = (""" + PREFIX : <urn:ns1:> + CONSTRUCT { + ?uri :prop1 ?val1; + :prop2 ?c . + } + WHERE { + bind(uri(concat("urn:ns1:", ?a)) as ?uri) + bind(?b as ?val1) + } + """) + q_prepared = prepareQuery(q_str) + + expected = [ + (URIRef('urn:ns1:A'),URIRef('urn:ns1:prop1'), Literal('B')), + (URIRef('urn:ns1:A'),URIRef('urn:ns1:prop2'), Literal('C')) + ] + results = g1.query(q_prepared, initBindings={ + 'a': Literal('A'), + 'b': Literal('B'), + 'c': Literal('C') + }) + + eq_(sorted(results, key=lambda x: str(x[1])), expected) diff --git a/test/test_sparqlstore.py b/test/test_sparqlstore.py index 26a69460..a0a93b57 100644 --- a/test/test_sparqlstore.py +++ b/test/test_sparqlstore.py @@ -4,7 +4,10 @@ import os import unittest from nose import SkipTest from requests import HTTPError - +from http.server import BaseHTTPRequestHandler, HTTPServer +import socket +from threading import Thread +import requests try: assert len(urlopen("http://dbpedia.org/sparql").read()) > 0 @@ -67,5 +70,78 @@ class SPARQLStoreDBPediaTestCase(unittest.TestCase): assert type(i[0]) == Literal, i[0].n3() +class SPARQLStoreUpdateTestCase(unittest.TestCase): + def setUp(self): + port = self.setup_mocked_endpoint() + self.graph = Graph(store="SPARQLUpdateStore", identifier=URIRef("urn:ex")) + self.graph.open(("http://localhost:{port}/query".format(port=port), + "http://localhost:{port}/update".format(port=port)), create=False) + ns = list(self.graph.namespaces()) + assert len(ns) > 0, ns + + def setup_mocked_endpoint(self): + # Configure mock server. + s = socket.socket(socket.AF_INET, type=socket.SOCK_STREAM) + s.bind(('localhost', 0)) + address, port = s.getsockname() + s.close() + mock_server = HTTPServer(('localhost', port), SPARQL11ProtocolStoreMock) + + # Start running mock server in a separate thread. + # Daemon threads automatically shut down when the main process exits. + mock_server_thread = Thread(target=mock_server.serve_forever) + mock_server_thread.setDaemon(True) + mock_server_thread.start() + print("Started mocked sparql endpoint on http://localhost:{port}/".format(port=port)) + return port + + def tearDown(self): + self.graph.close() + + def test_Query(self): + query = "insert data {<urn:s> <urn:p> <urn:o>}" + res = self.graph.update(query) + print(res) + + +class SPARQL11ProtocolStoreMock(BaseHTTPRequestHandler): + def do_POST(self): + """ + If the body should be analysed as well, just use: + ``` + body = self.rfile.read(int(self.headers['Content-Length'])).decode() + print(body) + ``` + """ + contenttype = self.headers.get("Content-Type") + if self.path == "/query": + if self.headers.get("Content-Type") == "application/sparql-query": + pass + elif self.headers.get("Content-Type") == "application/x-www-form-urlencoded": + pass + else: + self.send_response(requests.codes.not_acceptable) + self.end_headers() + elif self.path == "/update": + if self.headers.get("Content-Type") == "application/sparql-update": + pass + elif self.headers.get("Content-Type") == "application/x-www-form-urlencoded": + pass + else: + self.send_response(requests.codes.not_acceptable) + self.end_headers() + else: + self.send_response(requests.codes.not_found) + self.end_headers() + self.send_response(requests.codes.ok) + self.end_headers() + return + + def do_GET(self): + # Process an HTTP GET request and return a response with an HTTP 200 status. + self.send_response(requests.codes.ok) + self.end_headers() + return + if __name__ == '__main__': unittest.main() diff --git a/test/test_term.py b/test/test_term.py index c222a8d2..4dea9c3c 100644 --- a/test/test_term.py +++ b/test/test_term.py @@ -123,6 +123,87 @@ class TestLiteral(unittest.TestCase): random.shuffle(l2) self.assertListEqual(l1, sorted(l2)) + def test_literal_add(self): + from decimal import Decimal + + # compares Python decimals + def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): + a = float(a) + b = float(b) + return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) + + cases = [ + (1, Literal(1), Literal(1), Literal(2)), + (2, Literal(Decimal(1)), Literal(Decimal(1)), Literal(Decimal(2))), + (3, Literal(float(1)), Literal(float(1)), Literal(float(2))), + (4, Literal(1), Literal(1.1), Literal(2.1, datatype=XSD.decimal)), + (5, Literal(1.1), Literal(1.1), Literal(2.2)), + (6, Literal(Decimal(1)), Literal(Decimal(1.1)), Literal(Decimal(2.1), datatype=XSD.decimal)), + (7, Literal(Decimal(1.1)), Literal(Decimal(1.1)), Literal(Decimal(2.2))), + (8, Literal(float(1)), Literal(float(1.1)), Literal(float(2.1))), + (9, Literal(float(1.1)), Literal(float(1.1)), Literal(float(2.2))), + (10, Literal(-1), Literal(-1), Literal(-2)), + (12, Literal(Decimal(-1)), Literal(Decimal(-1)), Literal(Decimal(-2))), + (13, Literal(float(-1)), Literal(float(-1)), Literal(float(-2))), + (14, Literal(-1), Literal(-1.1), Literal(-2.1)), + (15, Literal(-1.1), Literal(-1.1), Literal(-2.2)), + (16, Literal(Decimal(-1)), Literal(Decimal(-1.1)), Literal(Decimal(-2.1))), + (17, Literal(Decimal(-1.1)), Literal(Decimal(-1.1)), Literal(Decimal(-2.2))), + (18, Literal(float(-1)), Literal(float(-1.1)), Literal(float(-2.1))), + (19, Literal(float(-1.1)), Literal(float(-1.1)), Literal(float(-2.2))), + + (20, Literal(1), Literal(1.0), Literal(2.0)), + (21, Literal(1.0), Literal(1.0), Literal(2.0)), + (22, Literal(Decimal(1)), Literal(Decimal(1.0)), Literal(Decimal(2.0))), + (23, Literal(Decimal(1.0)), Literal(Decimal(1.0)), Literal(Decimal(2.0))), + (24, Literal(float(1)), Literal(float(1.0)), Literal(float(2.0))), + (25, Literal(float(1.0)), Literal(float(1.0)), Literal(float(2.0))), + + (26, Literal(1, datatype=XSD.integer), Literal(1, datatype=XSD.integer), Literal(2, datatype=XSD.integer)), + (27, Literal(1, datatype=XSD.integer), Literal("1", datatype=XSD.integer), Literal("2", datatype=XSD.integer)), + (28, Literal("1", datatype=XSD.integer), Literal("1", datatype=XSD.integer), Literal("2", datatype=XSD.integer)), + (29, Literal("1"), Literal("1", datatype=XSD.integer), Literal("11", datatype=XSD.string)), + (30, Literal(1), Literal("1", datatype=XSD.integer), Literal("2", datatype=XSD.integer)), + (31, Literal(Decimal(1), datatype=XSD.decimal), Literal(Decimal(1), datatype=XSD.decimal), Literal(Decimal(2), datatype=XSD.decimal)), + (32, Literal(Decimal(1)), Literal(Decimal(1), datatype=XSD.decimal), Literal(Decimal(2), datatype=XSD.decimal)), + (33, Literal(float(1)), Literal(float(1), datatype=XSD.float), Literal(float(2), datatype=XSD.float)), + (34, Literal(float(1), datatype=XSD.float), Literal(float(1), datatype=XSD.float), Literal(float(2), datatype=XSD.float)), + + (35, Literal(1), 1, Literal(2)), + (36, Literal(1), 1.0, Literal(2, datatype=XSD.decimal)), + (37, Literal(1.0), 1, Literal(2, datatype=XSD.decimal)), + (38, Literal(1.0), 1.0, Literal(2.0)), + (39, Literal(Decimal(1.0)), Decimal(1), Literal(Decimal(2.0))), + (40, Literal(Decimal(1.0)), Decimal(1.0), Literal(Decimal(2.0))), + (41, Literal(float(1.0)), float(1), Literal(float(2.0))), + (42, Literal(float(1.0)), float(1.0), Literal(float(2.0))), + + (43, Literal(1, datatype=XSD.integer), "+1.1", Literal("1+1.1", datatype=XSD.string)), + (44, Literal(1, datatype=XSD.integer), Literal("+1.1", datatype=XSD.string), Literal("1+1.1", datatype=XSD.string)), + (45, Literal(Decimal(1.0), datatype=XSD.integer), Literal(u"1", datatype=XSD.string), Literal("11", datatype=XSD.string)), + (46, Literal(1.1, datatype=XSD.integer), Literal("1", datatype=XSD.string), Literal("1.11", datatype=XSD.string)), + + (47, Literal(1, datatype=XSD.integer), None, Literal(1, datatype=XSD.integer)), + (48, Literal("1", datatype=XSD.string), None, Literal("1", datatype=XSD.string)), + ] + + for case in cases: + # see if the addition exactly matches the expected output + case_passed = (case[1] + case[2]) == (case[3]) + # see if the addition almost matches the expected output, for decimal precision errors + if not case_passed: + try: + case_passed = isclose((case[1] + case[2].value), case[3].value) + except: + pass + + if not case_passed: + print(case[1], case[2]) + print("expected: " + case[3] + ", " + case[3].datatype) + print("actual: " + (case[1] + case[2]) + ", " + (case[1] + case[2]).datatype) + + self.assertTrue(case_passed, "Case " + str(case[0]) + " failed") + class TestValidityFunctions(unittest.TestCase): |