summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorNatanael Arndt <arndtn@gmail.com>2020-05-02 00:26:19 +0200
committerGitHub <noreply@github.com>2020-05-02 00:26:19 +0200
commit7c28713fad45d9e0403304c12a0928704e5f063b (patch)
tree3bfc3a6c383d98fba1dc6b2806380aa1b1eb7d29 /test
parent88ba5748e502792899b7763276dc3cab7b0b68cb (diff)
parent827eabd437e0a0b4404559b6acacdf696f700593 (diff)
downloadrdflib-7c28713fad45d9e0403304c12a0928704e5f063b.tar.gz
Merge branch 'master' into 357-batch-add-graph
Diffstat (limited to 'test')
-rw-r--r--test/test_hex_binary.py62
-rw-r--r--test/test_issue1003.py117
-rw-r--r--test/test_literal.py51
-rw-r--r--test/test_n3.py47
-rw-r--r--test/test_sparql_construct_bindings.py40
-rw-r--r--test/test_sparqlstore.py78
-rw-r--r--test/test_term.py81
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):