1# -*- coding: utf-8 -*-
2"""QGIS Unit tests for QgsServer WMS GetLegendGraphic.
3
4From build dir, run: ctest -R PyQgsServerWMSGetLegendGraphic -V
5
6
7.. note:: This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12"""
13__author__ = 'Alessandro Pasotti'
14__date__ = '25/05/2015'
15__copyright__ = 'Copyright 2015, The QGIS Project'
16
17import os
18
19# Needed on Qt 5 so that the serialization of XML is consistent among all executions
20os.environ['QT_HASH_SEED'] = '1'
21
22import re
23import urllib.request
24import urllib.parse
25import urllib.error
26
27from qgis.testing import unittest
28from qgis.PyQt.QtCore import QSize
29
30import osgeo.gdal  # NOQA
31
32from test_qgsserver_wms import TestQgsServerWMSTestBase
33from qgis.core import QgsProject
34
35# Strip path and content length because path may vary
36RE_STRIP_UNCHECKABLE = br'MAP=[^"]+|Content-Length: \d+'
37RE_ATTRIBUTES = br'[^>\s]+=[^>\s]+'
38
39
40class TestQgsServerWMSGetLegendGraphic(TestQgsServerWMSTestBase):
41    """QGIS Server WMS Tests for GetLegendGraphic request"""
42
43    # Set to True to re-generate reference files for this class
44    # regenerate_reference = True
45
46    def test_getLegendGraphics(self):
47        """Test that does not return an exception but an image"""
48        parms = {
49            'MAP': self.testdata_path + "test_project.qgs",
50            'SERVICE': 'WMS',
51            'VERSION': '1.3.0',
52            'REQUEST': 'GetLegendGraphic',
53            'FORMAT': 'image/png',
54            # 'WIDTH': '20', # optional
55            # 'HEIGHT': '20', # optional
56            'LAYER': 'testlayer%20èé',
57        }
58        qs = '?' + '&'.join(["%s=%s" % (k, v) for k, v in parms.items()])
59        h, r = self._execute_request(qs)
60        self.assertEqual(-1, h.find(b'Content-Type: text/xml; charset=utf-8'), "Header: %s\nResponse:\n%s" % (h, r))
61        self.assertNotEqual(-1, h.find(b'Content-Type: image/png'), "Header: %s\nResponse:\n%s" % (h, r))
62
63    def test_wms_GetLegendGraphic_LayerSpace(self):
64        qs = "?" + "&".join(["%s=%s" % i for i in list({
65            "MAP": urllib.parse.quote(self.projectPath),
66            "SERVICE": "WMS",
67            "VERSION": "1.1.1",
68            "REQUEST": "GetLegendGraphic",
69            "LAYER": "Country,Hello",
70            "FORMAT": "image/png",
71            # "HEIGHT": "500",
72            # "WIDTH": "500",
73            "LAYERSPACE": "50.0",
74            "LAYERFONTBOLD": "TRUE",
75            "LAYERFONTSIZE": "30",
76            "ITEMFONTBOLD": "TRUE",
77            "ITEMFONTSIZE": "20",
78            "LAYERFONTFAMILY": self.fontFamily,
79            "ITEMFONTFAMILY": self.fontFamily,
80            "LAYERTITLE": "TRUE",
81            "CRS": "EPSG:3857"
82        }.items())])
83
84        r, h = self._result(self._execute_request(qs))
85        self._img_diff_error(r, h, "WMS_GetLegendGraphic_LayerSpace", max_size_diff=QSize(1, 1))
86
87    def test_wms_getLegendGraphics_invalid_parameters(self):
88        """Test that does return an exception"""
89        qs = "?" + "&".join(["%s=%s" % i for i in list({
90            "MAP": urllib.parse.quote(self.projectPath),
91            "SERVICE": "WMS",
92            "VERSION": "1.1.1",
93            "REQUEST": "GetLegendGraphic",
94            "LAYER": "Country,Hello,db_point",
95            "LAYERTITLE": "FALSE",
96            "RULELABEL": "FALSE",
97            "FORMAT": "image/png",
98            "HEIGHT": "500",
99            "WIDTH": "500",
100            "RULE": "1",
101            "BBOX": "-151.7,-38.9,51.0,78.0",
102            "CRS": "EPSG:4326"
103        }.items())])
104
105        r, h = self._result(self._execute_request(qs))
106        err = b"BBOX parameter cannot be combined with RULE" in r
107        self.assertTrue(err)
108
109    def test_wms_GetLegendGraphic_LayerTitleSpace(self):
110        qs = "?" + "&".join(["%s=%s" % i for i in list({
111            "MAP": urllib.parse.quote(self.projectPath),
112            "SERVICE": "WMS",
113            "VERSION": "1.1.1",
114            "REQUEST": "GetLegendGraphic",
115            "LAYER": "Country,Hello",
116            "FORMAT": "image/png",
117            # "HEIGHT": "500",
118            # "WIDTH": "500",
119            "LAYERTITLESPACE": "20.0",
120            "LAYERFONTBOLD": "TRUE",
121            "LAYERFONTSIZE": "30",
122            "ITEMFONTBOLD": "TRUE",
123            "ITEMFONTSIZE": "20",
124            "LAYERFONTFAMILY": self.fontFamily,
125            "ITEMFONTFAMILY": self.fontFamily,
126            "LAYERTITLE": "TRUE",
127            "CRS": "EPSG:3857"
128        }.items())])
129
130        r, h = self._result(self._execute_request(qs))
131        self._img_diff_error(r, h, "WMS_GetLegendGraphic_LayerTitleSpace")
132
133    def test_wms_GetLegendGraphic_ShowFeatureCount(self):
134        qs = "?" + "&".join(["%s=%s" % i for i in list({
135            "MAP": urllib.parse.quote(self.projectPath),
136            "SERVICE": "WMS",
137            "VERSION": "1.1.1",
138            "REQUEST": "GetLegendGraphic",
139            "LAYER": "Country,Hello",
140            "FORMAT": "image/png",
141            # "HEIGHT": "500",
142            # "WIDTH": "500",
143            "LAYERTITLE": "TRUE",
144            "LAYERFONTBOLD": "TRUE",
145            "LAYERFONTSIZE": "30",
146            "LAYERFONTFAMILY": self.fontFamily,
147            "ITEMFONTFAMILY": self.fontFamily,
148            "ITEMFONTBOLD": "TRUE",
149            "ITEMFONTSIZE": "20",
150            "SHOWFEATURECOUNT": "TRUE",
151            "CRS": "EPSG:3857"
152        }.items())])
153
154        r, h = self._result(self._execute_request(qs))
155        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ShowFeatureCount", max_size_diff=QSize(1, 1))
156
157    def test_wms_getLegendGraphics_layertitle(self):
158        """Test that does not return an exception but an image"""
159
160        print("TEST FONT FAMILY: ", self.fontFamily)
161
162        parms = {
163            'MAP': self.testdata_path + "test_project.qgs",
164            'SERVICE': 'WMS',
165            'VERSION': '1.3.0',
166            'REQUEST': 'GetLegendGraphic',
167            'FORMAT': 'image/png',
168            # 'WIDTH': '20', # optional
169            # 'HEIGHT': '20', # optional
170            'LAYER': u'testlayer%20èé',
171            'LAYERFONTBOLD': 'TRUE',
172            'LAYERFONTSIZE': '30',
173            'ITEMFONTBOLD': 'TRUE',
174            'LAYERFONTFAMILY': self.fontFamily,
175            'ITEMFONTFAMILY': self.fontFamily,
176            'ITEMFONTSIZE': '20',
177            'LAYERTITLE': 'TRUE',
178            'RULELABEL': 'TRUE'
179        }
180        qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
181        r, h = self._result(self._execute_request(qs))
182        self._img_diff_error(r, h, "WMS_GetLegendGraphic_test", 250, QSize(15, 15))
183
184        # no set of LAYERTITLE and RULELABEL means they are true
185        parms = {
186            'MAP': self.testdata_path + "test_project.qgs",
187            'SERVICE': 'WMS',
188            'VERSION': '1.3.0',
189            'REQUEST': 'GetLegendGraphic',
190            'FORMAT': 'image/png',
191            # 'WIDTH': '20', # optional
192            # 'HEIGHT': '20', # optional
193            'LAYER': u'testlayer%20èé',
194            'LAYERFONTBOLD': 'TRUE',
195            'LAYERFONTSIZE': '30',
196            'ITEMFONTBOLD': 'TRUE',
197            'LAYERFONTFAMILY': self.fontFamily,
198            'ITEMFONTFAMILY': self.fontFamily,
199            'ITEMFONTSIZE': '20'
200        }
201        qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
202        r, h = self._result(self._execute_request(qs))
203
204        self._img_diff_error(r, h, "WMS_GetLegendGraphic_test", 250, QSize(15, 15))
205
206        parms = {
207            'MAP': self.testdata_path + "test_project.qgs",
208            'SERVICE': 'WMS',
209            'VERSION': '1.3.0',
210            'REQUEST': 'GetLegendGraphic',
211            'FORMAT': 'image/png',
212            # 'WIDTH': '20', # optional
213            # 'HEIGHT': '20', # optional
214            'LAYER': u'testlayer%20èé',
215            'LAYERTITLE': 'FALSE',
216            'RULELABEL': 'FALSE'
217        }
218        qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
219        r, h = self._result(self._execute_request(qs))
220        self._img_diff_error(r, h, "WMS_GetLegendGraphic_test_layertitle_false", 250, QSize(15, 15))
221
222    def test_wms_getLegendGraphics_rulelabel(self):
223        """Test that does not return an exception but an image"""
224        parms = {
225            'MAP': self.testdata_path + "test_project.qgs",
226            'SERVICE': 'WMS',
227            'VERSION': '1.3.0',
228            'REQUEST': 'GetLegendGraphic',
229            'FORMAT': 'image/png',
230            'LAYER': u'testlayer%20èé',
231            'LAYERFONTBOLD': 'TRUE',
232            'LAYERFONTSIZE': '30',
233            'ITEMFONTBOLD': 'TRUE',
234            'ITEMFONTSIZE': '20',
235            'LAYERFONTFAMILY': self.fontFamily,
236            'ITEMFONTFAMILY': self.fontFamily,
237            'RULELABEL': 'FALSE'
238        }
239        qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
240        r, h = self._result(self._execute_request(qs))
241        self._img_diff_error(r, h, "WMS_GetLegendGraphic_rulelabel_false", 250, QSize(15, 15))
242
243        parms = {
244            'MAP': self.testdata_path + "test_project.qgs",
245            'SERVICE': 'WMS',
246            'VERSION': '1.3.0',
247            'REQUEST': 'GetLegendGraphic',
248            'FORMAT': 'image/png',
249            'LAYER': u'testlayer%20èé',
250            'LAYERFONTBOLD': 'TRUE',
251            'LAYERFONTSIZE': '30',
252            'ITEMFONTBOLD': 'TRUE',
253            'ITEMFONTSIZE': '20',
254            'LAYERFONTFAMILY': self.fontFamily,
255            'ITEMFONTFAMILY': self.fontFamily,
256            'LAYERTITLE': 'FALSE',
257            'RULELABEL': 'TRUE'
258        }
259        qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
260        r, h = self._result(self._execute_request(qs))
261        self._img_diff_error(r, h, "WMS_GetLegendGraphic_rulelabel_true", 250, QSize(15, 15))
262
263        # no set of RULELABEL means it is true
264        parms = {
265            'MAP': self.testdata_path + "test_project.qgs",
266            'SERVICE': 'WMS',
267            'VERSION': '1.3.0',
268            'REQUEST': 'GetLegendGraphic',
269            'FORMAT': 'image/png',
270            'LAYER': u'testlayer%20èé',
271            'LAYERFONTBOLD': 'TRUE',
272            'LAYERFONTSIZE': '30',
273            'ITEMFONTBOLD': 'TRUE',
274            'ITEMFONTSIZE': '20',
275            'LAYERFONTFAMILY': self.fontFamily,
276            'ITEMFONTFAMILY': self.fontFamily,
277            'LAYERTITLE': 'FALSE'
278        }
279        qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
280        r, h = self._result(self._execute_request(qs))
281        self._img_diff_error(r, h, "WMS_GetLegendGraphic_rulelabel_notset", 250, QSize(15, 15))
282
283        # RULELABEL AUTO for single symbol means it is removed
284        parms = {
285            'MAP': self.testdata_path + "test_project.qgs",
286            'SERVICE': 'WMS',
287            'VERSION': '1.3.0',
288            'REQUEST': 'GetLegendGraphic',
289            'FORMAT': 'image/png',
290            'LAYER': u'testlayer%20èé',
291            'LAYERTITLE': 'FALSE',
292            'RULELABEL': 'AUTO'
293        }
294        qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
295        r, h = self._result(self._execute_request(qs))
296        self._img_diff_error(r, h, "WMS_GetLegendGraphic_rulelabel_auto", 250, QSize(15, 15))
297
298    def test_wms_getLegendGraphics_rule(self):
299        """Test that does not return an exception but an image"""
300        parms = {
301            'MAP': self.testdata_path + "test_project_legend_rule.qgs",
302            'SERVICE': 'WMS',
303            'VERSION': '1.3.0',
304            'REQUEST': 'GetLegendGraphic',
305            'FORMAT': 'image/png',
306            'LAYER': u'testlayer%20èé',
307            'WIDTH': '20',
308            'HEIGHT': '20',
309            'RULE': 'rule0',
310        }
311        qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
312        r, h = self._result(self._execute_request(qs))
313        self._img_diff_error(r, h, "WMS_GetLegendGraphic_rule0", 250, QSize(15, 15))
314
315        parms = {
316            'MAP': self.testdata_path + "test_project_legend_rule.qgs",
317            'SERVICE': 'WMS',
318            'VERSION': '1.3.0',
319            'REQUEST': 'GetLegendGraphic',
320            'FORMAT': 'image/png',
321            'LAYER': u'testlayer%20èé',
322            'WIDTH': '20',
323            'HEIGHT': '20',
324            'RULE': 'rule1',
325        }
326        qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
327        r, h = self._result(self._execute_request(qs))
328        self._img_diff_error(r, h, "WMS_GetLegendGraphic_rule1", 250, QSize(15, 15))
329
330    def test_wms_GetLegendGraphic_Basic(self):
331        qs = "?" + "&".join(["%s=%s" % i for i in list({
332            "MAP": urllib.parse.quote(self.projectPath),
333            "SERVICE": "WMS",
334            "VERSION": "1.1.1",
335            "REQUEST": "GetLegendGraphic",
336            "LAYER": "Country,Hello",
337            "LAYERTITLE": "FALSE",
338            "RULELABEL": "FALSE",
339            "FORMAT": "image/png",
340            "HEIGHT": "500",
341            "WIDTH": "500",
342            "CRS": "EPSG:3857"
343        }.items())])
344
345        r, h = self._result(self._execute_request(qs))
346        self._img_diff_error(r, h, "WMS_GetLegendGraphic_Basic")
347
348    def test_wms_GetLegendGraphic_Transparent(self):
349        qs = "?" + "&".join(["%s=%s" % i for i in list({
350            "MAP": urllib.parse.quote(self.projectPath),
351            "SERVICE": "WMS",
352            "VERSION": "1.1.1",
353            "REQUEST": "GetLegendGraphic",
354            "LAYER": "Country,Hello",
355            "LAYERTITLE": "FALSE",
356            "RULELABEL": "FALSE",
357            "FORMAT": "image/png",
358            "HEIGHT": "500",
359            "WIDTH": "500",
360            "CRS": "EPSG:3857",
361            "TRANSPARENT": "TRUE"
362        }.items())])
363
364        r, h = self._result(self._execute_request(qs))
365        self._img_diff_error(r, h, "WMS_GetLegendGraphic_Transparent")
366
367    def test_wms_GetLegendGraphic_Background(self):
368        qs = "?" + "&".join(["%s=%s" % i for i in list({
369            "MAP": urllib.parse.quote(self.projectPath),
370            "SERVICE": "WMS",
371            "VERSION": "1.1.1",
372            "REQUEST": "GetLegendGraphic",
373            "LAYER": "Country,Hello",
374            "LAYERTITLE": "FALSE",
375            "RULELABEL": "FALSE",
376            "FORMAT": "image/png",
377            "HEIGHT": "500",
378            "WIDTH": "500",
379            "CRS": "EPSG:3857",
380            "BGCOLOR": "green"
381        }.items())])
382
383        r, h = self._result(self._execute_request(qs))
384        self._img_diff_error(r, h, "WMS_GetLegendGraphic_Background")
385
386        qs = "?" + "&".join(["%s=%s" % i for i in list({
387            "MAP": urllib.parse.quote(self.projectPath),
388            "SERVICE": "WMS",
389            "VERSION": "1.1.1",
390            "REQUEST": "GetLegendGraphic",
391            "LAYER": "Country,Hello",
392            "LAYERTITLE": "FALSE",
393            "RULELABEL": "FALSE",
394            "FORMAT": "image/png",
395            "HEIGHT": "500",
396            "WIDTH": "500",
397            "CRS": "EPSG:3857",
398            "BGCOLOR": "0x008000"
399        }.items())])
400
401        r, h = self._result(self._execute_request(qs))
402        self._img_diff_error(r, h, "WMS_GetLegendGraphic_Background_Hex")
403
404    def test_wms_GetLegendGraphic_BoxSpace(self):
405        qs = "?" + "&".join(["%s=%s" % i for i in list({
406            "MAP": urllib.parse.quote(self.projectPath),
407            "SERVICE": "WMS",
408            "VERSION": "1.1.1",
409            "REQUEST": "GetLegendGraphic",
410            "LAYER": "Country,Hello",
411            "LAYERTITLE": "FALSE",
412            "RULELABEL": "FALSE",
413            "BOXSPACE": "100",
414            "FORMAT": "image/png",
415            "HEIGHT": "500",
416            "WIDTH": "500",
417            "CRS": "EPSG:3857"
418        }.items())])
419
420        r, h = self._result(self._execute_request(qs))
421        self._img_diff_error(r, h, "WMS_GetLegendGraphic_BoxSpace")
422
423    def test_wms_GetLegendGraphic_SymbolSpace(self):
424        qs = "?" + "&".join(["%s=%s" % i for i in list({
425            "MAP": urllib.parse.quote(self.projectPath),
426            "SERVICE": "WMS",
427            "VERSION": "1.1.1",
428            "REQUEST": "GetLegendGraphic",
429            "LAYER": "Country,Hello",
430            "LAYERTITLE": "FALSE",
431            "RULELABEL": "FALSE",
432            "SYMBOLSPACE": "100",
433            "FORMAT": "image/png",
434            "HEIGHT": "500",
435            "WIDTH": "500",
436            "CRS": "EPSG:3857"
437        }.items())])
438
439        r, h = self._result(self._execute_request(qs))
440        self._img_diff_error(r, h, "WMS_GetLegendGraphic_SymbolSpace")
441
442    def test_wms_GetLegendGraphic_IconLabelSpace(self):
443        qs = "?" + "&".join(["%s=%s" % i for i in list({
444            "MAP": urllib.parse.quote(self.projectPath),
445            "SERVICE": "WMS",
446            "VERSION": "1.1.1",
447            "REQUEST": "GetLegendGraphic",
448            "LAYER": "Country,Hello",
449            "LAYERTITLE": "FALSE",
450            "RULELABEL": "FALSE",
451            "ICONLABELSPACE": "100",
452            "FORMAT": "image/png",
453            "HEIGHT": "500",
454            "WIDTH": "500",
455            "CRS": "EPSG:3857"
456        }.items())])
457
458        r, h = self._result(self._execute_request(qs))
459        self._img_diff_error(r, h, "WMS_GetLegendGraphic_IconLabelSpace")
460
461    def test_wms_GetLegendGraphic_SymbolSize(self):
462        qs = "?" + "&".join(["%s=%s" % i for i in list({
463            "MAP": urllib.parse.quote(self.projectPath),
464            "SERVICE": "WMS",
465            "VERSION": "1.1.1",
466            "REQUEST": "GetLegendGraphic",
467            "LAYER": "Country,Hello",
468            "LAYERTITLE": "FALSE",
469            "RULELABEL": "FALSE",
470            "SYMBOLWIDTH": "50",
471            "SYMBOLHEIGHT": "30",
472            "FORMAT": "image/png",
473            "HEIGHT": "500",
474            "WIDTH": "500",
475            "CRS": "EPSG:3857"
476        }.items())])
477
478        r, h = self._result(self._execute_request(qs))
479        self._img_diff_error(r, h, "WMS_GetLegendGraphic_SymbolSize")
480
481    def test_wms_GetLegendGraphic_LayerFont(self):
482        qs = "?" + "&".join(["%s=%s" % i for i in list({
483            "MAP": urllib.parse.quote(self.projectPath),
484            "SERVICE": "WMS",
485            "VERSION": "1.1.1",
486            "REQUEST": "GetLegendGraphic",
487            "LAYER": "Country,Hello",
488            "LAYERTITLE": "TRUE",
489            "LAYERFONTBOLD": "TRUE",
490            "LAYERFONTITALIC": "TRUE",
491            "LAYERFONTSIZE": "30",
492            "ITEMFONTBOLD": "TRUE",
493            "ITEMFONTSIZE": "20",
494            "LAYERFONTFAMILY": self.fontFamily,
495            "ITEMFONTFAMILY": self.fontFamily,
496            "FORMAT": "image/png",
497            "HEIGHT": "500",
498            "WIDTH": "500",
499            "CRS": "EPSG:3857"
500        }.items())])
501
502        r, h = self._result(self._execute_request(qs))
503        self._img_diff_error(r, h, "WMS_GetLegendGraphic_LayerFont", max_size_diff=QSize(1, 1))
504
505    def test_wms_GetLegendGraphic_ItemFont(self):
506        qs = "?" + "&".join(["%s=%s" % i for i in list({
507            "MAP": urllib.parse.quote(self.projectPath),
508            "SERVICE": "WMS",
509            "VERSION": "1.1.1",
510            "REQUEST": "GetLegendGraphic",
511            "LAYER": "Country,Hello",
512            "LAYERTITLE": "TRUE",
513            "LAYERFONTBOLD": "TRUE",
514            "LAYERFONTSIZE": "30",
515            "ITEMFONTBOLD": "TRUE",
516            "ITEMFONTITALIC": "TRUE",
517            "ITEMFONTSIZE": "20",
518            "LAYERFONTFAMILY": self.fontFamily,
519            "ITEMFONTFAMILY": self.fontFamily,
520            "FORMAT": "image/png",
521            "HEIGHT": "500",
522            "WIDTH": "500",
523            "CRS": "EPSG:3857"
524        }.items())])
525
526        r, h = self._result(self._execute_request(qs))
527        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ItemFont", max_size_diff=QSize(1, 1))
528
529    def test_wms_GetLegendGraphic_BBox(self):
530        qs = "?" + "&".join(["%s=%s" % i for i in list({
531            "MAP": urllib.parse.quote(self.projectPath),
532            "SERVICE": "WMS",
533            "VERSION": "1.1.1",
534            "REQUEST": "GetLegendGraphic",
535            "LAYER": "Country,Hello,db_point",
536            "LAYERTITLE": "FALSE",
537            "RULELABEL": "FALSE",
538            "FORMAT": "image/png",
539            "SRCHEIGHT": "500",
540            "SRCWIDTH": "500",
541            "BBOX": "-151.7,-38.9,51.0,78.0",
542            "CRS": "EPSG:4326"
543        }.items())])
544
545        r, h = self._result(self._execute_request(qs))
546        self._img_diff_error(r, h, "WMS_GetLegendGraphic_BBox")
547
548    def test_wms_GetLegendGraphic_BBox2(self):
549        qs = "?" + "&".join(["%s=%s" % i for i in list({
550            "MAP": urllib.parse.quote(self.projectPath),
551            "SERVICE": "WMS",
552            "VERSION": "1.1.1",
553            "REQUEST": "GetLegendGraphic",
554            "LAYER": "Country,Hello,db_point",
555            "LAYERTITLE": "FALSE",
556            "RULELABEL": "FALSE",
557            "FORMAT": "image/png",
558            "SRCHEIGHT": "500",
559            "SRCWIDTH": "500",
560            "BBOX": "-76.08,-6.4,-19.38,38.04",
561            "SRS": "EPSG:4326"
562        }.items())])
563
564        r, h = self._result(self._execute_request(qs))
565        self._img_diff_error(r, h, "WMS_GetLegendGraphic_BBox2")
566
567    def test_wms_GetLegendGraphic_BBox_Fallback(self):
568        qs = "?" + "&".join(["%s=%s" % i for i in list({
569            "MAP": urllib.parse.quote(self.projectPath),
570            "SERVICE": "WMS",
571            "VERSION": "1.1.1",
572            "REQUEST": "GetLegendGraphic",
573            "LAYER": "Country,Hello,db_point",
574            "LAYERTITLE": "FALSE",
575            "RULELABEL": "FALSE",
576            "FORMAT": "image/png",
577            "HEIGHT": "500",
578            "WIDTH": "500",
579            "BBOX": "-151.7,-38.9,51.0,78.0",
580            "CRS": "EPSG:4326"
581        }.items())])
582
583        r, h = self._result(self._execute_request(qs))
584        self._img_diff_error(r, h, "WMS_GetLegendGraphic_BBox")
585
586    def test_wms_GetLegendGraphic_BBox2_Fallback(self):
587        qs = "?" + "&".join(["%s=%s" % i for i in list({
588            "MAP": urllib.parse.quote(self.projectPath),
589            "SERVICE": "WMS",
590            "VERSION": "1.1.1",
591            "REQUEST": "GetLegendGraphic",
592            "LAYER": "Country,Hello,db_point",
593            "LAYERTITLE": "FALSE",
594            "RULELABEL": "FALSE",
595            "FORMAT": "image/png",
596            "HEIGHT": "500",
597            "WIDTH": "500",
598            "BBOX": "-76.08,-6.4,-19.38,38.04",
599            "SRS": "EPSG:4326"
600        }.items())])
601
602        r, h = self._result(self._execute_request(qs))
603        self._img_diff_error(r, h, "WMS_GetLegendGraphic_BBox2")
604
605    def test_wms_GetLegendGraphic_EmptyLegend(self):
606        qs = "?" + "&".join(["%s=%s" % i for i in list({
607            "MAP": self.testdata_path + 'test_project_contextual_legend.qgs',
608            "SERVICE": "WMS",
609            "VERSION": "1.1.1",
610            "REQUEST": "GetLegendGraphic",
611            "LAYER": "QGIS%20Server%20Hello%20World",
612            "FORMAT": "image/png",
613            "SRCHEIGHT": "840",
614            "SRCWIDTH": "1226",
615            "BBOX": "10.38450,-49.6370,73.8183,42.9461",
616            "SRS": "EPSG:4326",
617            "SCALE": "15466642"
618        }.items())])
619
620        h, r = self._execute_request(qs)
621        self.assertEqual(-1, h.find(b'Content-Type: text/xml; charset=utf-8'), "Header: %s\nResponse:\n%s" % (h, r))
622        self.assertNotEqual(-1, h.find(b'Content-Type: image/png'), "Header: %s\nResponse:\n%s" % (h, r))
623
624    def test_wms_GetLegendGraphic_wmsRootName(self):
625        """Test an unreported issue when a wmsRootName short name is set in the service capabilities"""
626
627        # First test with the project title itself:
628        qs = "?" + "&".join(["%s=%s" % i for i in list({
629            "MAP": self.testdata_path + 'test_project_wms_grouped_layers.qgs',
630            "SERVICE": "WMS",
631            "VERSION": "1.1.1",
632            "REQUEST": "GetLegendGraphic",
633            "LAYER": "QGIS%20Server%20-%20Grouped%20Layer",
634            "FORMAT": "image/png",
635            "SRCHEIGHT": "840",
636            "SRCWIDTH": "1226",
637            "BBOX": "609152,5808188,625492,5814318",
638            "SRS": "EPSG:25832",
639            "SCALE": "38976"
640        }.items())])
641
642        h, r = self._execute_request(qs)
643        self.assertEqual(-1, h.find(b'Content-Type: text/xml; charset=utf-8'), "Header: %s\nResponse:\n%s" % (h, r))
644        self.assertNotEqual(-1, h.find(b'Content-Type: image/png'), "Header: %s\nResponse:\n%s" % (h, r))
645
646        # Then test with the wmsRootName short name:
647        qs = "?" + "&".join(["%s=%s" % i for i in list({
648            "MAP": self.testdata_path + 'test_project_wms_grouped_layers_wmsroot.qgs',
649            "SERVICE": "WMS",
650            "VERSION": "1.1.1",
651            "REQUEST": "GetLegendGraphic",
652            "LAYER": "All_grouped_layers",
653            "FORMAT": "image/png",
654            "SRCHEIGHT": "840",
655            "SRCWIDTH": "1226",
656            "BBOX": "609152,5808188,625492,5814318",
657            "SRS": "EPSG:25832",
658            "SCALE": "38976"
659        }.items())])
660
661        h, r = self._execute_request(qs)
662        self.assertEqual(-1, h.find(b'Content-Type: text/xml; charset=utf-8'), "Header: %s\nResponse:\n%s" % (h, r))
663        self.assertNotEqual(-1, h.find(b'Content-Type: image/png'), "Header: %s\nResponse:\n%s" % (h, r))
664
665    def test_wms_GetLegendGraphic_ScaleSymbol_Min(self):
666        # 1:500000000 min
667        qs = "?" + "&".join(["%s=%s" % i for i in list({
668            "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs',
669            "SERVICE": "WMS",
670            "REQUEST": "GetLegendGraphic",
671            "LAYER": "testlayer",
672            "FORMAT": "image/png",
673            "SRCHEIGHT": "550",
674            "SRCWIDTH": "850",
675            "BBOX": "-608.4,-1002.6,698.2,1019.0",
676            "CRS": "EPSG:4326"
677        }.items())])
678
679        r, h = self._result(self._execute_request(qs))
680        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Min", max_size_diff=QSize(1, 1))
681
682        # 1:1000000000 min
683        qs = "?" + "&".join(["%s=%s" % i for i in list({
684            "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs',
685            "SERVICE": "WMS",
686            "REQUEST": "GetLegendGraphic",
687            "LAYER": "testlayer",
688            "FORMAT": "image/png",
689            "SRCHEIGHT": "550",
690            "SRCWIDTH": "850",
691            "BBOX": "-1261.7,-2013.5,1351.5,2029.9",
692            "CRS": "EPSG:4326"
693        }.items())])
694
695        r, h = self._result(self._execute_request(qs))
696        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Min", max_size_diff=QSize(15, 15))
697
698    def test_wms_GetLegendGraphic_ScaleSymbol_Scaled_01(self):
699        # 1:10000000 scaled
700        qs = "?" + "&".join(["%s=%s" % i for i in list({
701            "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs',
702            "SERVICE": "WMS",
703            "REQUEST": "GetLegendGraphic",
704            "LAYER": "testlayer",
705            "FORMAT": "image/png",
706            "SRCHEIGHT": "550",
707            "SRCWIDTH": "850",
708            "BBOX": "31.8,-12.0,58.0,28.4",
709            "CRS": "EPSG:4326"
710        }.items())])
711
712        r, h = self._result(self._execute_request(qs))
713        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Scaled_01", max_size_diff=QSize(15, 15))
714
715    def test_wms_GetLegendGraphic_ScaleSymbol_Scaled_02(self):
716        # 1:15000000 scaled
717        qs = "?" + "&".join(["%s=%s" % i for i in list({
718            "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs',
719            "SERVICE": "WMS",
720            "REQUEST": "GetLegendGraphic",
721            "LAYER": "testlayer",
722            "FORMAT": "image/png",
723            "SRCHEIGHT": "550",
724            "SRCWIDTH": "850",
725            "BBOX": "25.3,-22.1,64.5,38.5",
726            "CRS": "EPSG:4326"
727        }.items())])
728
729        r, h = self._result(self._execute_request(qs))
730        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Scaled_02", max_size_diff=QSize(15, 15))
731
732    def test_wms_GetLegendGraphic_ScaleSymbol_Max(self):
733        # 1:100000 max
734        qs = "?" + "&".join(["%s=%s" % i for i in list({
735            "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs',
736            "SERVICE": "WMS",
737            "REQUEST": "GetLegendGraphic",
738            "LAYER": "testlayer",
739            "FORMAT": "image/png",
740            "SRCHEIGHT": "550",
741            "SRCWIDTH": "850",
742            "BBOX": "44.8,8.0,45.0,8.4",
743            "CRS": "EPSG:4326"
744        }.items())])
745
746        r, h = self._result(self._execute_request(qs))
747        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Max", max_size_diff=QSize(15, 15))
748
749        # 1:1000000 max
750        qs = "?" + "&".join(["%s=%s" % i for i in list({
751            "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs',
752            "SERVICE": "WMS",
753            "REQUEST": "GetLegendGraphic",
754            "LAYER": "testlayer",
755            "FORMAT": "image/png",
756            "SRCHEIGHT": "550",
757            "SRCWIDTH": "850",
758            "BBOX": "43.6,6.2,46.2,10.2",
759            "CRS": "EPSG:4326"
760        }.items())])
761
762        r, h = self._result(self._execute_request(qs))
763        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Max", max_size_diff=QSize(15, 15))
764
765    def test_wms_GetLegendGraphic_ScaleSymbol_DefaultMapUnitsPerMillimeter(self):
766        # map units per mm on 1:20000000 with SRCHEIGHT=598&SRCWIDTH=1640&BBOX=16.5,-69.7,73.3,86.1 would be around what is set as default: 0.359 map units per mm
767        qs = "?" + "&".join(["%s=%s" % i for i in list({
768            "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs',
769            "SERVICE": "WMS",
770            "REQUEST": "GetLegendGraphic",
771            "LAYER": "testlayer",
772            "FORMAT": "image/png",
773            "CRS": "EPSG:4326"
774        }.items())])
775
776        r, h = self._result(self._execute_request(qs))
777        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_DefaultMapUnitsPerMillimeter",
778                             max_size_diff=QSize(15, 15))
779
780    def test_wms_GetLegendGraphic_ScaleSymbol_Scaled_2056(self):
781        # 1:1000 scale on an EPSG:2056 calculating DPI that is around 96
782        qs = "?" + "&".join(["%s=%s" % i for i in list({
783            "MAP": self.testdata_path + 'test_project_scaledsymbols_2056.qgs',
784            "SERVICE": "WMS",
785            "REQUEST": "GetLegendGraphic",
786            "LAYER": "testlayer_2056",
787            "FORMAT": "image/png",
788            "SRCHEIGHT": "600",
789            "SRCWIDTH": "1500",
790            "BBOX": "2662610.7,1268841.8,2663010.5,1269000.05",
791            "CRS": "EPSG:2056"
792        }.items())])
793
794        r, h = self._result(self._execute_request(qs))
795        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Scaled_2056", max_size_diff=QSize(15, 15))
796
797    def test_wms_GetLegendGraphic_ScaleSymbol_DefaultScale_2056(self):
798        # 1:1000 as default value - it's not exactly the same result than passing the bbox and size because of exact DPI 96 (default)
799        qs = "?" + "&".join(["%s=%s" % i for i in list({
800            "MAP": self.testdata_path + 'test_project_scaledsymbols_2056.qgs',
801            "SERVICE": "WMS",
802            "REQUEST": "GetLegendGraphic",
803            "LAYER": "testlayer_2056",
804            "FORMAT": "image/png",
805            "CRS": "EPSG:2056"
806        }.items())])
807
808        r, h = self._result(self._execute_request(qs))
809        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_DefaultScale_2056", max_size_diff=QSize(15, 15))
810
811    def test_wms_GetLegendGraphic_LAYERFONTCOLOR(self):
812        qs = "?" + "&".join(["%s=%s" % i for i in list({
813            "MAP": urllib.parse.quote(self.projectPath),
814            "SERVICE": "WMS",
815            "VERSION": "1.1.1",
816            "REQUEST": "GetLegendGraphic",
817            "LAYER": "Country,Hello",
818            "FORMAT": "image/png",
819            "HEIGHT": "500",
820            "WIDTH": "500",
821            "CRS": "EPSG:3857",
822            "LAYERFONTCOLOR": "red"
823        }.items())])
824
825        r, h = self._result(self._execute_request(qs))
826        self._img_diff_error(r, h, "WMS_GetLegendGraphic_LAYERFONTCOLOR", max_size_diff=QSize(10, 2))
827
828    def test_wms_GetLegendGraphic_ITEMFONTCOLOR(self):
829        qs = "?" + "&".join(["%s=%s" % i for i in list({
830            "MAP": urllib.parse.quote(self.projectPath),
831            "SERVICE": "WMS",
832            "VERSION": "1.1.1",
833            "REQUEST": "GetLegendGraphic",
834            "LAYER": "Country,Hello",
835            "FORMAT": "image/png",
836            "HEIGHT": "500",
837            "WIDTH": "500",
838            "CRS": "EPSG:3857",
839            "ITEMFONTCOLOR": "red",
840        }.items())])
841
842        r, h = self._result(self._execute_request(qs))
843        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR", max_size_diff=QSize(10, 2))
844
845    def test_wms_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR(self):
846        qs = "?" + "&".join(["%s=%s" % i for i in list({
847            "MAP": urllib.parse.quote(self.projectPath),
848            "SERVICE": "WMS",
849            "VERSION": "1.1.1",
850            "REQUEST": "GetLegendGraphic",
851            "LAYER": "Country,Hello",
852            "FORMAT": "image/png",
853            "HEIGHT": "500",
854            "WIDTH": "500",
855            "CRS": "EPSG:3857",
856            "ITEMFONTCOLOR": "red",
857            "LAYERFONTCOLOR": "blue"
858        }.items())])
859
860        r, h = self._result(self._execute_request(qs))
861        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR", max_size_diff=QSize(10, 2))
862
863    def test_wms_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR_hex(self):
864        qs = "?" + "&".join(["%s=%s" % i for i in list({
865            "MAP": urllib.parse.quote(self.projectPath),
866            "SERVICE": "WMS",
867            "VERSION": "1.1.1",
868            "REQUEST": "GetLegendGraphic",
869            "LAYER": "Country,Hello",
870            "FORMAT": "image/png",
871            "HEIGHT": "500",
872            "WIDTH": "500",
873            "CRS": "EPSG:3857",
874            "ITEMFONTCOLOR": r"%23FF0000",
875            "LAYERFONTCOLOR": r"%230000FF"
876        }.items())])
877
878        r, h = self._result(self._execute_request(qs))
879        self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR", max_size_diff=QSize(10, 2))
880
881    def test_BBoxNoWidthNoHeight(self):
882        """Test with BBOX and no width/height (like QGIS client does)"""
883
884        qs = "?" + "&".join(["%s=%s" % i for i in list({
885            "MAP": self.testdata_path + 'test_project_wms_grouped_nested_layers.qgs',
886            "SERVICE": "WMS",
887            "VERSION": "1.3",
888            "REQUEST": "GetLegendGraphic",
889            "LAYER": "areas%20and%20symbols",
890            "FORMAT": "image/png",
891            "CRS": "EPSG:4326",
892            "BBOX": "52.44462990911360123,10.6723591605239374,52.44631832182876963,10.6795952150175264",
893            "SLD_VERSION": "1.1",
894        }.items())])
895
896        r, h = self._result(self._execute_request(qs))
897        self.assertFalse(b'Exception' in r)
898        self._img_diff_error(r, h, "WMS_GetLegendGraphic_NoWidthNoHeight", max_size_diff=QSize(10, 2))
899
900    def testGetLegendGraphicRegression32020(self):
901        """When two classes have the same symbol they both are shown in the contextual
902        legend even if just one is actually visible in the map extent
903
904        This test also checks for corner cases (literally) and reprojection.
905        """
906
907        # Visible is "Type 1"
908        qs = "?" + "&".join(["%s=%s" % i for i in list({
909            "MAP": self.testdata_path + 'bug_gh32020.qgs',
910            "SERVICE": "WMS",
911            "VERSION": "1.3",
912            "REQUEST": "GetLegendGraphic",
913            "LAYER": "test_layer",
914            "FORMAT": "image/png",
915            "CRS": "EPSG:4326",
916            "BBOX": "0.05148830809982496426,-2.237691019614711507,0.8090701330998248952,-0.2050896957968479928",
917            "SLD_VERSION": "1.1",
918        }.items())])
919
920        r, h = self._result(self._execute_request(qs))
921        self.assertFalse(b'Exception' in r)
922        self._img_diff_error(r, h, "WMS_GetLegendGraphic_Regression32020_type1", max_size_diff=QSize(10, 2))
923
924        # Visible is "Type 2"
925        qs = "?" + "&".join(["%s=%s" % i for i in list({
926            "MAP": self.testdata_path + 'bug_gh32020.qgs',
927            "SERVICE": "WMS",
928            "VERSION": "1.3",
929            "REQUEST": "GetLegendGraphic",
930            "LAYER": "test_layer",
931            "FORMAT": "image/png",
932            "CRS": "EPSG:4326",
933            "BBOX": "0.02893333257443075901,-0.2568334631786342026,1.544096982574430621,3.808369184457092604",
934            "SLD_VERSION": "1.1",
935        }.items())])
936
937        r, h = self._result(self._execute_request(qs))
938        self.assertFalse(b'Exception' in r)
939        self._img_diff_error(r, h, "WMS_GetLegendGraphic_Regression32020_type2", max_size_diff=QSize(10, 2))
940
941        # Visible is "Type 2" and 3
942        qs = "?" + "&".join(["%s=%s" % i for i in list({
943            "MAP": self.testdata_path + 'bug_gh32020.qgs',
944            "SERVICE": "WMS",
945            "VERSION": "1.3",
946            "REQUEST": "GetLegendGraphic",
947            "LAYER": "test_layer",
948            "FORMAT": "image/png",
949            "CRS": "EPSG:4326",
950            "BBOX": "-0.6636370923817864753,-0.2886757815674259042,0.8515265576182133866,3.776526866068300681",
951            "SLD_VERSION": "1.1",
952        }.items())])
953
954        r, h = self._result(self._execute_request(qs))
955        self.assertFalse(b'Exception' in r)
956        self._img_diff_error(r, h, "WMS_GetLegendGraphic_Regression32020_type2_and_3", max_size_diff=QSize(10, 2))
957
958        # Visible is "Type 1" and 3
959        qs = "?" + "&".join(["%s=%s" % i for i in list({
960            "MAP": self.testdata_path + 'bug_gh32020.qgs',
961            "SERVICE": "WMS",
962            "VERSION": "1.3",
963            "REQUEST": "GetLegendGraphic",
964            "LAYER": "test_layer",
965            "FORMAT": "image/png",
966            "CRS": "EPSG:4326",
967            "BBOX": "-0.5787242433450088264,-4.316729057749563836,0.9364394066549910356,-0.2515264101138368069",
968            "SLD_VERSION": "1.1",
969        }.items())])
970
971        r, h = self._result(self._execute_request(qs))
972        self.assertFalse(b'Exception' in r)
973        self._img_diff_error(r, h, "WMS_GetLegendGraphic_Regression32020_type1_and_3", max_size_diff=QSize(10, 2))
974
975        # Change CRS: 3857
976        # Visible is "Type 2"
977        qs = "?" + "&".join(["%s=%s" % i for i in list({
978            "MAP": self.testdata_path + 'bug_gh32020.qgs',
979            "SERVICE": "WMS",
980            "VERSION": "1.3",
981            "REQUEST": "GetLegendGraphic",
982            "LAYER": "test_layer",
983            "FORMAT": "image/png",
984            "CRS": "EPSG:3857",
985            "BBOX": "-28147.15420315234223,3960.286488616475253,424402.4530122592696,172632.4964886165108",
986            "SLD_VERSION": "1.1",
987        }.items())])
988
989        r, h = self._result(self._execute_request(qs))
990        self.assertFalse(b'Exception' in r)
991        self._img_diff_error(r, h, "WMS_GetLegendGraphic_Regression32020_type2_3857", max_size_diff=QSize(10, 2))
992
993    def test_wms_GetLegendGraphic_JSON(self):
994        self.wms_request_compare("GetLegendGraphic",
995                                 "&LAYERS=testlayer%20%C3%A8%C3%A9"
996                                 "&FORMAT=application/json",
997                                 "wms_getlegendgraphic_json")
998
999    def test_wms_GetLegendGraphic_JSON_multiple_layers(self):
1000        self.wms_request_compare("GetLegendGraphic",
1001                                 "&LAYERS=testlayer%20%C3%A8%C3%A9,testlayer3"
1002                                 "&FORMAT=application/json",
1003                                 "wms_getlegendgraphic_json_multiple_layers")
1004
1005    def test_wms_GetLegendGraphic_JSON_multiple_symbol(self):
1006        self.wms_request_compare("GetLegendGraphic",
1007                                 "&LAYERS=cdb_lines"
1008                                 "&FORMAT=application/json",
1009                                 "wms_getlegendgraphic_json_multiple_symbol",
1010                                 'test_project_wms_grouped_layers.qgs')
1011
1012
1013if __name__ == '__main__':
1014    unittest.main()
1015