1# -*- coding: utf-8 -*-
2import inspect
3import os
4import sys
5
6import logging
7
8import unittest
9import urllib2
10from urlparse import urlparse, parse_qsl, parse_qs
11from urllib2 import Request
12import time
13
14logging.basicConfig()
15
16# prefer local copy to the one which is installed
17# hack from http://stackoverflow.com/a/6098238/280539
18_top_level_path = os.path.realpath(os.path.abspath(os.path.join(
19    os.path.split(inspect.getfile(inspect.currentframe()))[0],
20    ".."
21)))
22if _top_level_path not in sys.path:
23    sys.path.insert(0, _top_level_path)
24# end of hack
25
26# we don't want to let Wrapper do real web-requests. so, we are…
27# constructing a simple Mock!
28from urllib2 import HTTPError
29
30from io import StringIO
31import warnings
32warnings.simplefilter("always")
33
34import SPARQLWrapper.Wrapper as _victim
35
36from SPARQLWrapper import SPARQLWrapper
37from SPARQLWrapper import XML, GET, POST, JSON, JSONLD, N3, TURTLE, RDF, SELECT, INSERT, RDFXML, CSV, TSV
38from SPARQLWrapper import URLENCODED, POSTDIRECTLY
39from SPARQLWrapper import BASIC, DIGEST
40from SPARQLWrapper.Wrapper import QueryResult, QueryBadFormed, EndPointNotFound, EndPointInternalError, Unauthorized, URITooLong
41
42
43class FakeResult(object):
44    def __init__(self, request):
45        self.request = request
46
47
48def urlopener(request):
49    return FakeResult(request)
50
51
52def urlopener_error_generator(code):
53    def urlopener_error(request):
54        raise HTTPError(request.get_full_url, code, '', {}, StringIO(u''))
55
56    return urlopener_error
57
58
59def urlopener_check_data_encoding(request):
60    if sys.version < '3':  # have to write it like this, for 2to3 compatibility
61        if isinstance(request.data, unicode):
62            raise TypeError
63    else:
64        if isinstance(request.data, str):
65            raise TypeError
66# DONE
67
68class TestCase(unittest.TestCase):
69
70    def assertIsInstance(self, obj, cls, msg=None, *args, **kwargs):
71        """Python < v2.7 compatibility.  Assert 'obj' is instance of 'cls'"""
72        try:
73            f = super(TestCase, self).assertIsInstance
74        except AttributeError:
75            self.assertTrue(isinstance(obj, cls), *args, **kwargs)
76        else:
77            f(obj, cls, *args, **kwargs)
78
79    def assertIsNone(self, obj, msg=None, *args, **kwargs):
80        """Python < v2.7 compatibility.  Assert 'obj' is None"""
81        try:
82            f = super(TestCase, self).assertIsNone
83        except AttributeError:
84            self.assertEqual(obj, None, *args, **kwargs)
85        else:
86            f(obj, *args, **kwargs)
87
88
89class SPARQLWrapper_Test(TestCase):
90
91    @staticmethod
92    def _get_request(wrapper):
93        return wrapper.query().response.request  # possible due to mock above
94
95    @staticmethod
96    def _get_parameters_from_request(request):
97        if request.get_method() == 'GET':
98            pieces_str = urlparse(request.get_full_url()).query
99        else:
100            if sys.version < '3':
101                pieces_str = request.data
102            else:
103                pieces_str = request.data.decode('ascii')
104
105        return parse_qs(pieces_str)
106
107    @staticmethod
108    def _get_request_parameters(wrapper):
109        request = SPARQLWrapper_Test._get_request(wrapper)
110        parameters = SPARQLWrapper_Test._get_parameters_from_request(request)
111
112        return parameters
113
114    @staticmethod
115    def _get_request_parameters_as_bytes(wrapper):
116        request = SPARQLWrapper_Test._get_request(wrapper)
117        parameters = SPARQLWrapper_Test._get_parameters_from_request(request)
118
119        if sys.version < '3':
120            return parameters
121        else:
122            result = {}
123            for k, vs in parameters.iteritems():
124                result[k] = [v.encode('utf-8') for v in vs]
125            return result
126
127    @classmethod
128    def setUpClass(cls):
129        urllib2._opener = None # clear value. Due to the order of test execution, the value of urllib2._opener contains, for instance, keepalive.keepalive.HTTPHandler
130
131    def setUp(self):
132        self.wrapper = SPARQLWrapper(endpoint='http://example.org/sparql')
133        _victim.urlopener = urlopener
134
135    def testConstructor(self):
136        try:
137            SPARQLWrapper()
138            self.fail("SPARQLWrapper constructor should fail without arguments")
139        except TypeError:
140            pass
141
142        wrapper = SPARQLWrapper(endpoint='http://example.org/sparql/')
143
144        self.assertEqual(XML, wrapper.returnFormat, 'default return format is XML')
145        self.assertTrue(
146            wrapper.agent.startswith('sparqlwrapper'),
147            'default user-agent should start with "sparqlwrapper"'
148        )
149
150        wrapper = SPARQLWrapper(endpoint='http://example.org/sparql/', returnFormat='wrongformat')
151        self.assertEqual(XML, wrapper.returnFormat, 'default return format is XML')
152
153        wrapper = SPARQLWrapper(endpoint='http://example.org/sparql/', defaultGraph='http://example.org/default')
154        parameters = self._get_request_parameters(wrapper)
155        self.assertEqual(
156            ['http://example.org/default'],
157            parameters.get('default-graph-uri'),
158            'default graph is set'
159        )
160
161    def testReset(self):
162        self.wrapper.setMethod(POST)
163        self.wrapper.setQuery('CONSTRUCT WHERE {?a ?b ?c}')
164        self.wrapper.setReturnFormat(N3)
165        self.wrapper.addParameter('a', 'b')
166        self.wrapper.setOnlyConneg(True)
167
168        request = self._get_request(self.wrapper)
169        parameters = self._get_parameters_from_request(request)
170        onlyConneg = self.wrapper.onlyConneg
171
172        self.assertEqual('POST', request.get_method())
173        self.assertTrue(parameters['query'][0].startswith('CONSTRUCT'))
174        self.assertTrue('rdf+n3' in request.get_header('Accept'))
175        self.assertTrue('a' in parameters)
176        self.assertTrue(onlyConneg)
177
178        self.wrapper.resetQuery()
179
180        request = self._get_request(self.wrapper)
181        parameters = self._get_parameters_from_request(request)
182        onlyConneg = self.wrapper.onlyConneg
183
184        self.assertEqual('GET', request.get_method())
185        self.assertTrue(parameters['query'][0].startswith('SELECT'))
186        self.assertFalse('rdf+n3' in request.get_header('Accept'))
187        self.assertTrue('sparql-results+xml' in request.get_header('Accept'))
188        self.assertFalse('a' in parameters)
189        self.assertFalse('a' in parameters)
190        self.assertTrue(onlyConneg)
191
192    def testSetReturnFormat(self):
193        with warnings.catch_warnings(record=True) as w:
194            self.wrapper.setReturnFormat('nonexistent format')
195            self.assertEqual(1, len(w), "Warning due to non expected format")
196
197        self.assertEqual(XML, self.wrapper.query().requestedFormat)
198
199        self.wrapper.setReturnFormat(JSON)
200        self.assertEqual(JSON, self.wrapper.query().requestedFormat)
201
202        try:
203            import rdflib_jsonld
204            self.wrapper.setReturnFormat(JSONLD)
205            self.assertEqual(JSONLD, self.wrapper.query().requestedFormat)
206        except ImportError:
207            self.assertRaises(ValueError, self.wrapper.setReturnFormat, JSONLD)
208
209    def testsSupportsReturnFormat(self):
210        self.assertTrue(self.wrapper.supportsReturnFormat(XML))
211        self.assertTrue(self.wrapper.supportsReturnFormat(JSON))
212        self.assertTrue(self.wrapper.supportsReturnFormat(TURTLE))
213        self.assertTrue(self.wrapper.supportsReturnFormat(N3))
214        self.assertTrue(self.wrapper.supportsReturnFormat(RDF))
215        self.assertTrue(self.wrapper.supportsReturnFormat(RDFXML))
216        self.assertTrue(self.wrapper.supportsReturnFormat(CSV))
217        self.assertTrue(self.wrapper.supportsReturnFormat(TSV))
218        self.assertFalse(self.wrapper.supportsReturnFormat('nonexistent format'))
219
220        try:
221            import rdflib_jsonld
222            self.assertTrue(self.wrapper.supportsReturnFormat(JSONLD))
223        except ImportError:
224            self.assertFalse(self.wrapper.supportsReturnFormat(JSONLD))
225
226
227    def testAddParameter(self):
228        self.assertFalse(self.wrapper.addParameter('query', 'dummy'))
229        self.assertTrue(self.wrapper.addParameter('param1', 'value1'))
230        self.assertTrue(self.wrapper.addParameter('param1', 'value2'))
231        self.assertTrue(self.wrapper.addParameter('param2', 'value2'))
232
233        pieces = self._get_request_parameters(self.wrapper)
234
235        self.assertTrue('param1' in pieces)
236        self.assertEqual(['value1', 'value2'], pieces['param1'])
237        self.assertTrue('param2' in pieces)
238        self.assertEqual(['value2'], pieces['param2'])
239        self.assertNotEqual(['dummy'], 'query')
240
241    def testSetCredentials(self):
242        request = self._get_request(self.wrapper)
243        self.assertFalse(request.has_header('Authorization'))
244
245        self.wrapper.setCredentials('login', 'password')
246        request = self._get_request(self.wrapper)
247        self.assertTrue(request.has_header('Authorization'))
248
249        # expected header for login:password
250        # should succeed for python 3 since pull request #72
251        self.assertEqual("Basic bG9naW46cGFzc3dvcmQ=", request.get_header('Authorization'))
252
253    def testAddCustomHttpHeader(self):
254        request = self._get_request(self.wrapper)
255        self.assertFalse(request.has_header('Foo'))
256
257        # Add new header field name
258        self.wrapper.addCustomHttpHeader('Foo', 'bar')
259        request = self._get_request(self.wrapper)
260        self.assertTrue(request.has_header('Foo'))
261        self.assertEqual("bar", request.get_header('Foo'))
262
263        # Override a new field name
264        self.wrapper.addCustomHttpHeader('Foo', 'bar')
265        request = self._get_request(self.wrapper)
266        self.assertTrue(request.has_header('Foo'))
267        self.assertEqual("bar", request.get_header('Foo'))
268        self.wrapper.addCustomHttpHeader('Foo', 'bar_2')
269        request = self._get_request(self.wrapper)
270        self.assertTrue(request.has_header('Foo'))
271        self.assertEqual("bar_2", request.get_header('Foo'))
272
273        # Override header field name
274        self.wrapper.addCustomHttpHeader('User-agent', 'Another UA')
275        request = self._get_request(self.wrapper)
276        self.assertEqual("Another UA", request.get_header('User-agent'))
277
278    def testClearCustomHttpHeader(self):
279        request = self._get_request(self.wrapper)
280        self.assertFalse(request.has_header('Foo'))
281
282        # Add new header field name
283        self.wrapper.addCustomHttpHeader('Foo_1', 'bar_1')
284        self.wrapper.addCustomHttpHeader('Foo_2', 'bar_2')
285        self.wrapper.addCustomHttpHeader('Foo_3', 'bar_3')
286
287
288        self.assertFalse(self.wrapper.clearCustomHttpHeader('Foo_4'))
289        self.assertTrue(self.wrapper.clearCustomHttpHeader('Foo_3'))
290
291        customHttpHeaders = self.wrapper.customHttpHeaders
292
293        self.assertTrue('Foo_1' in customHttpHeaders)
294        self.assertTrue('Foo_2' in customHttpHeaders)
295        self.assertEqual('bar_1', customHttpHeaders['Foo_1'])
296        self.assertEqual('bar_2', customHttpHeaders['Foo_2'])
297
298        self.assertFalse(self.wrapper.clearCustomHttpHeader('Foo_3'), 'already cleaned')
299
300
301    def testSetHTTPAuth(self):
302        self.assertRaises(TypeError, self.wrapper.setHTTPAuth, 123)
303        self.wrapper.setCredentials('login', 'password')
304        request = self._get_request(self.wrapper)
305        self.assertTrue(request.has_header('Authorization'))
306        self.assertIsNone(urllib2._opener)
307
308        self.wrapper.setHTTPAuth(DIGEST)
309        self.assertIsNone(urllib2._opener)
310        request = self._get_request(self.wrapper)
311        self.assertFalse(request.has_header('Authorization'))
312        self.assertEqual(self.wrapper.http_auth, DIGEST)
313        self.assertIsInstance(urllib2._opener, urllib2.OpenerDirector)
314
315        self.wrapper.setHTTPAuth(DIGEST)
316        self.wrapper.setCredentials('login', 'password')
317        request = self._get_request(self.wrapper)
318        self.assertEqual(self.wrapper.http_auth, DIGEST)
319        self.assertEqual(self.wrapper.user, "login")
320        self.assertEqual(self.wrapper.passwd, "password")
321        self.assertEqual(self.wrapper.realm, "SPARQL")
322        self.assertNotEqual(self.wrapper.realm, "SPARQL Endpoint")
323
324        self.wrapper.setHTTPAuth(DIGEST)
325        self.wrapper.setCredentials('login', 'password', realm="SPARQL Endpoint")
326        request = self._get_request(self.wrapper)
327        self.assertEqual(self.wrapper.http_auth, DIGEST)
328        self.assertEqual(self.wrapper.user, "login")
329        self.assertEqual(self.wrapper.passwd, "password")
330        self.assertEqual(self.wrapper.realm, "SPARQL Endpoint")
331        self.assertNotEqual(self.wrapper.realm, "SPARQL")
332
333        self.assertRaises(ValueError, self.wrapper.setHTTPAuth, 'OAuth')
334
335        self.wrapper.http_auth = "OAuth"
336        self.assertRaises(NotImplementedError, self._get_request, self.wrapper)
337
338    def testSetQuery(self):
339        self.wrapper.setQuery('PREFIX example: <http://example.org/INSERT/> SELECT * WHERE {?s ?p ?v}')
340        self.assertEqual(SELECT, self.wrapper.queryType)
341
342        self.wrapper.setQuery('PREFIX e: <http://example.org/> INSERT {e:a e:b e:c}')
343        self.assertEqual(INSERT, self.wrapper.queryType)
344
345        self.wrapper.setQuery("""#CONSTRUCT {?s ?p ?o}
346                                   SELECT ?s ?p ?o
347                                   WHERE {?s ?p ?o}""")
348        self.assertEqual(SELECT, self.wrapper.queryType)
349
350        with warnings.catch_warnings(record=True) as w:
351            self.wrapper.setQuery('UNKNOWN {e:a e:b e:c}')
352            self.assertEqual(SELECT, self.wrapper.queryType, 'unknown queries result in SELECT')
353
354    def testSetQueryEncodingIssues(self):
355        #further details from issue #35
356        query = u'INSERT DATA { <urn:michel> <urn:says> "これはテストです" }'
357        query_bytes = query.encode('utf-8')
358
359        self.wrapper.setMethod(POST)
360        self.wrapper.setRequestMethod(POSTDIRECTLY)
361
362        self.wrapper.setQuery(query)
363        request = self._get_request(self.wrapper)
364        self.assertEquals(query_bytes, request.data)
365
366        self.wrapper.setQuery(query_bytes)
367        request = self._get_request(self.wrapper)
368        self.assertEquals(query_bytes, request.data)
369
370        self.wrapper.setRequestMethod(URLENCODED)
371
372        self.wrapper.setQuery(query)
373        parameters = self._get_request_parameters_as_bytes(self.wrapper)
374        self.assertEquals(query_bytes, parameters['update'][0])
375
376        self.wrapper.setQuery(query_bytes)
377        parameters = self._get_request_parameters_as_bytes(self.wrapper)
378        self.assertEquals(query_bytes, parameters['update'][0])
379
380        try:
381            self.wrapper.setQuery(query.encode('sjis'))
382            self.fail()
383        except UnicodeDecodeError:
384            self.assertTrue(True)
385
386        try:
387            self.wrapper.setQuery({'foo': 'bar'})
388            self.fail()
389        except TypeError:
390            self.assertTrue(True)
391
392    def testSetTimeout(self):
393        self.wrapper.setTimeout(10)
394        self.assertEqual(10, self.wrapper.timeout)
395
396        self.wrapper.resetQuery()
397        self.assertEqual(None, self.wrapper.timeout)
398
399    def testClearParameter(self):
400        self.wrapper.addParameter('param1', 'value1')
401        self.wrapper.addParameter('param1', 'value2')
402        self.wrapper.addParameter('param2', 'value2')
403
404        self.assertFalse(self.wrapper.clearParameter('query'))
405        self.assertTrue(self.wrapper.clearParameter('param1'))
406
407        pieces = self._get_request_parameters(self.wrapper)
408
409        self.assertFalse('param1' in pieces)
410        self.assertTrue('param2' in pieces)
411        self.assertEqual(['value2'], pieces['param2'])
412
413        self.assertFalse(self.wrapper.clearParameter('param1'), 'already cleaned')
414
415    def testSetMethod(self):
416        self.wrapper.setMethod(POST)
417        request = self._get_request(self.wrapper)
418
419        self.assertEqual("POST", request.get_method())
420
421        self.wrapper.setMethod(GET)
422        request = self._get_request(self.wrapper)
423
424        self.assertEqual("GET", request.get_method())
425
426    def testSetRequestMethod(self):
427        self.assertEqual(URLENCODED, self.wrapper.requestMethod)
428
429        self.wrapper.setRequestMethod(POSTDIRECTLY)
430        self.assertEqual(POSTDIRECTLY, self.wrapper.requestMethod)
431
432    def testIsSparqlUpdateRequest(self):
433        self.wrapper.setQuery('DELETE WHERE {?s ?p ?o}')
434        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
435
436        self.wrapper.setQuery('DELETE DATA { <urn:john> <urn:likes> <urn:surfing> }')
437        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
438
439        self.wrapper.setQuery("""
440        PREFIX example: <http://example.org/SELECT/>
441        BASE <http://example.org/SELECT>
442        DELETE WHERE {?s ?p ?o}
443        """)
444        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
445
446        self.wrapper.setQuery('WITH <urn:graph> DELETE DATA { <urn:john> <urn:likes> <urn:surfing> }')
447        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
448
449        self.wrapper.setQuery('INSERT DATA { <urn:john> <urn:likes> <urn:surfing> }')
450        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
451
452        self.wrapper.setQuery('WITH <urn:graph> INSERT DATA { <urn:john> <urn:likes> <urn:surfing> }')
453        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
454
455        self.wrapper.setQuery('CREATE GRAPH <urn:graph>')
456        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
457
458        self.wrapper.setQuery('CLEAR GRAPH <urn:graph>')
459        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
460
461        self.wrapper.setQuery('DROP GRAPH <urn:graph>')
462        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
463
464        self.wrapper.setQuery('MOVE GRAPH <urn:graph1> TO GRAPH <urn:graph2>')
465        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
466
467        self.wrapper.setQuery('LOAD <http://localhost/file.rdf> INTO GRAPH <urn:graph>')
468        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
469
470        self.wrapper.setQuery('COPY <urn:graph1> TO GRAPH <urn:graph2>')
471        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
472
473        self.wrapper.setQuery('ADD <urn:graph1> TO GRAPH <urn:graph2>')
474        self.assertTrue(self.wrapper.isSparqlUpdateRequest())
475
476    def testIsSparqlQueryRequest(self):
477        self.wrapper.setQuery('SELECT * WHERE {?s ?p ?o}')
478        self.assertTrue(self.wrapper.isSparqlQueryRequest())
479
480        self.wrapper.setQuery("""
481        PREFIX example: <http://example.org/DELETE/>
482        BASE <http://example.org/MODIFY>
483        ASK WHERE {?s ?p ?o}
484        """)
485        self.assertTrue(self.wrapper.isSparqlQueryRequest())
486        self.assertFalse(self.wrapper.isSparqlUpdateRequest())
487
488    def testQuery(self):
489        qr = self.wrapper.query()
490        self.assertTrue(isinstance(qr, QueryResult))
491
492        request = qr.response.request  # possible due to mock above
493        self.assertTrue(isinstance(request, Request))
494
495        parameters = self._get_parameters_from_request(request)
496        self.assertTrue('query' in parameters)
497        self.assertTrue('update' not in parameters)
498
499        self.wrapper.setMethod(POST)
500        self.wrapper.setQuery('PREFIX e: <http://example.org/> INSERT {e:a e:b e:c}')
501        parameters = self._get_request_parameters(self.wrapper)
502        self.assertTrue('update' in parameters)
503        self.assertTrue('query' not in parameters)
504        #_returnFormatSetting = ["format", "output", "results"]
505        self.assertTrue('format' not in parameters)
506        self.assertTrue('output' not in parameters)
507        self.assertTrue('results' not in parameters)
508
509        _victim.urlopener = urlopener_error_generator(400)
510        try:
511            self.wrapper.query()
512            self.fail('should have raised exception')
513        except QueryBadFormed as e:
514            #  TODO: check exception-format
515            pass
516        except:
517            self.fail('got wrong exception')
518
519        _victim.urlopener = urlopener_error_generator(401)
520        try:
521            self.wrapper.query()
522            self.fail('should have raised exception')
523        except Unauthorized as e:
524            #  TODO: check exception-format
525            pass
526        except:
527            self.fail('got wrong exception')
528
529        _victim.urlopener = urlopener_error_generator(404)
530        try:
531            self.wrapper.query()
532            self.fail('should have raised exception')
533        except EndPointNotFound as e:
534            #  TODO: check exception-format
535            pass
536        except:
537            self.fail('got wrong exception')
538
539        _victim.urlopener = urlopener_error_generator(414)
540        try:
541            self.wrapper.query()
542            self.fail('should have raised exception')
543        except URITooLong as e:
544            #  TODO: check exception-format
545            pass
546        except:
547            self.fail('got wrong exception')
548
549        _victim.urlopener = urlopener_error_generator(500)
550        try:
551            self.wrapper.query()
552            self.fail('should have raised exception')
553        except EndPointInternalError as e:
554            #  TODO: check exception-format
555            pass
556        except:
557            self.fail('got wrong exception')
558
559        _victim.urlopener = urlopener_error_generator(999)
560        try:
561            self.wrapper.query()
562            self.fail('should have raised exception')
563        except HTTPError as e:
564            #  TODO: check exception-format
565            pass
566        except:
567            self.fail('got wrong exception')
568
569    def testQueryEncoding(self):
570        query = 'INSERT DATA { <urn:michel> <urn:says> "é" }'
571
572        wrapper = SPARQLWrapper('http://example.com:3030/example')
573        wrapper.setMethod(POST)
574        wrapper.setRequestMethod(URLENCODED)
575        wrapper.setQuery(query)
576
577        _victim.urlopener = urlopener_check_data_encoding
578        wrapper.query()
579
580    def testQueryAndConvert(self):
581        _oldQueryResult = _victim.QueryResult
582
583        class FakeQueryResult(object):
584            def __init__(self, result):
585                pass
586
587            def convert(self):
588                return True
589
590        try:
591            _victim.QueryResult = FakeQueryResult
592            result = self.wrapper.queryAndConvert()
593            self.assertEqual(True, result)
594        finally:
595            _victim.QueryResult = _oldQueryResult
596
597    def testComments(self):
598        # see issue #32
599        self.wrapper.setQuery("""
600# this is a comment
601select * where { ?s ?p ?o }
602""")
603        self.assertTrue(self.wrapper.isSparqlQueryRequest())
604
605    def testHashInPrefixes(self):
606        # see issue #77
607        self.wrapper.setQuery("""
608PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>
609select * where { ?s ?p ?o }
610""")
611        self.assertTrue(self.wrapper.isSparqlQueryRequest())
612
613    def testHashInPrefixComplex(self):
614        # see issue #77
615        self.wrapper.setQuery("""
616PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
617PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>
618PREFIX weather: <http://hal.zamia.org/weather/>
619PREFIX dbo:     <http://dbpedia.org/ontology/>
620PREFIX dbr:     <http://dbpedia.org/resource/>
621PREFIX dbp:     <http://dbpedia.org/property/>
622PREFIX xml:     <http://www.w3.org/XML/1998/namespace>
623PREFIX xsd:     <http://www.w3.org/2001/XMLSchema#>
624
625SELECT DISTINCT ?location ?cityid ?timezone ?label
626WHERE {
627  ?location weather:cityid ?cityid .
628  ?location weather:timezone ?timezone .
629  ?location rdfs:label ?label .
630}
631""")
632        self.assertTrue(self.wrapper.isSparqlQueryRequest())
633
634    def testHashWithNoComments(self):
635        # see issue #77
636        query = """
637PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
638
639SELECT *
640WHERE {
641  ?s ?p ?o .
642}
643"""
644        parsed_query = self.wrapper._cleanComments(query)
645        self.assertEquals(query, parsed_query)
646
647    def testCommentBeginningLine(self):
648        # see issue #77
649        query = """
650PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
651# a comment
652SELECT *
653WHERE {
654  ?s ?p ?o .
655}
656"""
657        expected_parsed_query = """
658PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
659
660SELECT *
661WHERE {
662  ?s ?p ?o .
663}
664"""
665        parsed_query = self.wrapper._cleanComments(query)
666        self.assertEquals(expected_parsed_query, parsed_query)
667
668    def testCommentEmtpyLine(self):
669        # see issue #77
670        query = """
671PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
672     # a comment
673SELECT *
674WHERE {
675  ?s ?p ?o .
676}
677"""
678        expected_parsed_query = """
679PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
680
681SELECT *
682WHERE {
683  ?s ?p ?o .
684}
685"""
686        parsed_query = self.wrapper._cleanComments(query)
687        self.assertEquals(expected_parsed_query, parsed_query)
688
689    def testCommentsFirstLine(self):
690        # see issue #77
691        query = """#CONSTRUCT {?s ?p ?o}
692                                   SELECT ?s ?p ?o
693                                   WHERE {?s ?p ?o}"""
694        expected_parsed_query = """
695
696                                   SELECT ?s ?p ?o
697                                   WHERE {?s ?p ?o}"""
698
699        parsed_query = self.wrapper._cleanComments(query)
700        self.assertEquals(expected_parsed_query, parsed_query)
701
702    @unittest.skip("issue #80")
703    def testCommentAfterStatements(self):
704        # see issue #77
705        query = """
706PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
707
708SELECT *
709WHERE {     # this is the where condition
710  ?s ?p ?o .
711}
712"""
713        expected_parsed_query = """
714PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
715
716SELECT *
717WHERE {
718  ?s ?p ?o .
719}
720"""
721        parsed_query = self.wrapper._cleanComments(query)
722        self.assertEquals(expected_parsed_query, parsed_query)
723
724    def testSingleLineQueryLine(self):
725        # see issue #74
726        query = "prefix whatever: <http://example.org/blah#> ASK { ?s ?p ?o }"
727        parsed_query = self.wrapper._cleanComments(query)
728        self.assertEquals(query, parsed_query)
729
730        self.wrapper.setQuery(query)
731        self.assertTrue(self.wrapper.isSparqlQueryRequest())
732
733    def testOnlyConneg(self):
734        # see issue #82
735        query = "prefix whatever: <http://example.org/blah#> ASK { ?s ?p ?o }"
736        self.wrapper.setOnlyConneg(False)
737        self.wrapper.setQuery(query)
738        request = self._get_request(self.wrapper)
739        request_params = dict(parse_qsl(urlparse(request.get_full_url()).query))
740        for returnFormatSetting in ["format", "output", "results"]: # Obviously _returnFormatSetting is not accessible from SPARQLWrapper, so we copy&paste the possible values
741            self.assertTrue(returnFormatSetting in request_params, "URL parameter '%s' was not sent, and it was expected" %returnFormatSetting)
742
743        #ONLY Content Negotiation
744        self.wrapper.resetQuery()
745        self.wrapper.setOnlyConneg(True)
746        self.wrapper.setQuery(query)
747        request = self._get_request(self.wrapper)
748        request_params = dict(parse_qsl(urlparse(request.get_full_url()).query))
749        for returnFormatSetting in ["format", "output", "results"]: # Obviously _returnFormatSetting is not accessible from SPARQLWrapper, so we copy&paste the possible values
750            self.assertFalse(returnFormatSetting in request_params, "URL parameter '%s' was sent, and it was not expected (only Content Negotiation)" %returnFormatSetting)
751
752
753class QueryResult_Test(unittest.TestCase):
754
755    def testConstructor(self):
756        qr = QueryResult('result')
757        self.assertEqual('result', qr.response)
758        try:
759            format = qr.requestedFormat
760            self.fail('format is not supposed to be set')
761        except:
762            pass
763
764        qr = QueryResult(('result', 'format'))
765        self.assertEqual('result', qr.response)
766        self.assertEqual('format', qr.requestedFormat)
767
768    def testProxyingToResponse(self):
769        class FakeResponse(object):
770            def __init__(self):
771                self.geturl_called = False
772                self.info_called = False
773                self.iter_called = False
774                self.next_called = False
775
776            def geturl(self):
777                self.geturl_called = True
778
779            def info(self):
780                self.info_called = True
781                return {"key": "value"}
782
783            def __iter__(self):
784                self.iter_called = True
785
786            def next(self):
787                self.next_called = True
788
789        result = FakeResponse()
790
791        qr = QueryResult(result)
792        qr.geturl()
793        qr.__iter__()
794        qr.next()
795
796        self.assertTrue(result.geturl_called)
797        self.assertTrue(result.iter_called)
798        self.assertTrue(result.next_called)
799
800        info = qr.info()
801        self.assertTrue(result.info_called)
802        self.assertEqual('value', info.__getitem__('KEY'), 'keys should be case-insensitive')
803
804    def testConvert(self):
805        class FakeResponse(object):
806            def __init__(self, content_type):
807                self.content_type = content_type
808
809            def info(self):
810                return {"Content-type": self.content_type}
811
812            def read(self, len):
813                return ''
814
815        def _mime_vs_type(mime, requested_type):
816            """
817            :param mime: mimetype/Content-Type of the response
818            :param requested_type: requested mimetype (alias)
819            :return: number of warnings produced by combo
820            """
821            with warnings.catch_warnings(record=True) as w:
822                qr = QueryResult((FakeResponse(mime), requested_type))
823
824                try:
825                    qr.convert()
826                except:
827                    pass
828
829                return len(w)
830
831        # In the cases of "application/ld+json" and "application/rdf+xml", the
832        # RDFLib raised a warning because the manually created QueryResult has no real
833        # response value (implemented a fake read).
834        # "WARNING:rdflib.term:  does not look like a valid URI, trying to serialize this will break."
835        self.assertEqual(0, _mime_vs_type("application/sparql-results+xml", XML))
836        self.assertEqual(0, _mime_vs_type("application/sparql-results+json", JSON))
837        self.assertEqual(0, _mime_vs_type("text/n3", N3))
838        self.assertEqual(0, _mime_vs_type("text/turtle", TURTLE))
839        self.assertEqual(0, _mime_vs_type("application/turtle", TURTLE))
840        self.assertEqual(0, _mime_vs_type("application/ld+json", JSON)) # Warning
841        self.assertEqual(0, _mime_vs_type("application/ld+json", JSONLD)) # Warning
842        self.assertEqual(0, _mime_vs_type("application/rdf+xml", XML)) # Warning
843        self.assertEqual(0, _mime_vs_type("application/rdf+xml", RDF)) # Warning
844        self.assertEqual(0, _mime_vs_type("application/rdf+xml", RDFXML)) # Warning
845        self.assertEqual(0, _mime_vs_type("text/csv", CSV))
846        self.assertEqual(0, _mime_vs_type("text/tab-separated-values", TSV))
847        self.assertEqual(0, _mime_vs_type("application/xml", XML))
848
849        self.assertEqual(1, _mime_vs_type("application/x-foo-bar", XML), "invalid mime")
850
851        self.assertEqual(1, _mime_vs_type("application/sparql-results+xml", N3))
852        self.assertEqual(1, _mime_vs_type("application/sparql-results+json", XML))
853        self.assertEqual(1, _mime_vs_type("text/n3", JSON))
854        self.assertEqual(1, _mime_vs_type("text/turtle", XML))
855        self.assertEqual(1, _mime_vs_type("application/ld+json", XML))  # Warning
856        self.assertEqual(1, _mime_vs_type("application/ld+json", N3))  # Warning
857        self.assertEqual(1, _mime_vs_type("application/rdf+xml", JSON))  # Warning
858        self.assertEqual(1, _mime_vs_type("application/rdf+xml", N3))  # Warning
859
860    def testPrint_results(self):
861        """
862        print_results() is only allowed for JSON return format.
863        """
864        class FakeResponse(object):
865            def __init__(self, content_type):
866                self.content_type = content_type
867
868            def info(self):
869                return {"Content-type": self.content_type}
870
871            def read(self, len):
872                return ''
873
874        def _print_results(mime):
875            """
876            :param mime: mimetype/Content-Type of the response
877            :return: number of warnings produced by combo
878            """
879            with warnings.catch_warnings(record=True) as w:
880                qr = QueryResult(FakeResponse(mime))
881
882                try:
883                    qr.print_results()
884                except:
885                    pass
886
887                return len(w)
888
889        self.assertEqual(0, _print_results("application/sparql-results+json"))
890        self.assertEqual(0, _print_results("application/json"))
891        self.assertEqual(0, _print_results("text/javascript"))
892        self.assertEqual(0, _print_results("application/javascript"))
893
894        self.assertEqual(1, _print_results("application/sparql-results+xml"))
895        self.assertEqual(1, _print_results("application/xml"))
896        self.assertEqual(1, _print_results("application/rdf+xml"))
897
898        self.assertEqual(1, _print_results("application/turtle"))
899        self.assertEqual(1, _print_results("text/turtle"))
900
901        self.assertEqual(1, _print_results("text/rdf+n3"))
902        self.assertEqual(1, _print_results("application/n-triples"))
903        self.assertEqual(1, _print_results("application/n3"))
904        self.assertEqual(1, _print_results("text/n3"))
905
906        self.assertEqual(1, _print_results("text/csv"))
907
908        self.assertEqual(1, _print_results("text/tab-separated-values"))
909
910        self.assertEqual(1, _print_results("application/ld+json"))
911        self.assertEqual(1, _print_results("application/x-json+ld"))
912
913        self.assertEqual(2, _print_results("application/x-foo-bar"))
914
915
916class QueryType_Time_Test(unittest.TestCase):
917
918    def testQueries(self):
919        sparql = SPARQLWrapper("http://example.org/sparql")
920
921        queries = []
922
923        queries.append("""
924    PREFIX a: <http://dbpedia.org/a>
925    PREFIX b: <http://dbpedia.org/b>
926    PREFIX c: <http://dbpedia.org/c>
927    PREFIX d: <http://dbpedia.org/d>
928    PREFIX e: <http://dbpedia.org/e>
929    PREFIX f: <http://dbpedia.org/f>
930    PREFIX g: <http://dbpedia.org/g>
931    PREFIX h: <http://dbpedia.org/h>
932    FROM <http://dbpedia.org>
933    SELECT ?s ?p ?o WHERE {
934        ?s ?p ?o.
935    }""")
936
937        queries.append("""PREFIX a: <http://dbpedia.org/a>
938    PREFIX b: <http://dbpedia.org/b>
939    PREFIX c: <http://dbpedia.org/c>
940    PREFIX d: <http://dbpedia.org/d>
941    PREFIX e: <http://dbpedia.org/e>
942    PREFIX f: <http://dbpedia.org/f>
943    PREFIX g: <http://dbpedia.org/g>
944    PREFIX h: <http://dbpedia.org/h>
945    FROM <http://dbpedia.org>
946    SELECT ?s ?p ?o WHERE {
947        ?s ?p ?o.
948    }""")
949
950        queries.append("""PREFIX a: <http://dbpedia.org/a>
951PREFIX b: <http://dbpedia.org/b>
952PREFIX c: <http://dbpedia.org/c>
953PREFIX d: <http://dbpedia.org/d>
954PREFIX e: <http://dbpedia.org/e>
955PREFIX f: <http://dbpedia.org/f>
956PREFIX g: <http://dbpedia.org/g>
957PREFIX h: <http://dbpedia.org/h>
958FROM <http://dbpedia.org>
959SELECT ?s ?p ?o WHERE {
960    ?s ?p ?o.
961}""")
962
963
964        queries.append("""PREFIX a: <http://dbpedia.org/a>
965PREFIX b: <http://dbpedia.org/b>
966PREFIX c: <http://dbpedia.org/c>
967PREFIX d: <http://dbpedia.org/d>
968PREFIX e: <http://dbpedia.org/e>
969PREFIX f: <http://dbpedia.org/f>
970PREFIX g: <http://dbpedia.org/g>
971PREFIX h: <http://dbpedia.org/h>
972SELECT ?s ?p ?o WHERE {
973    ?s ?p ?o.
974}""")
975
976
977        queries.append("""
978    PREFIX a: <http://dbpedia.org/a>
979    PREFIX b: <http://dbpedia.org/b>
980    PREFIX c: <http://dbpedia.org/c>
981    PREFIX d: <http://dbpedia.org/d>
982    PREFIX e: <http://dbpedia.org/e>
983    PREFIX f: <http://dbpedia.org/f>
984    PREFIX g: <http://dbpedia.org/g>
985    PREFIX h: <http://dbpedia.org/h>
986    SELECT ?s ?p ?o WHERE {
987        ?s ?p ?o.
988    }""")
989
990
991        queries.append("""
992    FROM <http://dbpedia.org>
993    SELECT ?s ?p ?o WHERE {
994        ?s ?p ?o.
995    }""")
996
997
998        queries.append("""
999    PREFIX a: <http://dbpedia.org/a>
1000    PREFIX b: <http://dbpedia.org/b>
1001    PREFIX c: <http://dbpedia.org/c>
1002    PREFIX d: <http://dbpedia.org/d>
1003    PREFIX e: <http://dbpedia.org/e>
1004    PREFIX f: <http://dbpedia.org/f>
1005    PREFIX g: <http://dbpedia.org/g>
1006    PREFIX h: <http://dbpedia.org/h>
1007    PREFIX a: <http://dbpedia.org/a>
1008    PREFIX b: <http://dbpedia.org/b>
1009    PREFIX c: <http://dbpedia.org/c>
1010    PREFIX d: <http://dbpedia.org/d>
1011    PREFIX e: <http://dbpedia.org/e>
1012    PREFIX f: <http://dbpedia.org/f>
1013    PREFIX g: <http://dbpedia.org/g>
1014    PREFIX h: <http://dbpedia.org/h>
1015    PREFIX a: <http://dbpedia.org/a>
1016    PREFIX b: <http://dbpedia.org/b>
1017    PREFIX c: <http://dbpedia.org/c>
1018    PREFIX d: <http://dbpedia.org/d>
1019    PREFIX e: <http://dbpedia.org/e>
1020    PREFIX f: <http://dbpedia.org/f>
1021    PREFIX g: <http://dbpedia.org/g>
1022    PREFIX h: <http://dbpedia.org/h>
1023    FROM <http://dbpedia.org>
1024    SELECT ?s ?p ?o WHERE {
1025        ?s ?p ?o.
1026    }""")
1027
1028        queries.append("""PREFIX a: <http://dbpedia.org/a>
1029    PREFIX b: <http://dbpedia.org/b>
1030    PREFIX c: <http://dbpedia.org/c>
1031    PREFIX d: <http://dbpedia.org/d>
1032    PREFIX e: <http://dbpedia.org/e>
1033    PREFIX f: <http://dbpedia.org/f>
1034    PREFIX g: <http://dbpedia.org/g>
1035    PREFIX h: <http://dbpedia.org/h>
1036    PREFIX a: <http://dbpedia.org/a>
1037    PREFIX b: <http://dbpedia.org/b>
1038    PREFIX c: <http://dbpedia.org/c>
1039    PREFIX d: <http://dbpedia.org/d>
1040    PREFIX e: <http://dbpedia.org/e>
1041    PREFIX f: <http://dbpedia.org/f>
1042    PREFIX g: <http://dbpedia.org/g>
1043    PREFIX h: <http://dbpedia.org/h>
1044    PREFIX a: <http://dbpedia.org/a>
1045    PREFIX b: <http://dbpedia.org/b>
1046    PREFIX c: <http://dbpedia.org/c>
1047    PREFIX d: <http://dbpedia.org/d>
1048    PREFIX e: <http://dbpedia.org/e>
1049    PREFIX f: <http://dbpedia.org/f>
1050    PREFIX g: <http://dbpedia.org/g>
1051    PREFIX h: <http://dbpedia.org/h>
1052    FROM <http://dbpedia.org>
1053    SELECT ?s ?p ?o WHERE {
1054        ?s ?p ?o.
1055    }""")
1056
1057        for query in queries:
1058            start_time = time.time()
1059            sparql.setQuery(query)
1060            self.assertTrue((time.time()-start_time)<0.001) # less than 0.001 second
1061
1062
1063if __name__ == "__main__":
1064    unittest.main()
1065