From 60a28e32b7591979b21e03fbe2e41dd876b69ea1 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 20 Dec 2017 08:17:45 +1000 Subject: [PATCH] Add some unit tests --- python/core/layout/qgslayoutatlas.sip | 13 ++- src/core/layout/qgslayoutatlas.cpp | 18 ++- src/core/layout/qgslayoutatlas.h | 10 +- tests/src/python/test_qgslayoutatlas.py | 144 +++++++++++++++++++++++- 4 files changed, 172 insertions(+), 13 deletions(-) diff --git a/python/core/layout/qgslayoutatlas.sip b/python/core/layout/qgslayoutatlas.sip index d68bfdfa234..38e742b44ec 100644 --- a/python/core/layout/qgslayoutatlas.sip +++ b/python/core/layout/qgslayoutatlas.sip @@ -78,7 +78,7 @@ atlas page. .. seealso:: :py:func:`setFilenameExpression()` -.. seealso:: :py:func:`filenameExpressionErrorString()` +.. seealso:: :py:func:`currentFilename()` %End bool setFilenameExpression( const QString &expression, QString &errorString /Out/ ); @@ -89,6 +89,17 @@ If an invalid expression is passed, false will be returned and ``errorString`` will be set to the expression error. .. seealso:: :py:func:`filenameExpression()` + +.. seealso:: :py:func:`currentFilename()` +%End + + QString currentFilename() const; +%Docstring +Returns the current feature filename. + +.. seealso:: :py:func:`filenameExpression()` + +.. seealso:: :py:func:`setFilenameExpression()` %End QgsVectorLayer *coverageLayer() const; diff --git a/src/core/layout/qgslayoutatlas.cpp b/src/core/layout/qgslayoutatlas.cpp index 19d7bd1ab40..f39fe25afb5 100644 --- a/src/core/layout/qgslayoutatlas.cpp +++ b/src/core/layout/qgslayoutatlas.cpp @@ -394,6 +394,11 @@ bool QgsLayoutAtlas::setFilenameExpression( const QString &pattern, QString &err return updateFilenameExpression( errorString ); } +QString QgsLayoutAtlas::currentFilename() const +{ + return mCurrentFilename; +} + QgsExpressionContext QgsLayoutAtlas::createExpressionContext() { QgsExpressionContext expressionContext; @@ -408,10 +413,9 @@ QgsExpressionContext QgsLayoutAtlas::createExpressionContext() if ( mCoverageLayer ) expressionContext.lastScope()->setFields( mCoverageLayer->fields() ); -#if 0 //TODO + if ( mLayout && mEnabled ) expressionContext.lastScope()->setFeature( mCurrentFeature ); -#endif return expressionContext; } @@ -440,13 +444,8 @@ bool QgsLayoutAtlas::updateFilenameExpression( QString &error ) mFilenameExpression.prepare( &expressionContext ); } -#if 0 //TODO - //if atlas preview is currently enabled, regenerate filename for current feature - if ( mComposition->atlasMode() == QgsComposition::PreviewAtlas ) - { - evalFeatureFilename( expressionContext ); - } -#endif + // regenerate current filename + evalFeatureFilename( expressionContext ); return true; } @@ -496,7 +495,6 @@ bool QgsLayoutAtlas::prepareForFeature( const int featureI ) // generate filename for current feature if ( !evalFeatureFilename( expressionContext ) ) { - //error evaluating filename return false; } diff --git a/src/core/layout/qgslayoutatlas.h b/src/core/layout/qgslayoutatlas.h index 46378972277..c2c1ba8aa43 100644 --- a/src/core/layout/qgslayoutatlas.h +++ b/src/core/layout/qgslayoutatlas.h @@ -77,7 +77,7 @@ class CORE_EXPORT QgsLayoutAtlas : public QObject, public QgsAbstractLayoutItera * Returns the filename expression used for generating output filenames for each * atlas page. * \see setFilenameExpression() - * \see filenameExpressionErrorString() + * \see currentFilename() */ QString filenameExpression() const { return mFilenameExpressionString; } @@ -87,9 +87,17 @@ class CORE_EXPORT QgsLayoutAtlas : public QObject, public QgsAbstractLayoutItera * If an invalid expression is passed, false will be returned and \a errorString * will be set to the expression error. * \see filenameExpression() + * \see currentFilename() */ bool setFilenameExpression( const QString &expression, QString &errorString SIP_OUT ); + /** + * Returns the current feature filename. + * \see filenameExpression() + * \see setFilenameExpression() + */ + QString currentFilename() const; + /** * Returns the coverage layer used for the atlas features. * \see setCoverageLayer() diff --git a/tests/src/python/test_qgslayoutatlas.py b/tests/src/python/test_qgslayoutatlas.py index 9310c3edb53..12cbfdabf22 100644 --- a/tests/src/python/test_qgslayoutatlas.py +++ b/tests/src/python/test_qgslayoutatlas.py @@ -43,6 +43,7 @@ from qgis.PyQt.QtTest import QSignalSpy from qgis.PyQt.QtXml import QDomDocument from utilities import unitTestDataPath from qgis.testing import start_app, unittest +from qgis.PyQt.QtTest import QSignalSpy start_app() @@ -86,7 +87,148 @@ class TestQgsLayoutAtlas(unittest.TestCase): self.assertTrue(atlas2.filterFeatures()) self.assertEqual(atlas2.filterExpression(), 'filter exp') - def test + def testIteration(self): + p = QgsProject() + vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") + vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + self.assertTrue(vector_layer.isValid()) + p.addMapLayer(vector_layer) + + l = QgsPrintLayout(p) + atlas = l.atlas() + atlas.setEnabled(True) + atlas.setCoverageLayer(vector_layer) + + atlas_feature_changed_spy = QSignalSpy(atlas.featureChanged) + context_changed_spy = QSignalSpy(l.context().changed) + + self.assertTrue(atlas.beginRender()) + self.assertTrue(atlas.first()) + self.assertEqual(len(atlas_feature_changed_spy), 1) + self.assertEqual(len(context_changed_spy), 1) + self.assertEqual(atlas.currentFeatureNumber(), 0) + self.assertEqual(l.context().feature()[4], 'Basse-Normandie') + self.assertEqual(l.context().layer(), vector_layer) + + self.assertTrue(atlas.next()) + self.assertEqual(len(atlas_feature_changed_spy), 2) + self.assertEqual(len(context_changed_spy), 2) + self.assertEqual(atlas.currentFeatureNumber(), 1) + self.assertEqual(l.context().feature()[4], 'Bretagne') + + self.assertTrue(atlas.next()) + self.assertEqual(len(atlas_feature_changed_spy), 3) + self.assertEqual(len(context_changed_spy), 3) + self.assertEqual(atlas.currentFeatureNumber(), 2) + self.assertEqual(l.context().feature()[4], 'Pays de la Loire') + + self.assertTrue(atlas.next()) + self.assertEqual(len(atlas_feature_changed_spy), 4) + self.assertEqual(len(context_changed_spy), 4) + self.assertEqual(atlas.currentFeatureNumber(), 3) + self.assertEqual(l.context().feature()[4], 'Centre') + + self.assertFalse(atlas.next()) + self.assertTrue(atlas.seekTo(2)) + self.assertEqual(len(atlas_feature_changed_spy), 5) + self.assertEqual(len(context_changed_spy), 5) + self.assertEqual(atlas.currentFeatureNumber(), 2) + self.assertEqual(l.context().feature()[4], 'Pays de la Loire') + + self.assertTrue(atlas.last()) + self.assertEqual(len(atlas_feature_changed_spy), 6) + self.assertEqual(len(context_changed_spy), 6) + self.assertEqual(atlas.currentFeatureNumber(), 3) + self.assertEqual(l.context().feature()[4], 'Centre') + + self.assertTrue(atlas.previous()) + self.assertEqual(len(atlas_feature_changed_spy), 7) + self.assertEqual(len(context_changed_spy), 7) + self.assertEqual(atlas.currentFeatureNumber(), 2) + self.assertEqual(l.context().feature()[4], 'Pays de la Loire') + + self.assertTrue(atlas.previous()) + self.assertTrue(atlas.previous()) + self.assertEqual(len(atlas_feature_changed_spy), 9) + self.assertFalse(atlas.previous()) + self.assertEqual(len(atlas_feature_changed_spy), 9) + + self.assertTrue(atlas.endRender()) + self.assertEqual(len(atlas_feature_changed_spy), 10) + + def testUpdateFeature(self): + p = QgsProject() + vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") + vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + self.assertTrue(vector_layer.isValid()) + p.addMapLayer(vector_layer) + + l = QgsPrintLayout(p) + atlas = l.atlas() + atlas.setEnabled(True) + atlas.setCoverageLayer(vector_layer) + + self.assertTrue(atlas.beginRender()) + self.assertTrue(atlas.first()) + self.assertEqual(atlas.currentFeatureNumber(), 0) + self.assertEqual(l.context().feature()[4], 'Basse-Normandie') + self.assertEqual(l.context().layer(), vector_layer) + + vector_layer.startEditing() + self.assertTrue(vector_layer.changeAttributeValue(l.context().feature().id(), 4, 'Nah, Canberra mate!')) + self.assertEqual(l.context().feature()[4], 'Basse-Normandie') + l.atlas().refreshCurrentFeature() + self.assertEqual(l.context().feature()[4], 'Nah, Canberra mate!') + vector_layer.rollBack() + + def testFileName(self): + p = QgsProject() + vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") + vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + self.assertTrue(vector_layer.isValid()) + p.addMapLayer(vector_layer) + + l = QgsPrintLayout(p) + atlas = l.atlas() + atlas.setEnabled(True) + atlas.setCoverageLayer(vector_layer) + atlas.setFilenameExpression("'output_' || \"NAME_1\"") + + self.assertTrue(atlas.beginRender()) + self.assertEqual(atlas.count(), 4) + atlas.first() + self.assertEqual(atlas.currentFilename(), 'output_Basse-Normandie') + atlas.next() + self.assertEqual(atlas.currentFilename(), 'output_Bretagne') + atlas.next() + self.assertEqual(atlas.currentFilename(), 'output_Pays de la Loire') + atlas.next() + self.assertEqual(atlas.currentFilename(), 'output_Centre') + + # try changing expression, filename should be updated instantly + atlas.setFilenameExpression("'export_' || \"NAME_1\"") + self.assertEqual(atlas.currentFilename(), 'export_Centre') + + atlas.endRender() + + def testNameForPage(self): + p = QgsProject() + vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") + vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + self.assertTrue(vector_layer.isValid()) + p.addMapLayer(vector_layer) + + l = QgsPrintLayout(p) + atlas = l.atlas() + atlas.setEnabled(True) + atlas.setCoverageLayer(vector_layer) + atlas.setPageNameExpression("\"NAME_1\"") + + self.assertTrue(atlas.beginRender()) + self.assertEqual(atlas.nameForPage(0), 'Basse-Normandie') + self.assertEqual(atlas.nameForPage(1), 'Bretagne') + self.assertEqual(atlas.nameForPage(2), 'Pays de la Loire') + self.assertEqual(atlas.nameForPage(3), 'Centre') if __name__ == '__main__':