diff --git a/.gitignore b/.gitignore index 4b61866b3377..31c8f9267358 100644 --- a/.gitignore +++ b/.gitignore @@ -105,6 +105,8 @@ tests/testdata/raster/band3_float32_noct_epsg4326.tif.aux.xml tests/testdata/raster/band3_int16_noct_epsg4326.tif.aux.xml tests/testdata/tenbytenraster.asc.aux.xml tests/testdata/test_plugin_path/plugin_started.txt +tests/testdata/test_qgis_config_path/profiles/default/* +!tests/testdata/test_qgis_config_path/profiles/default/python tests/testdata/widget_config.qlr tests/testdata/zip/testtar.tgz.properties venv diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index bf8511ddad11..1db55d1f87d4 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -2761,6 +2761,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow friend class TestQgisAppPython; friend class TestQgisApp; + friend class TestQgsProjectExpressions; friend class QgisAppInterface; friend class QgsAppScreenShots; }; diff --git a/tests/src/app/CMakeLists.txt b/tests/src/app/CMakeLists.txt index 1cedc22e87e2..8c20fdddc9ed 100644 --- a/tests/src/app/CMakeLists.txt +++ b/tests/src/app/CMakeLists.txt @@ -63,6 +63,7 @@ endif() if (WITH_BINDINGS) set(TESTS ${TESTS} testqgisapppython.cpp) + set(TESTS ${TESTS} testqgsprojectexpressions.cpp) endif() foreach(TESTSRC ${TESTS}) diff --git a/tests/src/app/testqgsprojectexpressions.cpp b/tests/src/app/testqgsprojectexpressions.cpp new file mode 100644 index 000000000000..24fd093392f8 --- /dev/null +++ b/tests/src/app/testqgsprojectexpressions.cpp @@ -0,0 +1,109 @@ +/*************************************************************************** + testqgsprojectexpressions.cpp + -------------------- + Date : Aug 2024 + Copyright : (C) 2024 by Germán Carrillo + Email : german at opengis dot ch + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include +#include +#include +#include +#include +#include "qgstest.h" + +#include +#include + +/** + * \ingroup UnitTests + * This is a unit test for the Save Python Expression in project support. + */ +class TestQgsProjectExpressions : public QObject +{ + Q_OBJECT + + public: + TestQgsProjectExpressions(); + + private slots: + void initTestCase();// will be called before the first testfunction is executed. + void cleanupTestCase();// will be called after the last testfunction was executed. + + void projectExpressions(); + + private: + QgisApp *mQgisApp = nullptr; +}; + +TestQgsProjectExpressions::TestQgsProjectExpressions() = default; + +//runs before all tests +void TestQgsProjectExpressions::initTestCase() +{ + const QByteArray configPath = QByteArray( TEST_DATA_DIR ) + "/test_qgis_config_path"; + qputenv( "QGIS_CUSTOM_CONFIG_PATH", configPath ); + + // Set up the QgsSettings environment + QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) ); + QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) ); + QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) ); + + qDebug() << "TestQgsProjectExpressions::initTestCase()"; + // init QGIS's paths - true means that all path will be inited from prefix + QgsApplication::init(); + QgsApplication::initQgis(); + mQgisApp = new QgisApp(); + mQgisApp->loadPythonSupport(); +} + +//runs after all tests +void TestQgsProjectExpressions::cleanupTestCase() +{ + QgsApplication::exitQgis(); +} + +void TestQgsProjectExpressions::projectExpressions() +{ + const int count_before_project = QgsExpression::functionCount(); + QVERIFY( QgsExpression::functionIndex( QStringLiteral( "mychoice" ) ) != -1 ); // User expression loaded + + const QString myExpression = QStringLiteral( "mychoice(1, 2)" ); + QgsExpression exp( QStringLiteral( "mychoice(1, 2)" ) ); + QCOMPARE( exp.evaluate().toInt(), 1 ); + + // Load expressions from project + // Project registers 2 functions: mychoice (overwriting it) and myprojectfunction + const QByteArray projectPath = QByteArray( TEST_DATA_DIR ) + "/projects/test_project_functions.qgz"; + QgsProject::instance()->read( projectPath ); + QCOMPARE( QgsExpression::functionIndex( QStringLiteral( "myprojectfunction" ) ), -1 ); + QgsExpression::loadFunctionsFromProject(); + QVERIFY( QgsExpression::functionIndex( QStringLiteral( "myprojectfunction" ) ) != -1 ); + QVERIFY( QgsExpression::functionIndex( QStringLiteral( "mychoice" ) ) != -1 ); // Overwritten function + const int count_project_loaded = QgsExpression::functionCount(); + + QCOMPARE( count_project_loaded - count_before_project, 1 ); // myprojectfunction + + exp = myExpression; // Re-parse it + QCOMPARE( exp.evaluate().toInt(), 2 ); // Different result because now it's from project + + // Unload expressions from project, reload user ones + QgsExpression::cleanFunctionsFromProject(); + const int count_project_unloaded = QgsExpression::functionCount(); + QCOMPARE( count_before_project, count_project_unloaded ); // myprojectfunction is gone + + QCOMPARE( QgsExpression::functionIndex( QStringLiteral( "myprojectfunction" ) ), -1 ); + exp = myExpression; // Re-parse it + QCOMPARE( exp.evaluate().toInt(), 1 ); // Original result, coming from user function +} + + +QGSTEST_MAIN( TestQgsProjectExpressions ) +#include "testqgsprojectexpressions.moc" diff --git a/tests/testdata/projects/test_project_functions.qgz b/tests/testdata/projects/test_project_functions.qgz new file mode 100644 index 000000000000..533594fd56da Binary files /dev/null and b/tests/testdata/projects/test_project_functions.qgz differ diff --git a/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/__init__.py b/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test.py b/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test.py new file mode 100644 index 000000000000..72941c5adfdc --- /dev/null +++ b/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test.py @@ -0,0 +1,7 @@ +from qgis.core import qgsfunction + + +@qgsfunction(group='Custom', referenced_columns=[]) +def mychoice(value1, value2): + return value1 + diff --git a/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test2.py b/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test2.py new file mode 100644 index 000000000000..8bcde0850037 --- /dev/null +++ b/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test2.py @@ -0,0 +1,7 @@ +from qgis.core import qgsfunction + + +@qgsfunction(group='Custom', referenced_columns=[]) +def mychoice2(value1, value2): + return value1 + value2 +