diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt
index 70963f0a595..1538ffa6e9b 100644
--- a/tests/src/python/CMakeLists.txt
+++ b/tests/src/python/CMakeLists.txt
@@ -63,6 +63,7 @@ ADD_PYTHON_TEST(PyQgsGraduatedSymbolRenderer test_qgsgraduatedsymbolrenderer.py)
ADD_PYTHON_TEST(PyQgsInterval test_qgsinterval.py)
ADD_PYTHON_TEST(PyQgsJSONUtils test_qgsjsonutils.py)
ADD_PYTHON_TEST(PyQgsLineSymbolLayers test_qgslinesymbollayers.py)
+ADD_PYTHON_TEST(PyQgsMapCanvas test_qgsmapcanvas.py)
ADD_PYTHON_TEST(PyQgsMapCanvasAnnotationItem test_qgsmapcanvasannotationitem.py)
ADD_PYTHON_TEST(PyQgsMapLayerModel test_qgsmaplayermodel.py)
ADD_PYTHON_TEST(PyQgsMapRenderer test_qgsmaprenderer.py)
diff --git a/tests/src/python/test_qgsmapcanvas.py b/tests/src/python/test_qgsmapcanvas.py
new file mode 100644
index 00000000000..a739dc69b26
--- /dev/null
+++ b/tests/src/python/test_qgsmapcanvas.py
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+"""QGIS Unit tests for QgsMapCanvas
+
+.. note:: This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+"""
+__author__ = 'Nyall Dawson'
+__date__ = '24/1/2017'
+__copyright__ = 'Copyright 2017, The QGIS Project'
+# This will get replaced with a git SHA1 when you do a git archive
+__revision__ = '$Format:%H$'
+
+import qgis # NOQA
+
+from qgis.core import (QgsMapSettings,
+ QgsCoordinateReferenceSystem,
+ QgsRectangle,
+ QgsVectorLayer,
+ QgsFeature,
+ QgsGeometry,
+ QgsMultiRenderChecker,
+ QgsApplication)
+from qgis.gui import (QgsMapCanvas)
+
+from qgis.PyQt.QtCore import (Qt,
+ QDir)
+import time
+from qgis.testing import start_app, unittest
+
+app = start_app()
+
+
+class TestQgsMapCanvas(unittest.TestCase):
+
+ def setUp(self):
+ self.report = "
Python QgsMapCanvas Tests
\n"
+
+ def tearDown(self):
+ report_file_path = "%s/qgistest.html" % QDir.tempPath()
+ with open(report_file_path, 'a') as report_file:
+ report_file.write(self.report)
+
+ def testDeferredUpdate(self):
+ """ test that map canvas doesn't auto refresh on deferred layer update """
+ canvas = QgsMapCanvas()
+ canvas.setDestinationCrs(QgsCoordinateReferenceSystem(4326))
+ canvas.setFrameStyle(0)
+ canvas.resize(600, 400)
+ self.assertEqual(canvas.width(), 600)
+ self.assertEqual(canvas.height(), 400)
+
+ layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string",
+ "layer", "memory")
+
+ canvas.setLayers([layer])
+ canvas.setExtent(QgsRectangle(10, 30, 20, 35))
+ canvas.show()
+
+ # need to wait until first redraw can occur (note that we first need to wait till drawing starts!)
+ while not canvas.isDrawing():
+ app.processEvents()
+ while canvas.isDrawing():
+ app.processEvents()
+
+ self.assertTrue(self.canvasImageCheck('empty_canvas', 'empty_canvas', canvas))
+
+ # add polygon to layer
+ f = QgsFeature()
+ f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45)))
+ self.assertTrue(layer.dataProvider().addFeatures([f]))
+
+ # deferred update - so expect that canvas will not been refreshed
+ layer.triggerRepaint(True)
+ timeout = time.time() + 0.1
+ while time.time() < timeout:
+ # messy, but only way to check that canvas redraw doesn't occur
+ self.assertFalse(canvas.isDrawing())
+ # canvas should still be empty
+ self.assertTrue(self.canvasImageCheck('empty_canvas', 'empty_canvas', canvas))
+
+ # refresh canvas
+ canvas.refresh()
+ while not canvas.isDrawing():
+ app.processEvents()
+ while canvas.isDrawing():
+ app.processEvents()
+
+ # now we expect the canvas check to fail (since they'll be a new polygon rendered over it)
+ self.assertFalse(self.canvasImageCheck('empty_canvas', 'empty_canvas', canvas))
+
+ def canvasImageCheck(self, name, reference_image, canvas):
+ self.report += "Render {}
\n".format(name)
+ temp_dir = QDir.tempPath() + '/'
+ file_name = temp_dir + 'mapcanvas_' + name + ".png"
+ print(file_name)
+ canvas.saveAsImage(file_name)
+ checker = QgsMultiRenderChecker()
+ checker.setControlPathPrefix("mapcanvas")
+ checker.setControlName("expected_" + reference_image)
+ checker.setRenderedImage(file_name)
+ checker.setColorTolerance(2)
+ result = checker.runTest(name, 20)
+ self.report += checker.report()
+ print((self.report))
+ return result
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/src/python/test_qgsmaprenderercache.py b/tests/src/python/test_qgsmaprenderercache.py
index 2e438b88246..1b6757c5a59 100644
--- a/tests/src/python/test_qgsmaprenderercache.py
+++ b/tests/src/python/test_qgsmaprenderercache.py
@@ -116,6 +116,13 @@ class TestQgsMapRendererCache(unittest.TestCase):
self.assertFalse(cache.hasCacheImage('xxx'))
QgsProject.instance().removeMapLayer(layer.id())
+ # test that cache is also cleared on deferred update
+ layer = QgsVectorLayer("Point?field=fldtxt:string",
+ "layer", "memory")
+ cache.setCacheImage('xxx', im, [layer])
+ layer.triggerRepaint(True)
+ self.assertFalse(cache.hasCacheImage('xxx'))
+
def testRequestRepaintMultiple(self):
""" test requesting repaint with multiple dependent layers """
layer1 = QgsVectorLayer("Point?field=fldtxt:string",
diff --git a/tests/testdata/control_images/mapcanvas/expected_empty_canvas/expected_empty_canvas.png b/tests/testdata/control_images/mapcanvas/expected_empty_canvas/expected_empty_canvas.png
new file mode 100644
index 00000000000..5bf1a4d0bad
Binary files /dev/null and b/tests/testdata/control_images/mapcanvas/expected_empty_canvas/expected_empty_canvas.png differ