From 930ce545a8e970ef705d3b862ac8fe7d7769b33b Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Mon, 5 Dec 2016 15:43:15 +0100 Subject: [PATCH] Fix failing tests --- .../qgsvaluerelationsearchwidgetwrapper.sip | 5 + src/CMakeLists.txt | 1 + .../fieldkit/qgsvaluerelationfieldkit.cpp | 35 +-- src/core/qgsconfigurationmap.cpp | 5 +- src/core/qgsfieldkit.h | 2 +- .../qgsvaluerelationsearchwidgetwrapper.h | 2 +- src/test/CMakeLists.txt | 7 + src/test/qgstest.h | 35 +++ tests/src/app/CMakeLists.txt | 3 +- tests/src/app/testqgsattributetable.cpp | 4 +- tests/src/gui/CMakeLists.txt | 1 + tests/src/gui/testqgsdualview.cpp | 9 +- tests/src/python/CMakeLists.txt | 1 + tests/src/python/test_qgsconfigurationmap.py | 10 +- tests/src/python/test_qgseditwidgets.py | 174 +-------------- tests/src/python/test_qgsfieldkits.py | 202 ++++++++++++++++++ tests/testdata/provider/testdata_pg.sql | 2 +- 17 files changed, 293 insertions(+), 205 deletions(-) create mode 100644 src/test/CMakeLists.txt create mode 100644 src/test/qgstest.h create mode 100644 tests/src/python/test_qgsfieldkits.py diff --git a/python/gui/editorwidgets/qgsvaluerelationsearchwidgetwrapper.sip b/python/gui/editorwidgets/qgsvaluerelationsearchwidgetwrapper.sip index c4eb8ab002b..e1c2403004f 100644 --- a/python/gui/editorwidgets/qgsvaluerelationsearchwidgetwrapper.sip +++ b/python/gui/editorwidgets/qgsvaluerelationsearchwidgetwrapper.sip @@ -28,4 +28,9 @@ class QgsValueRelationSearchWidgetWrapper : QgsSearchWidgetWrapper QWidget* createWidget( QWidget* parent ); void initWidget( QWidget* editor ); + protected slots: + void onValueChanged(); + + void setExpression( QString exp ); + }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bf504186581..087f3ba1072 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ ADD_SUBDIRECTORY(gui) ADD_SUBDIRECTORY(auth) ADD_SUBDIRECTORY(providers) ADD_SUBDIRECTORY(crssync) +ADD_SUBDIRECTORY(test) IF (WITH_DESKTOP) ADD_SUBDIRECTORY(app) diff --git a/src/core/fieldkit/qgsvaluerelationfieldkit.cpp b/src/core/fieldkit/qgsvaluerelationfieldkit.cpp index 3b8857acd5e..8c7bef5c179 100644 --- a/src/core/fieldkit/qgsvaluerelationfieldkit.cpp +++ b/src/core/fieldkit/qgsvaluerelationfieldkit.cpp @@ -47,47 +47,50 @@ QString QgsValueRelationFieldKit::representValue( QgsVectorLayer* layer, int fie Q_UNUSED( layer ) Q_UNUSED( fieldIndex ) - QHash vrCache; + QgsValueRelationFieldKit::ValueRelationCache vrCache; if ( cache.isValid() ) { - vrCache = cache.value>(); + vrCache = cache.value(); } else { - vrCache = createCache( layer, fieldIndex, config ).value>(); + vrCache = QgsValueRelationFieldKit::createCache( config ); } - if ( config.value( QStringLiteral( "AllowMulti" ) ).toBool() ) + if ( config.value( "AllowMulti" ).toBool() ) { QStringList keyList = value.toString().remove( QChar( '{' ) ).remove( QChar( '}' ) ).split( ',' ); QStringList valueList; - Q_FOREACH ( const QString& key, keyList ) + Q_FOREACH ( const QgsValueRelationFieldKit::ValueRelationItem& item, vrCache ) { - auto val = vrCache.constFind( key ); - if ( val != vrCache.constEnd() ) - valueList << val.value(); - else - valueList << QStringLiteral( "(%1)" ).arg( key ); + if ( keyList.contains( item.key.toString() ) ) + { + valueList << item.value; + } } - return valueList.join( QStringLiteral( ", " ) ).prepend( '{' ).append( '}' ); + return valueList.join( ", " ).prepend( '{' ).append( '}' ); } else { if ( value.isNull() ) { QSettings settings; - return settings.value( QStringLiteral( "qgis/nullValue" ), "NULL" ).toString(); + return settings.value( "qgis/nullValue", "NULL" ).toString(); } - auto val = vrCache.constFind( value.toString() ); - if ( val != vrCache.constEnd() ) - return val.value(); + Q_FOREACH ( const QgsValueRelationFieldKit::ValueRelationItem& item, vrCache ) + { + if ( item.key == value ) + { + return item.value; + } + } } - return QStringLiteral( "(%1)" ).arg( value.toString() ); + return QString( "(%1)" ).arg( value.toString() ); } QVariant QgsValueRelationFieldKit::sortValue( QgsVectorLayer* layer, int fieldIndex, const QVariantMap& config, const QVariant& cache, const QVariant& value ) const diff --git a/src/core/qgsconfigurationmap.cpp b/src/core/qgsconfigurationmap.cpp index 50d03ba95a6..1ad64b944d9 100644 --- a/src/core/qgsconfigurationmap.cpp +++ b/src/core/qgsconfigurationmap.cpp @@ -116,12 +116,13 @@ QVariant QgsConfigurationMap::fromXmlHelper( const QDomElement& element ) const else if ( type == QLatin1String( "Map" ) ) { QVariantMap map; - QDomNodeList options = element.elementsByTagName( QStringLiteral( "Option" ) ); + QDomNodeList options = element.childNodes(); for ( int i = 0; i < options.count(); ++i ) { QDomElement elem = options.at( i ).toElement(); - map.insert( elem.attribute( QStringLiteral( "name" ) ), fromXmlHelper( elem ) ); + if ( elem.tagName() == QLatin1String( "Option" ) ) + map.insert( elem.attribute( QStringLiteral( "name" ) ), fromXmlHelper( elem ) ); } return map; } diff --git a/src/core/qgsfieldkit.h b/src/core/qgsfieldkit.h index a7881c60820..36ed3c08ee8 100644 --- a/src/core/qgsfieldkit.h +++ b/src/core/qgsfieldkit.h @@ -33,7 +33,7 @@ class QgsVectorLayer; * * This is an abstract base class and will always need to be subclassed. * - * @Note added in QGIS 3.0 + * @note added in QGIS 3.0 */ class CORE_EXPORT QgsFieldKit { diff --git a/src/gui/editorwidgets/qgsvaluerelationsearchwidgetwrapper.h b/src/gui/editorwidgets/qgsvaluerelationsearchwidgetwrapper.h index 48907e706ca..e1d8a3a9de5 100644 --- a/src/gui/editorwidgets/qgsvaluerelationsearchwidgetwrapper.h +++ b/src/gui/editorwidgets/qgsvaluerelationsearchwidgetwrapper.h @@ -52,7 +52,7 @@ class GUI_EXPORT QgsValueRelationSearchWidgetWrapper : public QgsSearchWidgetWra QWidget* createWidget( QWidget* parent ) override; void initWidget( QWidget* editor ) override; - private slots: + protected slots: //! Called when current value of search widget changes void onValueChanged(); diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt new file mode 100644 index 00000000000..93635405b3f --- /dev/null +++ b/src/test/CMakeLists.txt @@ -0,0 +1,7 @@ +# for installing headers + +SET(QGIS_TEST_HDRS + qgstest.h +) + +INSTALL(FILES ${QGIS_TEST_HDRS} DESTINATION ${QGIS_INCLUDE_DIR}) diff --git a/src/test/qgstest.h b/src/test/qgstest.h new file mode 100644 index 00000000000..ffbd12a43f4 --- /dev/null +++ b/src/test/qgstest.h @@ -0,0 +1,35 @@ +/*************************************************************************** + qgstest - %{Cpp:License:ClassName} + + --------------------- + begin : 5.12.2016 + copyright : (C) 2016 by Matthias Kuhn + email : matthias@opengis.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. * + * * + ***************************************************************************/ +#ifndef QGSTEST_H +#define QGSTEST_H + +#define QGSTEST_MAIN(TestObject) \ + QT_BEGIN_NAMESPACE \ + QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS \ + QT_END_NAMESPACE \ + int main(int argc, char *argv[]) \ + { \ + QgsApplication app(argc, argv, false); \ + app.setAttribute(Qt::AA_Use96Dpi, true); \ + QTEST_DISABLE_KEYPAD_NAVIGATION \ + QTEST_ADD_GPU_BLACKLIST_SUPPORT \ + TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ + return QTest::qExec(&tc, argc, argv); \ + } + + +#endif // QGSTEST_H diff --git a/tests/src/app/CMakeLists.txt b/tests/src/app/CMakeLists.txt index a4548604331..0cc6bd89086 100644 --- a/tests/src/app/CMakeLists.txt +++ b/tests/src/app/CMakeLists.txt @@ -10,6 +10,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/raster ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/symbology-ng ${CMAKE_CURRENT_BINARY_DIR}/../../../src/ui + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ui ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/editorwidgets ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/editorwidgets/core @@ -19,7 +20,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/python ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/app ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/app/pluginmanager - ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ui + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/test ) INCLUDE_DIRECTORIES(SYSTEM ${QT_INCLUDE_DIR} diff --git a/tests/src/app/testqgsattributetable.cpp b/tests/src/app/testqgsattributetable.cpp index ae2cc96f392..ef1d5c3c268 100644 --- a/tests/src/app/testqgsattributetable.cpp +++ b/tests/src/app/testqgsattributetable.cpp @@ -25,6 +25,8 @@ #include "qgsmapcanvas.h" #include "qgsunittypes.h" +#include "qgstest.h" + /** \ingroup UnitTests * This is a unit test for the attribute table dialog */ @@ -167,5 +169,5 @@ void TestQgsAttributeTable::testFieldCalculationArea() QVERIFY( qgsDoubleNear( f.attribute( "col1" ).toDouble(), expected, 0.001 ) ); } -QTEST_MAIN( TestQgsAttributeTable ) +QGSTEST_MAIN( TestQgsAttributeTable ) #include "testqgsattributetable.moc" diff --git a/tests/src/gui/CMakeLists.txt b/tests/src/gui/CMakeLists.txt index dee5f193d8b..2aaf7cf0f13 100644 --- a/tests/src/gui/CMakeLists.txt +++ b/tests/src/gui/CMakeLists.txt @@ -19,6 +19,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/geometry ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/raster ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/symbology-ng + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/test ) INCLUDE_DIRECTORIES(SYSTEM ${QT_INCLUDE_DIR} diff --git a/tests/src/gui/testqgsdualview.cpp b/tests/src/gui/testqgsdualview.cpp index fa671cadb55..92ad6f09bbd 100644 --- a/tests/src/gui/testqgsdualview.cpp +++ b/tests/src/gui/testqgsdualview.cpp @@ -27,6 +27,8 @@ #include #include +#include "qgstest.h" + class TestQgsDualView : public QObject { Q_OBJECT @@ -67,6 +69,7 @@ void TestQgsDualView::initTestCase() QgsApplication::init(); QgsApplication::initQgis(); QgsApplication::showSettings(); + QgsEditorWidgetRegistry::initEditors(); // Setup a map canvas with a vector layer loaded... @@ -267,9 +270,5 @@ void TestQgsDualView::testAttributeFormSharedValueScanning() QVERIFY( mixedValueFields.isEmpty() ); } -QTEST_MAIN( TestQgsDualView ) +QGSTEST_MAIN( TestQgsDualView ) #include "testqgsdualview.moc" - - - - diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt index 44e04f8f266..f2d77dc33c2 100644 --- a/tests/src/python/CMakeLists.txt +++ b/tests/src/python/CMakeLists.txt @@ -45,6 +45,7 @@ ADD_PYTHON_TEST(PyQgsEditWidgets test_qgseditwidgets.py) ADD_PYTHON_TEST(PyQgsExpression test_qgsexpression.py) ADD_PYTHON_TEST(PyQgsExpressionLineEdit test_qgsexpressionlineedit.py) ADD_PYTHON_TEST(PyQgsFeature test_qgsfeature.py) +ADD_PYTHON_TEST(PyQgsFieldKitsTest test_qgsfieldkits.py) ADD_PYTHON_TEST(PyQgsProject test_qgsproject.py) ADD_PYTHON_TEST(PyQgsFeatureIterator test_qgsfeatureiterator.py) ADD_PYTHON_TEST(PyQgsField test_qgsfield.py) diff --git a/tests/src/python/test_qgsconfigurationmap.py b/tests/src/python/test_qgsconfigurationmap.py index a0319f8f5df..2662f175a9c 100644 --- a/tests/src/python/test_qgsconfigurationmap.py +++ b/tests/src/python/test_qgsconfigurationmap.py @@ -52,7 +52,7 @@ class TestQgsConfigurationMap(unittest.TestCase): prop2 = QgsConfigurationMap() prop2.fromXml(element) - self.assertEquals(prop2.get(), my_properties) + self.assertEquals(my_properties, prop2.get()) def test_string(self): """ @@ -69,7 +69,7 @@ class TestQgsConfigurationMap(unittest.TestCase): prop2 = QgsConfigurationMap() prop2.fromXml(element) - self.assertEquals(prop2.get(), my_properties) + self.assertEquals(my_properties, prop2.get()) def test_double(self): """ @@ -86,7 +86,7 @@ class TestQgsConfigurationMap(unittest.TestCase): prop2 = QgsConfigurationMap() prop2.fromXml(element) - self.assertEquals(prop2.get(), my_properties) + self.assertEquals(my_properties, prop2.get()) def test_boolean(self): """ @@ -105,7 +105,7 @@ class TestQgsConfigurationMap(unittest.TestCase): prop2 = QgsConfigurationMap() prop2.fromXml(element) - self.assertEquals(prop2.get(), my_properties) + self.assertEquals(my_properties, prop2.get()) def test_complex(self): """ @@ -124,7 +124,7 @@ class TestQgsConfigurationMap(unittest.TestCase): prop2 = QgsConfigurationMap() prop2.fromXml(element) - self.assertEquals(prop2.get(), my_properties) + self.assertEquals(my_properties, prop2.get()) if __name__ == '__main__': diff --git a/tests/src/python/test_qgseditwidgets.py b/tests/src/python/test_qgseditwidgets.py index ba6660bc7ad..3804547acbc 100644 --- a/tests/src/python/test_qgseditwidgets.py +++ b/tests/src/python/test_qgseditwidgets.py @@ -95,40 +95,6 @@ class TestQgsTextEditWidget(unittest.TestCase): QgsProject.instance().removeAllMapLayers() - def test_ValueMap_representValue(self): - layer = QgsVectorLayer("none?field=number1:integer&field=number2:double&field=text1:string&field=number3:integer&field=number4:double&field=text2:string", - "layer", "memory") - assert layer.isValid() - QgsProject.instance().addMapLayer(layer) - f = QgsFeature() - f.setAttributes([2, 2.5, 'NULL', None, None, None]) - assert layer.dataProvider().addFeatures([f]) - reg = QgsEditorWidgetRegistry.instance() - factory = reg.factory("ValueMap") - self.assertIsNotNone(factory) - - # Tests with different value types occurring in the value map - config = {'two': '2', 'twoandhalf': '2.5', 'NULL text': 'NULL', - 'nothing': self.VALUEMAP_NULL_TEXT} - self.assertEqual(factory.representValue(layer, 0, config, None, 2), 'two') - self.assertEqual(factory.representValue(layer, 1, config, None, 2.5), 'twoandhalf') - self.assertEqual(factory.representValue(layer, 2, config, None, 'NULL'), 'NULL text') - # Tests with null values of different types, if value map contains null - self.assertEqual(factory.representValue(layer, 3, config, None, None), 'nothing') - self.assertEqual(factory.representValue(layer, 4, config, None, None), 'nothing') - self.assertEqual(factory.representValue(layer, 5, config, None, None), 'nothing') - # Tests with fallback display for different value types - config = {} - self.assertEqual(factory.representValue(layer, 0, config, None, 2), '(2)') - self.assertEqual(factory.representValue(layer, 1, config, None, 2.5), '(2.50000)') - self.assertEqual(factory.representValue(layer, 2, config, None, 'NULL'), '(NULL)') - # Tests with fallback display for null in different types of fields - self.assertEqual(factory.representValue(layer, 3, config, None, None), '(NULL)') - self.assertEqual(factory.representValue(layer, 4, config, None, None), '(NULL)') - self.assertEqual(factory.representValue(layer, 5, config, None, None), '(NULL)') - - QgsProject.instance().removeAllMapLayers() - def test_ValueMap_set_get(self): layer = QgsVectorLayer("none?field=number:integer", "layer", "memory") assert layer.isValid() @@ -136,8 +102,8 @@ class TestQgsTextEditWidget(unittest.TestCase): reg = QgsEditorWidgetRegistry.instance() configWdg = reg.createConfigWidget('ValueMap', layer, 0, None) - config = {'two': '2', 'twoandhalf': '2.5', 'NULL text': 'NULL', - 'nothing': self.VALUEMAP_NULL_TEXT} + config = {'map': {'two': '2', 'twoandhalf': '2.5', 'NULL text': 'NULL', + 'nothing': self.VALUEMAP_NULL_TEXT}} # Set a configuration containing values and NULL and check if it # is returned intact. @@ -145,140 +111,4 @@ class TestQgsTextEditWidget(unittest.TestCase): self.assertEqual(configWdg.config(), config) QgsProject.instance().removeAllMapLayers() - - def test_ValueRelation_representValue(self): - - first_layer = QgsVectorLayer("none?field=foreign_key:integer", - "first_layer", "memory") - assert first_layer.isValid() - second_layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string", - "second_layer", "memory") - assert second_layer.isValid() - QgsProject.instance().addMapLayer(second_layer) - f = QgsFeature() - f.setAttributes([123]) - assert first_layer.dataProvider().addFeatures([f]) - f = QgsFeature() - f.setAttributes([123, 'decoded_val']) - assert second_layer.dataProvider().addFeatures([f]) - - reg = QgsEditorWidgetRegistry.instance() - factory = reg.factory("ValueRelation") - self.assertIsNotNone(factory) - - # Everything valid - config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded'} - self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), 'decoded_val') - - # Code not find match in foreign layer - config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded'} - self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)') - - # Missing Layer - config = {'Key': 'pkid', 'Value': 'decoded'} - self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)') - - # Invalid Layer - config = {'Layer': 'invalid', 'Key': 'pkid', 'Value': 'decoded'} - self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)') - - # Invalid Key - config = {'Layer': second_layer.id(), 'Key': 'invalid', 'Value': 'decoded'} - self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)') - - # Invalid Value - config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'invalid'} - self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)') - - QgsProject.instance().removeMapLayer(second_layer.id()) - - def test_RelationReference_representValue(self): - - first_layer = QgsVectorLayer("none?field=foreign_key:integer", - "first_layer", "memory") - assert first_layer.isValid() - second_layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string", - "second_layer", "memory") - assert second_layer.isValid() - QgsProject.instance().addMapLayers([first_layer, second_layer]) - f = QgsFeature() - f.setAttributes([123]) - assert first_layer.dataProvider().addFeatures([f]) - f = QgsFeature() - f.setAttributes([123, 'decoded_val']) - assert second_layer.dataProvider().addFeatures([f]) - - relMgr = QgsProject.instance().relationManager() - - reg = QgsEditorWidgetRegistry.instance() - factory = reg.factory("RelationReference") - self.assertIsNotNone(factory) - - rel = QgsRelation() - rel.setRelationId('rel1') - rel.setRelationName('Relation Number One') - rel.setReferencingLayer(first_layer.id()) - rel.setReferencedLayer(second_layer.id()) - rel.addFieldPair('foreign_key', 'pkid') - assert(rel.isValid()) - - relMgr.addRelation(rel) - - # Everything valid - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('decoded') - self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), 'decoded_val') - - # Code not find match in foreign layer - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('decoded') - self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '456') - - # Invalid relation id - config = {'Relation': 'invalid'} - second_layer.setDisplayExpression('decoded') - self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123') - - # No display expression - config = {'Relation': rel.id()} - second_layer.setDisplayExpression(None) - self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123') - - # Invalid display expression - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('invalid +') - self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123') - - # Missing relation - config = {} - second_layer.setDisplayExpression('decoded') - self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123') - - # Inconsistent layer provided to representValue() - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('decoded') - self.assertEqual(factory.representValue(second_layer, 0, config, None, '123'), '123') - - # Inconsistent idx provided to representValue() - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('decoded') - self.assertEqual(factory.representValue(first_layer, 1, config, None, '123'), '123') - - # Invalid relation - rel = QgsRelation() - rel.setRelationId('rel2') - rel.setRelationName('Relation Number Two') - rel.setReferencingLayer(first_layer.id()) - rel.addFieldPair('foreign_key', 'pkid') - self.assertFalse(rel.isValid()) - - relMgr.addRelation(rel) - - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('decoded') - self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123') - - QgsProject.instance().removeAllMapLayers() - -if __name__ == '__main__': unittest.main() diff --git a/tests/src/python/test_qgsfieldkits.py b/tests/src/python/test_qgsfieldkits.py new file mode 100644 index 00000000000..2f3b169bbc1 --- /dev/null +++ b/tests/src/python/test_qgsfieldkits.py @@ -0,0 +1,202 @@ +# -*- coding: utf-8 -*- +"""QGIS Unit tests for field kits. + +.. 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__ = 'Matthias Kuhn' +__date__ = '05/12/2016' +__copyright__ = 'Copyright 2016, 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 (QgsMapLayerRegistry, QgsFeature, QgsGeometry, QgsPoint, + QgsProject, QgsRelation, QgsVectorLayer, NULL, QgsField, + QgsValueMapFieldKit, QgsValueRelationFieldKit, + QgsRelationReferenceFieldKit) + +from qgis.testing import start_app, unittest +from qgis.PyQt.QtCore import QVariant +from qgis.PyQt.QtWidgets import QTextEdit + +start_app() + + +class TestQgsValueMapFieldKit(unittest.TestCase): + + VALUEMAP_NULL_TEXT = "{2839923C-8B7D-419E-B84B-CA2FE9B80EC7}" + + def test_representValue(self): + layer = QgsVectorLayer("none?field=number1:integer&field=number2:double&field=text1:string&field=number3:integer&field=number4:double&field=text2:string", + "layer", "memory") + self.assertTrue(layer.isValid()) + QgsMapLayerRegistry.instance().addMapLayer(layer) + f = QgsFeature() + f.setAttributes([2, 2.5, 'NULL', None, None, None]) + layer.dataProvider().addFeatures([f]) + fieldKit = QgsValueMapFieldKit() + + # Tests with different value types occurring in the value map + config = {'map': {'two': '2', 'twoandhalf': '2.5', 'NULL text': 'NULL', + 'nothing': self.VALUEMAP_NULL_TEXT}} + self.assertEqual(fieldKit.representValue(layer, 0, config, None, 2), 'two') + self.assertEqual(fieldKit.representValue(layer, 1, config, None, 2.5), 'twoandhalf') + self.assertEqual(fieldKit.representValue(layer, 2, config, None, 'NULL'), 'NULL text') + # Tests with null values of different types, if value map contains null + self.assertEqual(fieldKit.representValue(layer, 3, config, None, None), 'nothing') + self.assertEqual(fieldKit.representValue(layer, 4, config, None, None), 'nothing') + self.assertEqual(fieldKit.representValue(layer, 5, config, None, None), 'nothing') + # Tests with fallback display for different value types + config = {} + self.assertEqual(fieldKit.representValue(layer, 0, config, None, 2), '(2)') + self.assertEqual(fieldKit.representValue(layer, 1, config, None, 2.5), '(2.50000)') + self.assertEqual(fieldKit.representValue(layer, 2, config, None, 'NULL'), '(NULL)') + # Tests with fallback display for null in different types of fields + self.assertEqual(fieldKit.representValue(layer, 3, config, None, None), '(NULL)') + self.assertEqual(fieldKit.representValue(layer, 4, config, None, None), '(NULL)') + self.assertEqual(fieldKit.representValue(layer, 5, config, None, None), '(NULL)') + + QgsMapLayerRegistry.instance().removeAllMapLayers() + + +class TestQgsValueRelationFieldKit(unittest.TestCase): + + def test_representValue(self): + + first_layer = QgsVectorLayer("none?field=foreign_key:integer", + "first_layer", "memory") + self.assertTrue(first_layer.isValid()) + second_layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string", + "second_layer", "memory") + self.assertTrue(second_layer.isValid()) + QgsMapLayerRegistry.instance().addMapLayer(second_layer) + f = QgsFeature() + f.setAttributes([123]) + first_layer.dataProvider().addFeatures([f]) + f = QgsFeature() + f.setAttributes([123, 'decoded_val']) + second_layer.dataProvider().addFeatures([f]) + + fieldKit = QgsValueRelationFieldKit() + + # Everything valid + config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded'} + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '123'), 'decoded_val') + + # Code not find match in foreign layer + config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded'} + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '456'), '(456)') + + # Missing Layer + config = {'Key': 'pkid', 'Value': 'decoded'} + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '456'), '(456)') + + # Invalid Layer + config = {'Layer': 'invalid', 'Key': 'pkid', 'Value': 'decoded'} + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '456'), '(456)') + + # Invalid Key + config = {'Layer': second_layer.id(), 'Key': 'invalid', 'Value': 'decoded'} + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '456'), '(456)') + + # Invalid Value + config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'invalid'} + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '456'), '(456)') + + QgsMapLayerRegistry.instance().removeMapLayer(second_layer.id()) + + +class TestQgsRelationReferenceFieldKit(unittest.TestCase): + + def test_representValue(self): + + first_layer = QgsVectorLayer("none?field=foreign_key:integer", + "first_layer", "memory") + self.assertTrue(first_layer.isValid()) + second_layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string", + "second_layer", "memory") + self.assertTrue(second_layer.isValid()) + QgsMapLayerRegistry.instance().addMapLayers([first_layer, second_layer]) + f = QgsFeature() + f.setAttributes([123]) + first_layer.dataProvider().addFeatures([f]) + f = QgsFeature() + f.setAttributes([123, 'decoded_val']) + second_layer.dataProvider().addFeatures([f]) + + relMgr = QgsProject.instance().relationManager() + + fieldKit = QgsRelationReferenceFieldKit() + + rel = QgsRelation() + rel.setRelationId('rel1') + rel.setRelationName('Relation Number One') + rel.setReferencingLayer(first_layer.id()) + rel.setReferencedLayer(second_layer.id()) + rel.addFieldPair('foreign_key', 'pkid') + self.assertTrue(rel.isValid()) + + relMgr.addRelation(rel) + + # Everything valid + config = {'Relation': rel.id()} + second_layer.setDisplayExpression('decoded') + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '123'), 'decoded_val') + + # Code not find match in foreign layer + config = {'Relation': rel.id()} + second_layer.setDisplayExpression('decoded') + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '456'), '456') + + # Invalid relation id + config = {'Relation': 'invalid'} + second_layer.setDisplayExpression('decoded') + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '123'), '123') + + # No display expression + config = {'Relation': rel.id()} + second_layer.setDisplayExpression(None) + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '123'), '123') + + # Invalid display expression + config = {'Relation': rel.id()} + second_layer.setDisplayExpression('invalid +') + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '123'), '123') + + # Missing relation + config = {} + second_layer.setDisplayExpression('decoded') + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '123'), '123') + + # Inconsistent layer provided to representValue() + config = {'Relation': rel.id()} + second_layer.setDisplayExpression('decoded') + self.assertEqual(fieldKit.representValue(second_layer, 0, config, None, '123'), '123') + + # Inconsistent idx provided to representValue() + config = {'Relation': rel.id()} + second_layer.setDisplayExpression('decoded') + self.assertEqual(fieldKit.representValue(first_layer, 1, config, None, '123'), '123') + + # Invalid relation + rel = QgsRelation() + rel.setRelationId('rel2') + rel.setRelationName('Relation Number Two') + rel.setReferencingLayer(first_layer.id()) + rel.addFieldPair('foreign_key', 'pkid') + self.assertFalse(rel.isValid()) + + relMgr.addRelation(rel) + + config = {'Relation': rel.id()} + second_layer.setDisplayExpression('decoded') + self.assertEqual(fieldKit.representValue(first_layer, 0, config, None, '123'), '123') + + QgsMapLayerRegistry.instance().removeAllMapLayers() + +if __name__ == '__main__': + unittest.main() diff --git a/tests/testdata/provider/testdata_pg.sql b/tests/testdata/provider/testdata_pg.sql index 4299b2f43e3..62d5a8a3823 100644 --- a/tests/testdata/provider/testdata_pg.sql +++ b/tests/testdata/provider/testdata_pg.sql @@ -457,7 +457,7 @@ CREATE TABLE qgis_test.widget_styles( ); INSERT INTO qgis_editor_widget_styles VALUES -('qgis_test', 'widget_styles', 'fld1', 'FooEdit', ''); +('qgis_test', 'widget_styles', 'fld1', 'FooEdit', ''); -----------------------------