diff --git a/src/analysis/processing/qgsalgorithmgpsbabeltools.h b/src/analysis/processing/qgsalgorithmgpsbabeltools.h index 8c61f039eeac..869dd232da44 100644 --- a/src/analysis/processing/qgsalgorithmgpsbabeltools.h +++ b/src/analysis/processing/qgsalgorithmgpsbabeltools.h @@ -78,7 +78,7 @@ class ANALYSIS_EXPORT QgsConvertGpxFeatureTypeAlgorithm : public QgsProcessingAl QStringList &logArgs ); - friend class TestQgsProcessingAlgs; + friend class TestQgsProcessingAlgsPt2; }; diff --git a/src/analysis/processing/qgsalgorithmimportphotos.h b/src/analysis/processing/qgsalgorithmimportphotos.h index e0b23a29bdb5..cf369fe4f90b 100644 --- a/src/analysis/processing/qgsalgorithmimportphotos.h +++ b/src/analysis/processing/qgsalgorithmimportphotos.h @@ -59,7 +59,7 @@ class ANALYSIS_EXPORT QgsImportPhotosAlgorithm : public QgsProcessingAlgorithm static QVariant extractOrientationFromMetadata( const QVariantMap &metadata ); static QVariant extractTimestampFromMetadata( const QVariantMap &metadata ); - friend class TestQgsProcessingAlgs; + friend class TestQgsProcessingAlgsPt1; }; ///@endcond PRIVATE diff --git a/src/analysis/processing/qgsalgorithmkmeansclustering.h b/src/analysis/processing/qgsalgorithmkmeansclustering.h index eb565a353940..78aac5055011 100644 --- a/src/analysis/processing/qgsalgorithmkmeansclustering.h +++ b/src/analysis/processing/qgsalgorithmkmeansclustering.h @@ -67,7 +67,7 @@ class ANALYSIS_EXPORT QgsKMeansClusteringAlgorithm : public QgsProcessingAlgorit static void findNearest( std::vector< Feature > &points, const std::vector< QgsPointXY > ¢ers, int k, bool &changed ); static void updateMeans( const std::vector< Feature > &points, std::vector< QgsPointXY > ¢ers, std::vector< uint > &weights, int k ); - friend class TestQgsProcessingAlgs; + friend class TestQgsProcessingAlgsPt1; }; ///@endcond PRIVATE diff --git a/src/analysis/processing/qgsalgorithmrasterlogicalop.h b/src/analysis/processing/qgsalgorithmrasterlogicalop.h index a7709ff30f9c..a4a317ce6520 100644 --- a/src/analysis/processing/qgsalgorithmrasterlogicalop.h +++ b/src/analysis/processing/qgsalgorithmrasterlogicalop.h @@ -62,7 +62,7 @@ class ANALYSIS_EXPORT QgsRasterBooleanLogicAlgorithmBase : public QgsProcessingA double mRasterUnitsPerPixelX; double mRasterUnitsPerPixelY; bool mTreatNodataAsFalse = false; - friend class TestQgsProcessingAlgs; + friend class TestQgsProcessingAlgsPt1; }; /** diff --git a/tests/src/analysis/CMakeLists.txt b/tests/src/analysis/CMakeLists.txt index 4ee0b7035905..aab568a82e76 100644 --- a/tests/src/analysis/CMakeLists.txt +++ b/tests/src/analysis/CMakeLists.txt @@ -20,7 +20,8 @@ endif() set(TESTS testqgsgeometrysnapper.cpp testqgsinterpolator.cpp - testqgsprocessingalgs.cpp + testqgsprocessingalgspt1.cpp + testqgsprocessingalgspt2.cpp testqgsprocessingmodelalgorithm.cpp testqgszonalstatistics.cpp testqgsrastercalculator.cpp diff --git a/tests/src/analysis/testqgsprocessingalgs.cpp b/tests/src/analysis/testqgsprocessingalgspt1.cpp similarity index 75% rename from tests/src/analysis/testqgsprocessingalgs.cpp rename to tests/src/analysis/testqgsprocessingalgspt1.cpp index d3fae9c281b6..72952386e4ce 100644 --- a/tests/src/analysis/testqgsprocessingalgs.cpp +++ b/tests/src/analysis/testqgsprocessingalgspt1.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - testqgsprocessingalgs.cpp + testqgsprocessingalgspt1.cpp --------------------- begin : November 2017 copyright : (C) 2017 by Nyall Dawson @@ -66,7 +66,7 @@ #include "qgscolorrampimpl.h" #include "qgstextformat.h" -class TestQgsProcessingAlgs: public QObject +class TestQgsProcessingAlgsPt1: public QObject { Q_OBJECT @@ -171,38 +171,7 @@ class TestQgsProcessingAlgs: public QObject void saveLog(); void setProjectVariable(); -#ifndef QT_NO_PRINTER - void exportLayoutPdf(); - void exportLayoutPng(); - void exportAtlasLayoutPdf(); - void exportAtlasLayoutPdfMultiple(); - void exportAtlasLayoutPng(); -#endif - - void tinMeshCreation(); - void exportMeshVertices(); - void exportMeshFaces(); - void exportMeshEdges(); - void exportMeshOnGrid(); - void rasterizeMesh(); - void exportMeshContours(); - void exportMeshCrossSection(); - void exportMeshTimeSeries(); - - void fileDownloader(); - - void rasterize(); - - void convertGpxFeatureType(); - void convertGpsData(); - void downloadGpsData(); - void uploadGpsData(); - void transferMainAnnotationLayer(); - - void extractLabels(); - - void splitVectorLayer(); - void buffer(); + // WARNING this test is "full" -- adding more to it will cause timeouts on CI! Add to testqgsprocessingalgspt(N+1).cpp instead private: @@ -215,12 +184,12 @@ class TestQgsProcessingAlgs: public QObject void exportToSpreadsheet( const QString &outputPath ); }; -std::unique_ptr TestQgsProcessingAlgs::featureBasedAlg( const QString &id ) +std::unique_ptr TestQgsProcessingAlgsPt1::featureBasedAlg( const QString &id ) { return std::unique_ptr( static_cast( QgsApplication::processingRegistry()->createAlgorithmById( id ) ) ); } -QgsFeature TestQgsProcessingAlgs::runForFeature( const std::unique_ptr< QgsProcessingFeatureBasedAlgorithm > &alg, QgsFeature feature, const QString &layerType, QVariantMap parameters ) +QgsFeature TestQgsProcessingAlgsPt1::runForFeature( const std::unique_ptr< QgsProcessingFeatureBasedAlgorithm > &alg, QgsFeature feature, const QString &layerType, QVariantMap parameters ) { Q_ASSERT( alg.get() ); std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); @@ -247,7 +216,7 @@ QgsFeature TestQgsProcessingAlgs::runForFeature( const std::unique_ptr< QgsProce return result; } -void TestQgsProcessingAlgs::initTestCase() +void TestQgsProcessingAlgsPt1::initTestCase() { QgsApplication::init(); QgsApplication::initQgis(); @@ -308,7 +277,7 @@ void TestQgsProcessingAlgs::initTestCase() QCOMPARE( meshLayer1d->datasetGroupCount(), 3 ); } -void TestQgsProcessingAlgs::cleanupTestCase() +void TestQgsProcessingAlgsPt1::cleanupTestCase() { QgsApplication::exitQgis(); } @@ -331,7 +300,7 @@ QVariantMap pkgAlg( const QStringList &layers, const QString &outputGpkg, bool o return package->run( parameters, *context, &feedback, ok ); } -void TestQgsProcessingAlgs::saveFeaturesAlg() +void TestQgsProcessingAlgsPt1::saveFeaturesAlg() { const QString outputGeoJson = QDir::tempPath() + "/savefeatures_alg.geojson"; const QString layerName = QStringLiteral( "custom_layer" ); @@ -364,7 +333,7 @@ void TestQgsProcessingAlgs::saveFeaturesAlg() QCOMPARE( savedLayer->getFeature( 1 ).geometry().asPoint().x(), -83.3 ); } -void TestQgsProcessingAlgs::exportLayersInformationAlg() +void TestQgsProcessingAlgsPt1::exportLayersInformationAlg() { const QString dataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt const QString gpkgFileName = dataDir + "/humanbeings.gpkg"; @@ -404,7 +373,7 @@ void TestQgsProcessingAlgs::exportLayersInformationAlg() QCOMPARE( vlayer->crs().authid(), QStringLiteral( "EPSG:4326" ) ); } -void TestQgsProcessingAlgs::packageAlg() +void TestQgsProcessingAlgsPt1::packageAlg() { const QString outputGpkg = QDir::tempPath() + "/package_alg.gpkg"; @@ -498,7 +467,7 @@ void TestQgsProcessingAlgs::packageAlg() QCOMPARE( selectedPolygonsPackagedLayer->featureCount(), 10 ); // With enabled SELECTED_FEATURES_ONLY all features should be saved when there is no selection } -void TestQgsProcessingAlgs::rasterLayerProperties() +void TestQgsProcessingAlgsPt1::rasterLayerProperties() { std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:rasterlayerproperties" ) ) ); @@ -551,7 +520,7 @@ void TestQgsProcessingAlgs::rasterLayerProperties() QCOMPARE( results.value( QStringLiteral( "NODATA_VALUE" ) ).toInt(), -9999 ); } -void TestQgsProcessingAlgs::exportToSpreadsheetXlsx() +void TestQgsProcessingAlgsPt1::exportToSpreadsheetXlsx() { if ( QgsTest::isCIRun() ) { @@ -562,13 +531,13 @@ void TestQgsProcessingAlgs::exportToSpreadsheetXlsx() exportToSpreadsheet( outputPath ); } -void TestQgsProcessingAlgs::exportToSpreadsheetOds() +void TestQgsProcessingAlgsPt1::exportToSpreadsheetOds() { const QString outputPath = QDir::tempPath() + "/spreadsheet.ods"; exportToSpreadsheet( outputPath ); } -void TestQgsProcessingAlgs::exportToSpreadsheetOptions() +void TestQgsProcessingAlgsPt1::exportToSpreadsheetOptions() { const QString outputPath = QDir::tempPath() + "/spreadsheet.ods"; if ( QFile::exists( outputPath ) ) @@ -658,7 +627,7 @@ void TestQgsProcessingAlgs::exportToSpreadsheetOptions() QVERIFY( values.contains( "VHigh" ) ); } -void TestQgsProcessingAlgs::exportToSpreadsheet( const QString &outputPath ) +void TestQgsProcessingAlgsPt1::exportToSpreadsheet( const QString &outputPath ) { if ( QFile::exists( outputPath ) ) QFile::remove( outputPath ); @@ -724,7 +693,7 @@ void TestQgsProcessingAlgs::exportToSpreadsheet( const QString &outputPath ) } -void TestQgsProcessingAlgs::renameLayerAlg() +void TestQgsProcessingAlgsPt1::renameLayerAlg() { const QgsProcessingAlgorithm *package( QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:renamelayer" ) ) ); QVERIFY( package ); @@ -776,7 +745,7 @@ void TestQgsProcessingAlgs::renameLayerAlg() QCOMPARE( results.value( "OUTPUT" ).toString(), QStringLiteral( "new name2" ) ); } -void TestQgsProcessingAlgs::loadLayerAlg() +void TestQgsProcessingAlgsPt1::loadLayerAlg() { const QgsProcessingAlgorithm *package( QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:loadlayer" ) ) ); QVERIFY( package ); @@ -821,7 +790,7 @@ void TestQgsProcessingAlgs::loadLayerAlg() QCOMPARE( context->layersToLoadOnCompletion().value( layerId, QgsProcessingContext::LayerDetails( QString(), nullptr, QString() ) ).outputName, QStringLiteral( "my layer" ) ); } -void TestQgsProcessingAlgs::parseGeoTags() +void TestQgsProcessingAlgsPt1::parseGeoTags() { // parseCoord QVERIFY( !QgsImportPhotosAlgorithm::parseCoord( "" ).isValid() ); @@ -960,7 +929,7 @@ void TestQgsProcessingAlgs::parseGeoTags() } -void TestQgsProcessingAlgs::featureFilterAlg() +void TestQgsProcessingAlgsPt1::featureFilterAlg() { const QgsProcessingAlgorithm *filterAlgTemplate = QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:filter" ) ); @@ -1010,7 +979,7 @@ void TestQgsProcessingAlgs::featureFilterAlg() Q_ASSERT( outputParamDef2->flags() & QgsProcessingParameterDefinition::FlagHidden ); } -void TestQgsProcessingAlgs::transformAlg() +void TestQgsProcessingAlgsPt1::transformAlg() { std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:reprojectlayer" ) ) ); QVERIFY( alg != nullptr ); @@ -1039,7 +1008,7 @@ void TestQgsProcessingAlgs::transformAlg() QVERIFY( ok ); } -void TestQgsProcessingAlgs::kmeansCluster() +void TestQgsProcessingAlgsPt1::kmeansCluster() { // make some features std::vector< QgsKMeansClusteringAlgorithm::Feature > features; @@ -1097,7 +1066,7 @@ void TestQgsProcessingAlgs::kmeansCluster() QCOMPARE( features[ 2 ].cluster, -1 ); } -void TestQgsProcessingAlgs::categorizeByStyle() +void TestQgsProcessingAlgsPt1::categorizeByStyle() { std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:categorizeusingstyle" ) ) ); QVERIFY( alg != nullptr ); @@ -1226,7 +1195,7 @@ void TestQgsProcessingAlgs::categorizeByStyle() QCOMPARE( catRenderer->categories().at( catRenderer->categoryIndexForValue( QStringLiteral( "c " ) ) ).symbol()->color().name(), QStringLiteral( "#0000ff" ) ); } -void TestQgsProcessingAlgs::extractBinary() +void TestQgsProcessingAlgsPt1::extractBinary() { std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:extractbinary" ) ) ); QVERIFY( alg != nullptr ); @@ -1264,7 +1233,7 @@ void TestQgsProcessingAlgs::extractBinary() QCOMPARE( QString( QCryptographicHash::hash( d, QCryptographicHash::Md5 ).toHex() ), QStringLiteral( "4b952b80e4288ca5111be2f6dd5d6809" ) ); } -void TestQgsProcessingAlgs::createDirectory() +void TestQgsProcessingAlgsPt1::createDirectory() { std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:createdirectory" ) ) ); QVERIFY( alg != nullptr ); @@ -1308,7 +1277,7 @@ void TestQgsProcessingAlgs::createDirectory() QVERIFY( QFileInfo( outputPath ).isDir() ); } -void TestQgsProcessingAlgs::flattenRelations() +void TestQgsProcessingAlgsPt1::flattenRelations() { std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:flattenrelationships" ) ) ); QVERIFY( alg != nullptr ); @@ -1408,7 +1377,7 @@ void TestQgsProcessingAlgs::flattenRelations() } -void TestQgsProcessingAlgs::polygonsToLines_data() +void TestQgsProcessingAlgsPt1::polygonsToLines_data() { QTest::addColumn( "sourceGeometry" ); QTest::addColumn( "expectedGeometry" ); @@ -1433,7 +1402,7 @@ void TestQgsProcessingAlgs::polygonsToLines_data() } -void TestQgsProcessingAlgs::polygonsToLines() +void TestQgsProcessingAlgsPt1::polygonsToLines() { QFETCH( QgsGeometry, sourceGeometry ); QFETCH( QgsGeometry, expectedGeometry ); @@ -1448,7 +1417,7 @@ void TestQgsProcessingAlgs::polygonsToLines() QVERIFY2( result.geometry().equals( expectedGeometry ), QStringLiteral( "Result: %1, Expected: %2" ).arg( result.geometry().asWkt(), expectedGeometry.asWkt() ).toUtf8().constData() ); } -void TestQgsProcessingAlgs::roundness_data() +void TestQgsProcessingAlgsPt1::roundness_data() { QTest::addColumn( "sourceGeometry" ); QTest::addColumn( "expectedAttribute" ); @@ -1470,7 +1439,7 @@ void TestQgsProcessingAlgs::roundness_data() << 0.393; } -void TestQgsProcessingAlgs::roundness() +void TestQgsProcessingAlgsPt1::roundness() { QFETCH( QgsGeometry, sourceGeometry ); QFETCH( double, expectedAttribute ); @@ -1487,7 +1456,7 @@ void TestQgsProcessingAlgs::roundness() } Q_DECLARE_METATYPE( Qgis::DataType ) -void TestQgsProcessingAlgs::createConstantRaster_data() +void TestQgsProcessingAlgsPt1::createConstantRaster_data() { QTest::addColumn( "inputExtent" ); QTest::addColumn( "expectedRaster" ); @@ -1843,7 +1812,7 @@ void TestQgsProcessingAlgs::createConstantRaster_data() } -void TestQgsProcessingAlgs::createConstantRaster() +void TestQgsProcessingAlgsPt1::createConstantRaster() { QFETCH( QString, inputExtent ); QFETCH( QString, expectedRaster ); @@ -1936,7 +1905,7 @@ void TestQgsProcessingAlgs::createConstantRaster() } -void TestQgsProcessingAlgs::densifyGeometries_data() +void TestQgsProcessingAlgsPt1::densifyGeometries_data() { QTest::addColumn( "sourceGeometry" ); QTest::addColumn( "expectedGeometry" ); @@ -1998,7 +1967,7 @@ void TestQgsProcessingAlgs::densifyGeometries_data() << "Polygon"; } -void TestQgsProcessingAlgs::densifyGeometries() +void TestQgsProcessingAlgsPt1::densifyGeometries() { QFETCH( QgsGeometry, sourceGeometry ); QFETCH( QgsGeometry, expectedGeometry ); @@ -2021,7 +1990,7 @@ void TestQgsProcessingAlgs::densifyGeometries() QVERIFY2( result.geometry().equals( expectedGeometry ), QStringLiteral( "Result: %1, Expected: %2" ).arg( result.geometry().asWkt(), expectedGeometry.asWkt() ).toUtf8().constData() ); } -void TestQgsProcessingAlgs::fillNoData_data() +void TestQgsProcessingAlgsPt1::fillNoData_data() { QTest::addColumn( "inputRaster" ); QTest::addColumn( "expectedRaster" ); @@ -2069,7 +2038,7 @@ void TestQgsProcessingAlgs::fillNoData_data() } -void TestQgsProcessingAlgs::fillNoData() +void TestQgsProcessingAlgsPt1::fillNoData() { QFETCH( QString, inputRaster ); QFETCH( QString, expectedRaster ); @@ -2149,7 +2118,7 @@ void TestQgsProcessingAlgs::fillNoData() } } -void TestQgsProcessingAlgs::lineDensity_data() +void TestQgsProcessingAlgsPt1::lineDensity_data() { QTest::addColumn( "inputDataset" ); QTest::addColumn( "expectedDataset" ); @@ -2187,7 +2156,7 @@ void TestQgsProcessingAlgs::lineDensity_data() } -void TestQgsProcessingAlgs::lineDensity() +void TestQgsProcessingAlgsPt1::lineDensity() { QFETCH( QString, inputDataset ); QFETCH( QString, expectedDataset ); @@ -2271,7 +2240,7 @@ void TestQgsProcessingAlgs::lineDensity() } } -void TestQgsProcessingAlgs::rasterLogicOp_data() +void TestQgsProcessingAlgsPt1::rasterLogicOp_data() { QTest::addColumn>( "input1" ); QTest::addColumn>( "input2" ); @@ -2382,7 +2351,7 @@ void TestQgsProcessingAlgs::rasterLogicOp_data() << -9999.0 << static_cast< int >( Qgis::DataType::Float32 ); } -void TestQgsProcessingAlgs::rasterLogicOp() +void TestQgsProcessingAlgsPt1::rasterLogicOp() { QFETCH( QVector< double >, input1 ); QFETCH( QVector< double >, input2 ); @@ -2539,7 +2508,7 @@ void TestQgsProcessingAlgs::rasterLogicOp() } } -void TestQgsProcessingAlgs::cellStatistics_data() +void TestQgsProcessingAlgsPt1::cellStatistics_data() { QTest::addColumn( "inputRasters" ); QTest::addColumn( "referenceLayer" ); @@ -2759,7 +2728,7 @@ void TestQgsProcessingAlgs::cellStatistics_data() } -void TestQgsProcessingAlgs::cellStatistics() +void TestQgsProcessingAlgsPt1::cellStatistics() { QFETCH( QStringList, inputRasters ); QFETCH( QString, referenceLayer ); @@ -2852,7 +2821,7 @@ void TestQgsProcessingAlgs::cellStatistics() } Q_DECLARE_METATYPE( QgsRasterAnalysisUtils::CellValuePercentileMethods ) -void TestQgsProcessingAlgs::percentileFunctions_data() +void TestQgsProcessingAlgsPt1::percentileFunctions_data() { QTest::addColumn( "function" ); QTest::addColumn>( "inputValues" ); @@ -2878,7 +2847,7 @@ void TestQgsProcessingAlgs::percentileFunctions_data() << std::vector( {-9999, 3.6, 18.4, 20, 21.6, 30, 43.8, 59.5, 91.2, 99.8, -9999} ); } -void TestQgsProcessingAlgs::percentileFunctions() +void TestQgsProcessingAlgsPt1::percentileFunctions() { QFETCH( QgsRasterAnalysisUtils::CellValuePercentileMethods, function ); QFETCH( std::vector, inputValues ); @@ -2918,7 +2887,7 @@ void TestQgsProcessingAlgs::percentileFunctions() } } -void TestQgsProcessingAlgs::percentileRaster_data() +void TestQgsProcessingAlgsPt1::percentileRaster_data() { QTest::addColumn( "inputRasters" ); QTest::addColumn( "referenceLayer" ); @@ -3054,7 +3023,7 @@ void TestQgsProcessingAlgs::percentileRaster_data() } -void TestQgsProcessingAlgs::percentileRaster() +void TestQgsProcessingAlgsPt1::percentileRaster() { QFETCH( QStringList, inputRasters ); QFETCH( QString, referenceLayer ); @@ -3147,7 +3116,7 @@ void TestQgsProcessingAlgs::percentileRaster() } Q_DECLARE_METATYPE( QgsRasterAnalysisUtils::CellValuePercentRankMethods ) -void TestQgsProcessingAlgs::percentrankFunctions_data() +void TestQgsProcessingAlgsPt1::percentrankFunctions_data() { QTest::addColumn( "function" ); QTest::addColumn>( "inputValues" ); @@ -3167,7 +3136,7 @@ void TestQgsProcessingAlgs::percentrankFunctions_data() << std::vector( {-9999, 0.0909090909091, 0.1818181818181, 0.272727272727, 0.522727272727, 0.622377622378, 0.492424242424, 0.56993006993, 0.684848484848, 0.566433566434, 0.1477272727272, 0.909090909091, -9999} ); } -void TestQgsProcessingAlgs::percentrankFunctions() +void TestQgsProcessingAlgsPt1::percentrankFunctions() { QFETCH( QgsRasterAnalysisUtils::CellValuePercentRankMethods, function ); QFETCH( std::vector, inputValues ); @@ -3207,7 +3176,7 @@ void TestQgsProcessingAlgs::percentrankFunctions() QVERIFY( true ); } -void TestQgsProcessingAlgs::percentrankByRaster_data() +void TestQgsProcessingAlgsPt1::percentrankByRaster_data() { QTest::addColumn( "valueLayer" ); QTest::addColumn( "valueLayerBand" ); @@ -3320,7 +3289,7 @@ void TestQgsProcessingAlgs::percentrankByRaster_data() } -void TestQgsProcessingAlgs::percentrankByRaster() +void TestQgsProcessingAlgsPt1::percentrankByRaster() { QFETCH( QString, valueLayer ); QFETCH( int, valueLayerBand ); @@ -3416,7 +3385,7 @@ void TestQgsProcessingAlgs::percentrankByRaster() } } -void TestQgsProcessingAlgs::percentrankByValue_data() +void TestQgsProcessingAlgsPt1::percentrankByValue_data() { QTest::addColumn( "inputRasters" ); QTest::addColumn( "referenceLayer" ); @@ -3523,7 +3492,7 @@ void TestQgsProcessingAlgs::percentrankByValue_data() } -void TestQgsProcessingAlgs::percentrankByValue() +void TestQgsProcessingAlgsPt1::percentrankByValue() { QFETCH( QStringList, inputRasters ); QFETCH( QString, referenceLayer ); @@ -3617,7 +3586,7 @@ void TestQgsProcessingAlgs::percentrankByValue() } } -void TestQgsProcessingAlgs::rasterFrequencyByComparisonOperator_data() +void TestQgsProcessingAlgsPt1::rasterFrequencyByComparisonOperator_data() { QTest::addColumn( "algName" ); QTest::addColumn( "inputValueRaster" ); @@ -3769,7 +3738,7 @@ void TestQgsProcessingAlgs::rasterFrequencyByComparisonOperator_data() << Qgis::DataType::Int32; } -void TestQgsProcessingAlgs::rasterFrequencyByComparisonOperator() +void TestQgsProcessingAlgsPt1::rasterFrequencyByComparisonOperator() { QFETCH( QString, algName ); QFETCH( QString, inputValueRaster ); @@ -3865,7 +3834,7 @@ void TestQgsProcessingAlgs::rasterFrequencyByComparisonOperator() } -void TestQgsProcessingAlgs::rasterLocalPosition_data() +void TestQgsProcessingAlgsPt1::rasterLocalPosition_data() { QTest::addColumn( "algName" ); QTest::addColumn( "inputRasters" ); @@ -3916,7 +3885,7 @@ void TestQgsProcessingAlgs::rasterLocalPosition_data() << QStringLiteral( "/expected_highestPosition/expectedHighestPositionTest3.tif" ); } -void TestQgsProcessingAlgs::rasterLocalPosition() +void TestQgsProcessingAlgsPt1::rasterLocalPosition() { QFETCH( QString, algName ); QFETCH( QStringList, inputRasters ); @@ -4006,7 +3975,7 @@ void TestQgsProcessingAlgs::rasterLocalPosition() } } -void TestQgsProcessingAlgs::roundRasterValues_data() +void TestQgsProcessingAlgsPt1::roundRasterValues_data() { QTest::addColumn( "inputRaster" ); QTest::addColumn( "expectedRaster" ); @@ -4145,7 +4114,7 @@ void TestQgsProcessingAlgs::roundRasterValues_data() } -void TestQgsProcessingAlgs::roundRasterValues() +void TestQgsProcessingAlgsPt1::roundRasterValues() { QFETCH( QString, inputRaster ); QFETCH( QString, expectedRaster ); @@ -4229,7 +4198,7 @@ void TestQgsProcessingAlgs::roundRasterValues() } } -void TestQgsProcessingAlgs::layoutMapExtent() +void TestQgsProcessingAlgsPt1::layoutMapExtent() { std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:printlayoutmapextenttolayer" ) ) ); QVERIFY( alg != nullptr ); @@ -4355,7 +4324,7 @@ void TestQgsProcessingAlgs::layoutMapExtent() } -void TestQgsProcessingAlgs::styleFromProject() +void TestQgsProcessingAlgsPt1::styleFromProject() { QgsProject p; QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=col1:string" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ); @@ -4474,7 +4443,7 @@ void TestQgsProcessingAlgs::styleFromProject() QCOMPARE( results.value( QStringLiteral( "LABELSETTINGS" ) ).toInt(), 1 ); } -void TestQgsProcessingAlgs::combineStyles() +void TestQgsProcessingAlgsPt1::combineStyles() { QgsStyle s1; s1.createMemoryDatabase(); @@ -4547,7 +4516,7 @@ void TestQgsProcessingAlgs::combineStyles() QVERIFY( s.labelSettingsNames().contains( QStringLiteral( "label1" ) ) ); } -void TestQgsProcessingAlgs::bookmarksToLayer() +void TestQgsProcessingAlgsPt1::bookmarksToLayer() { QgsApplication::bookmarkManager()->clear(); // create some bookmarks @@ -4637,7 +4606,7 @@ void TestQgsProcessingAlgs::bookmarksToLayer() } -void TestQgsProcessingAlgs::layerToBookmarks() +void TestQgsProcessingAlgsPt1::layerToBookmarks() { std::unique_ptr inputLayer( std::make_unique( QStringLiteral( "Polygon?crs=epsg:4326&field=province:string&field=municipality:string" ), QStringLiteral( "layer" ), QStringLiteral( "memory" ) ) ); QVERIFY( inputLayer->isValid() ); @@ -4705,7 +4674,7 @@ void TestQgsProcessingAlgs::layerToBookmarks() QCOMPARE( QgsApplication::bookmarkManager()->bookmarks().at( 1 ).extent().toString( 0 ), QStringLiteral( "146,-22 : 147,-21" ) ); } -void TestQgsProcessingAlgs::repairShapefile() +void TestQgsProcessingAlgsPt1::repairShapefile() { const QTemporaryDir tmpPath; @@ -4742,7 +4711,7 @@ void TestQgsProcessingAlgs::repairShapefile() QVERIFY( layer->isValid() ); } -void TestQgsProcessingAlgs::renameField() +void TestQgsProcessingAlgsPt1::renameField() { QgsProject p; QgsVectorLayer *layer = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=col1:string" ), QStringLiteral( "vl2" ), QStringLiteral( "memory" ) ); @@ -4783,7 +4752,7 @@ void TestQgsProcessingAlgs::renameField() } -void TestQgsProcessingAlgs::compareDatasets() +void TestQgsProcessingAlgsPt1::compareDatasets() { QgsProject p; QgsVectorLayer *pointLayer = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=col1:string" ), QStringLiteral( "vl2" ), QStringLiteral( "memory" ) ); @@ -4971,7 +4940,7 @@ void TestQgsProcessingAlgs::compareDatasets() } -void TestQgsProcessingAlgs::shapefileEncoding() +void TestQgsProcessingAlgsPt1::shapefileEncoding() { std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:shpencodinginfo" ) ) ); QVERIFY( alg != nullptr ); @@ -5008,7 +4977,7 @@ void TestQgsProcessingAlgs::shapefileEncoding() QCOMPARE( results.value( QStringLiteral( "LDID_ENCODING" ) ).toString(), QString() ); } -void TestQgsProcessingAlgs::setLayerEncoding() +void TestQgsProcessingAlgsPt1::setLayerEncoding() { QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( TEST_DATA_DIR ) + "/shapefile/system_encoding.shp", QStringLiteral( "test" ), QStringLiteral( "ogr" ) ); @@ -5053,7 +5022,7 @@ class TestProcessingFeedback : public QgsProcessingFeedback }; -void TestQgsProcessingAlgs::raiseException() +void TestQgsProcessingAlgsPt1::raiseException() { TestProcessingFeedback feedback; @@ -5087,7 +5056,7 @@ void TestQgsProcessingAlgs::raiseException() QCOMPARE( feedback.errors, QStringList() << QStringLiteral( "you done screwed up boy" ) ); } -void TestQgsProcessingAlgs::raiseWarning() +void TestQgsProcessingAlgsPt1::raiseWarning() { TestProcessingFeedback feedback; @@ -5121,7 +5090,7 @@ void TestQgsProcessingAlgs::raiseWarning() QCOMPARE( feedback.errors, QStringList() << QStringLiteral( "you mighta screwed up boy, but i aint so sure" ) ); } -void TestQgsProcessingAlgs::randomFloatingPointDistributionRaster_data() +void TestQgsProcessingAlgsPt1::randomFloatingPointDistributionRaster_data() { QTest::addColumn( "inputExtent" ); QTest::addColumn( "expectedDataType" ); @@ -5148,7 +5117,7 @@ void TestQgsProcessingAlgs::randomFloatingPointDistributionRaster_data() << 1; } -void TestQgsProcessingAlgs::randomFloatingPointDistributionRaster() +void TestQgsProcessingAlgsPt1::randomFloatingPointDistributionRaster() { //this test only checks if the correct raster data type is chosen //value by value comparison is not effective for random rasters @@ -5212,7 +5181,7 @@ void TestQgsProcessingAlgs::randomFloatingPointDistributionRaster() } -void TestQgsProcessingAlgs::randomIntegerDistributionRaster_data() +void TestQgsProcessingAlgsPt1::randomIntegerDistributionRaster_data() { QTest::addColumn( "inputExtent" ); QTest::addColumn( "expectedDataType" ); @@ -5272,7 +5241,7 @@ void TestQgsProcessingAlgs::randomIntegerDistributionRaster_data() } -void TestQgsProcessingAlgs::randomIntegerDistributionRaster() +void TestQgsProcessingAlgsPt1::randomIntegerDistributionRaster() { //this test only checks if the correct raster data type is chosen //value by value comparison is not effective for random rasters @@ -5336,7 +5305,7 @@ void TestQgsProcessingAlgs::randomIntegerDistributionRaster() } } -void TestQgsProcessingAlgs::randomRaster_data() +void TestQgsProcessingAlgsPt1::randomRaster_data() { QTest::addColumn( "inputExtent" ); QTest::addColumn( "expectedDataType" ); @@ -5531,7 +5500,7 @@ void TestQgsProcessingAlgs::randomRaster_data() } -void TestQgsProcessingAlgs::randomRaster() +void TestQgsProcessingAlgsPt1::randomRaster() { QFETCH( QString, inputExtent ); QFETCH( Qgis::DataType, expectedDataType ); @@ -5647,7 +5616,7 @@ void TestQgsProcessingAlgs::randomRaster() } } -void TestQgsProcessingAlgs::filterByLayerType() +void TestQgsProcessingAlgsPt1::filterByLayerType() { QgsProject p; QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=col1:string" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ); @@ -5685,7 +5654,7 @@ void TestQgsProcessingAlgs::filterByLayerType() QVERIFY( !results.contains( QStringLiteral( "VECTOR" ) ) ); } -void TestQgsProcessingAlgs::conditionalBranch() +void TestQgsProcessingAlgsPt1::conditionalBranch() { QVariantMap config; QVariantList conditions; @@ -5720,7 +5689,7 @@ void TestQgsProcessingAlgs::conditionalBranch() QCOMPARE( results.value( QStringLiteral( "name2" ) ).toInt(), 0 ); } -void TestQgsProcessingAlgs::saveLog() +void TestQgsProcessingAlgsPt1::saveLog() { std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:savelog" ) ) ); QVERIFY( alg != nullptr ); @@ -5750,7 +5719,7 @@ void TestQgsProcessingAlgs::saveLog() QCOMPARE( QString( file2.readAll() ), QStringLiteral( "test
" ) ); } -void TestQgsProcessingAlgs::setProjectVariable() +void TestQgsProcessingAlgsPt1::setProjectVariable() { std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:setprojectvariable" ) ) ); QVERIFY( alg != nullptr ); @@ -5779,1552 +5748,7 @@ void TestQgsProcessingAlgs::setProjectVariable() QCOMPARE( scope->variable( QStringLiteral( "my_var" ) ).toInt(), 13 ); } -#ifndef QT_NO_PRINTER -void TestQgsProcessingAlgs::exportLayoutPdf() -{ - QgsProject p; - QgsPrintLayout *layout = new QgsPrintLayout( &p ); - layout->initializeDefaults(); - layout->setName( QStringLiteral( "my layout" ) ); - p.layoutManager()->addLayout( layout ); - - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:printlayouttopdf" ) ) ); - QVERIFY( alg != nullptr ); - - const QString outputPdf = QDir::tempPath() + "/my_layout.pdf"; - if ( QFile::exists( outputPdf ) ) - QFile::remove( outputPdf ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "missing" ) ); - parameters.insert( QStringLiteral( "OUTPUT" ), outputPdf ); - - bool ok = false; - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( &p ); - QgsProcessingFeedback feedback; - QVariantMap results; - results = alg->run( parameters, *context, &feedback, &ok ); - // invalid layout name - QVERIFY( !ok ); - QVERIFY( !QFile::exists( outputPdf ) ); - - parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "my layout" ) ); - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QVERIFY( QFile::exists( outputPdf ) ); -} - -void TestQgsProcessingAlgs::exportLayoutPng() -{ - QgsProject p; - QgsPrintLayout *layout = new QgsPrintLayout( &p ); - layout->initializeDefaults(); - layout->setName( QStringLiteral( "my layout" ) ); - - QgsLayoutItemMap *map = new QgsLayoutItemMap( layout ); - map->setBackgroundEnabled( false ); - map->setFrameEnabled( false ); - map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) ); - layout->addLayoutItem( map ); - map->setExtent( mPointsLayer->extent() ); - - p.layoutManager()->addLayout( layout ); - - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:printlayouttoimage" ) ) ); - QVERIFY( alg != nullptr ); - - QString outputPng = QDir::tempPath() + "/my_layout.png"; - if ( QFile::exists( outputPng ) ) - QFile::remove( outputPng ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "missing" ) ); - parameters.insert( QStringLiteral( "OUTPUT" ), outputPng ); - - bool ok = false; - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( &p ); - QgsProcessingFeedback feedback; - QVariantMap results; - results = alg->run( parameters, *context, &feedback, &ok ); - // invalid layout name - QVERIFY( !ok ); - QVERIFY( !QFile::exists( outputPng ) ); - - parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "my layout" ) ); - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - QVERIFY( QFile::exists( outputPng ) ); - - outputPng = QDir::tempPath() + "/my_layout_custom_layers.png"; - if ( QFile::exists( outputPng ) ) - QFile::remove( outputPng ); - - parameters.insert( QStringLiteral( "OUTPUT" ), outputPng ); - parameters.insert( QStringLiteral( "LAYERS" ), QVariantList() << QVariant::fromValue( mPointsLayer ) ); - parameters.insert( QStringLiteral( "DPI" ), 96 ); - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - QVERIFY( QFile::exists( outputPng ) ); - QVERIFY( imageCheck( "export_layout_custom_layers", outputPng ) ); -} - -void TestQgsProcessingAlgs::exportAtlasLayoutPdf() -{ - QgsMapLayer *polygonLayer = mPolygonLayer->clone(); - QgsProject p; - p.addMapLayers( QList() << polygonLayer ); - - QgsPrintLayout *layout = new QgsPrintLayout( &p ); - layout->initializeDefaults(); - layout->setName( QStringLiteral( "my layout" ) ); - - QgsLayoutItemMap *map = new QgsLayoutItemMap( layout ); - map->setBackgroundEnabled( false ); - map->setFrameEnabled( false ); - map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) ); - layout->addLayoutItem( map ); - map->setExtent( polygonLayer->extent() ); - - p.layoutManager()->addLayout( layout ); - - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:atlaslayouttopdf" ) ) ); - QVERIFY( alg != nullptr ); - - const QString outputPdf = QDir::tempPath() + "/my_atlas_layout.pdf"; - if ( QFile::exists( outputPdf ) ) - QFile::remove( outputPdf ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "my layout" ) ); - parameters.insert( QStringLiteral( "COVERAGE_LAYER" ), QVariant::fromValue( polygonLayer ) ); - parameters.insert( QStringLiteral( "OUTPUT" ), outputPdf ); - parameters.insert( QStringLiteral( "DPI" ), 96 ); - - bool ok = false; - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( &p ); - QgsProcessingFeedback feedback; - QVariantMap results; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QVERIFY( QFile::exists( outputPdf ) ); -} - -void TestQgsProcessingAlgs::exportAtlasLayoutPdfMultiple() -{ - QgsMapLayer *polygonLayer = mPolygonLayer->clone(); - QgsProject p; - p.addMapLayers( QList() << polygonLayer ); - - QgsPrintLayout *layout = new QgsPrintLayout( &p ); - layout->initializeDefaults(); - layout->setName( QStringLiteral( "my layout" ) ); - - QgsLayoutItemMap *map = new QgsLayoutItemMap( layout ); - map->setBackgroundEnabled( false ); - map->setFrameEnabled( false ); - map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) ); - layout->addLayoutItem( map ); - map->setExtent( polygonLayer->extent() ); - - p.layoutManager()->addLayout( layout ); - - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:atlaslayouttomultiplepdf" ) ) ); - QVERIFY( alg != nullptr ); - - const QString outputPdfDir = QDir::tempPath() + "/atlas_pdf"; - if ( QFile::exists( outputPdfDir ) ) - QDir().rmdir( outputPdfDir ); - - QDir().mkdir( outputPdfDir ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "my layout" ) ); - parameters.insert( QStringLiteral( "COVERAGE_LAYER" ), QVariant::fromValue( polygonLayer ) ); - parameters.insert( QStringLiteral( "OUTPUT_FOLDER" ), outputPdfDir ); - parameters.insert( QStringLiteral( "DPI" ), 96 ); - - bool ok = false; - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( &p ); - QgsProcessingFeedback feedback; - QVariantMap results; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QVERIFY( QFile::exists( outputPdfDir + "/output_1.pdf" ) ); - QVERIFY( QFile::exists( outputPdfDir + "/output_2.pdf" ) ); - QVERIFY( QFile::exists( outputPdfDir + "/output_3.pdf" ) ); -} - -void TestQgsProcessingAlgs::exportAtlasLayoutPng() -{ - QgsMapLayer *polygonLayer = mPolygonLayer->clone(); - QgsProject p; - p.addMapLayers( QList() << polygonLayer ); - - QgsPrintLayout *layout = new QgsPrintLayout( &p ); - layout->initializeDefaults(); - layout->setName( QStringLiteral( "my layout" ) ); - - QgsLayoutItemMap *map = new QgsLayoutItemMap( layout ); - map->setBackgroundEnabled( false ); - map->setFrameEnabled( false ); - map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) ); - layout->addLayoutItem( map ); - map->setExtent( polygonLayer->extent() ); - - p.layoutManager()->addLayout( layout ); - - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:atlaslayouttoimage" ) ) ); - QVERIFY( alg != nullptr ); - - const QDir tempDir( QDir::tempPath() ); - if ( !tempDir.mkdir( "my_atlas" ) ) - { - const QDir dir( QDir::tempPath() + "/my_atlas" ); - const QStringList files = dir.entryList( QStringList() << "*.*", QDir::Files ); - for ( const QString &file : files ) - QFile::remove( QDir::tempPath() + "/my_atlas/" + file ); - } - - QVariantMap parameters; - parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "my layout" ) ); - parameters.insert( QStringLiteral( "COVERAGE_LAYER" ), QVariant::fromValue( polygonLayer ) ); - parameters.insert( QStringLiteral( "FOLDER" ), QString( QDir::tempPath() + "/my_atlas" ) ); - parameters.insert( QStringLiteral( "FILENAME_EXPRESSION" ), QStringLiteral( "'export_'||@atlas_featurenumber" ) ); - parameters.insert( QStringLiteral( "DPI" ), 96 ); - - bool ok = false; - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( &p ); - QgsProcessingFeedback feedback; - QVariantMap results; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QVERIFY( QFile::exists( QDir::tempPath() + "/my_atlas/export_1.png" ) ); - QVERIFY( QFile::exists( QDir::tempPath() + "/my_atlas/export_10.png" ) ); - QVERIFY( imageCheck( "export_atlas", QDir::tempPath() + "/my_atlas/export_1.png" ) ); - - parameters[QStringLiteral( "FILENAME_EXPRESSION" )] = QStringLiteral( "'custom_'||@atlas_featurenumber" ); - parameters.insert( QStringLiteral( "LAYERS" ), QVariantList() << QVariant::fromValue( mPointsLayer ) ); - - ok = false; - results.clear(); - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QVERIFY( QFile::exists( QDir::tempPath() + "/my_atlas/custom_1.png" ) ); - QVERIFY( QFile::exists( QDir::tempPath() + "/my_atlas/custom_10.png" ) ); - QVERIFY( imageCheck( "export_atlas_custom_layers", QDir::tempPath() + "/my_atlas/custom_1.png" ) ); -} -#endif - -void TestQgsProcessingAlgs::tinMeshCreation() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:tinmeshcreation" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantList inputLayers; - - QVariantMap pointLayer; - pointLayer[QStringLiteral( "source" )] = "points"; - pointLayer[QStringLiteral( "type" )] = 0; - pointLayer[QStringLiteral( "attributeIndex" )] = mPointsLayer->fields().indexOf( "Importance" ); - - inputLayers.append( pointLayer ); - - QVariantMap polyLayer; - polyLayer[QStringLiteral( "source" )] = "polygons"; - polyLayer[QStringLiteral( "type" )] = 2; - polyLayer[QStringLiteral( "attributeIndex" )] = mPolygonLayer->fields().indexOf( "Value" ); - - inputLayers.append( polyLayer ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "SOURCE_DATA" ), inputLayers ); - parameters.insert( QStringLiteral( "OUTPUT_MESH" ), QString( QDir::tempPath() + "/meshLayer.2dm" ) ); - parameters.insert( QStringLiteral( "MESH_FORMAT" ), 0 ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( QgsProject::instance() ); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QgsMeshLayer meshLayer( QDir::tempPath() + "/meshLayer.2dm", "mesh", "mdal" ); - QVERIFY( meshLayer.isValid() ); - - QgsMeshDataProvider *provider = meshLayer.dataProvider(); - QCOMPARE( provider->vertexCount(), 627 ); - QCOMPARE( provider->faceCount(), 1218 ); - - meshLayer.updateTriangularMesh(); - QVERIFY( qgsDoubleNear( meshLayer.datasetValue( QgsMeshDatasetIndex( 0, 0 ), QgsPointXY( -103.0, 39.0 ) ).scalar(), 20.0, 0.001 ) ); - QVERIFY( qgsDoubleNear( meshLayer.datasetValue( QgsMeshDatasetIndex( 0, 0 ), QgsPointXY( -86.0, 35.0 ) ).scalar(), 1.855, 0.001 ) ) ; -} - -void TestQgsProcessingAlgs::exportMeshVertices() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:exportmeshvertices" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); - - QVariantList datasetGroup; - datasetGroup << 1 << 2; - parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); - - QVariantMap datasetTime; - datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); - QVariantList datasetIndex; - datasetIndex << 1 << 1; - datasetTime[QStringLiteral( "value" )] = datasetIndex; - parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); - - parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); - parameters.insert( QStringLiteral( "VECTOR_OPTION" ), 2 ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( QgsProject::instance() ); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); - QVERIFY( resultLayer ); - QVERIFY( resultLayer->isValid() ); - QVERIFY( resultLayer->geometryType() == QgsWkbTypes::PointGeometry ); - QCOMPARE( resultLayer->featureCount(), 5l ); - const QgsAttributeList attributeList = resultLayer->attributeList(); - QCOMPARE( resultLayer->fields().count(), 5 ); - QCOMPARE( resultLayer->fields().at( 0 ).name(), QStringLiteral( "VertexScalarDataset" ) ); - QCOMPARE( resultLayer->fields().at( 1 ).name(), QStringLiteral( "VertexVectorDataset_x" ) ); - QCOMPARE( resultLayer->fields().at( 2 ).name(), QStringLiteral( "VertexVectorDataset_y" ) ); - QCOMPARE( resultLayer->fields().at( 3 ).name(), QStringLiteral( "VertexVectorDataset_mag" ) ); - QCOMPARE( resultLayer->fields().at( 4 ).name(), QStringLiteral( "VertexVectorDataset_dir" ) ); - - QgsFeatureIterator featIt = resultLayer->getFeatures(); - QgsFeature feat; - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "PointZ (1000 2000 20)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toDouble(), 2.0 ); - QCOMPARE( feat.attributes().at( 1 ).toDouble(), 2.0 ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.0 ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 2.828, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); - - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "PointZ (2000 2000 30)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toDouble(), 3.0 ); - QCOMPARE( feat.attributes().at( 1 ).toDouble(), 3.0 ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.0 ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 3.605, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 56.3099, 2 ) ); - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "PointZ (3000 2000 40)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toDouble(), 4.0 ); - QCOMPARE( feat.attributes().at( 1 ).toDouble(), 4.0 ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 3.0 ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 5.0, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 53.130, 2 ) ); - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "PointZ (2000 3000 50)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toDouble(), 3.0 ); - QCOMPARE( feat.attributes().at( 1 ).toDouble(), 3.0 ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 3.0 ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 4.242, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45, 2 ) ); - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "PointZ (1000 3000 10)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toDouble(), 2.0 ); - QCOMPARE( feat.attributes().at( 1 ).toDouble(), 2.0 ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), -1.0 ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 2.236, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 116.565, 2 ) ); -} - -void TestQgsProcessingAlgs::exportMeshFaces() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:exportmeshfaces" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); - - QVariantList datasetGroup; - datasetGroup << 3 << 4; - parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); - - QVariantMap datasetTime; - datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); - QVariantList datasetIndex; - datasetIndex << 1 << 1; - datasetTime[QStringLiteral( "value" )] = datasetIndex; - parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); - - parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); - parameters.insert( QStringLiteral( "VECTOR_OPTION" ), 2 ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( QgsProject::instance() ); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); - QVERIFY( resultLayer ); - QVERIFY( resultLayer->isValid() ); - QVERIFY( resultLayer->geometryType() == QgsWkbTypes::PolygonGeometry ); - QCOMPARE( resultLayer->featureCount(), 2l ); - const QgsAttributeList attributeList = resultLayer->attributeList(); - QCOMPARE( resultLayer->fields().count(), 5 ); - QCOMPARE( resultLayer->fields().at( 0 ).name(), QStringLiteral( "FaceScalarDataset" ) ); - QCOMPARE( resultLayer->fields().at( 1 ).name(), QStringLiteral( "FaceVectorDataset_x" ) ); - QCOMPARE( resultLayer->fields().at( 2 ).name(), QStringLiteral( "FaceVectorDataset_y" ) ); - QCOMPARE( resultLayer->fields().at( 3 ).name(), QStringLiteral( "FaceVectorDataset_mag" ) ); - QCOMPARE( resultLayer->fields().at( 4 ).name(), QStringLiteral( "FaceVectorDataset_dir" ) ); - - QgsFeatureIterator featIt = resultLayer->getFeatures(); - QgsFeature feat; - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "PolygonZ ((1000 2000 20, 2000 2000 30, 2000 3000 50, 1000 3000 10, 1000 2000 20))" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toDouble(), 2.0 ); - QCOMPARE( feat.attributes().at( 1 ).toDouble(), 2.0 ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.0 ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 2.828, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); - - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "PolygonZ ((2000 2000 30, 3000 2000 40, 2000 3000 50, 2000 2000 30))" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toDouble(), 3.0 ); - QCOMPARE( feat.attributes().at( 1 ).toDouble(), 3.0 ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 3.0 ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 4.242, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); -} - -void TestQgsProcessingAlgs::exportMeshEdges() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:exportmeshedges" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "INPUT" ), "mesh layer 1D" ); - - QVariantList datasetGroup; - datasetGroup << 1 << 2; - parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); - - QVariantMap datasetTime; - datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); - QVariantList datasetIndex; - datasetIndex << 1 << 1; - datasetTime[QStringLiteral( "value" )] = datasetIndex; - parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); - - parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); - parameters.insert( QStringLiteral( "VECTOR_OPTION" ), 2 ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( QgsProject::instance() ); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); - QVERIFY( resultLayer ); - QVERIFY( resultLayer->isValid() ); - QVERIFY( resultLayer->geometryType() == QgsWkbTypes::LineGeometry ); - QCOMPARE( resultLayer->featureCount(), 3l ); - const QgsAttributeList attributeList = resultLayer->attributeList(); - QCOMPARE( resultLayer->fields().count(), 5 ); - QCOMPARE( resultLayer->fields().at( 0 ).name(), QStringLiteral( "EdgeScalarDataset" ) ); - QCOMPARE( resultLayer->fields().at( 1 ).name(), QStringLiteral( "EdgeVectorDataset_x" ) ); - QCOMPARE( resultLayer->fields().at( 2 ).name(), QStringLiteral( "EdgeVectorDataset_y" ) ); - QCOMPARE( resultLayer->fields().at( 3 ).name(), QStringLiteral( "EdgeVectorDataset_mag" ) ); - QCOMPARE( resultLayer->fields().at( 4 ).name(), QStringLiteral( "EdgeVectorDataset_dir" ) ); - - QgsFeatureIterator featIt = resultLayer->getFeatures(); - QgsFeature feat; - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "LineStringZ (1000 2000 20, 2000 2000 30)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toDouble(), 2.0 ); - QCOMPARE( feat.attributes().at( 1 ).toDouble(), 2.0 ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.0 ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 2.828, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); - - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "LineStringZ (2000 2000 30, 3000 2000 40)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toDouble(), 3.0 ); - QCOMPARE( feat.attributes().at( 1 ).toDouble(), 3.0 ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 3.0 ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 4.242, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); - - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "LineStringZ (3000 2000 40, 2000 3000 50)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toDouble(), 4.0 ); - QCOMPARE( feat.attributes().at( 1 ).toDouble(), 4.0 ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 4.0 ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 5.656, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); -} - -void TestQgsProcessingAlgs::exportMeshOnGrid() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:exportmeshongrid" ) ) ); - QVERIFY( alg != nullptr ); - - const QString dataDir = QString( TEST_DATA_DIR ); //defined in CmakeLists.txt - const QString meshUri( dataDir + "/mesh/trap_steady_05_3D.nc" ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "INPUT" ), meshUri ); - - QVariantList datasetGroup; - for ( int i = 0; i < 12; ++i ) - datasetGroup.append( i ); - parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); - - QVariantMap datasetTime; - datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); - QVariantList datasetIndex; - datasetIndex << 1 << 1; - datasetTime[QStringLiteral( "value" )] = datasetIndex; - parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); - - parameters.insert( QStringLiteral( "GRID_SPACING" ), 25.0 ); - - parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); - parameters.insert( QStringLiteral( "VECTOR_OPTION" ), 2 ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( QgsProject::instance() ); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); - QVERIFY( resultLayer ); - QVERIFY( resultLayer->isValid() ); - QVERIFY( resultLayer->geometryType() == QgsWkbTypes::PointGeometry ); - QCOMPARE( resultLayer->featureCount(), 205l ); - const QgsAttributeList attributeList = resultLayer->attributeList(); - QCOMPARE( resultLayer->fields().count(), 21 ); - QStringList fieldsName; - fieldsName << QStringLiteral( "Bed Elevation" ) << QStringLiteral( "temperature" ) << QStringLiteral( "temperature/Maximums" ) - << QStringLiteral( "temperature/Minimums" ) << QStringLiteral( "temperature/Time at Maximums" ) << QStringLiteral( "temperature/Time at Minimums" ) - << QStringLiteral( "velocity_x" ) << QStringLiteral( "velocity_y" ) << QStringLiteral( "velocity_mag" ) << QStringLiteral( "velocity_dir" ) - << QStringLiteral( "velocity/Maximums_x" ) << QStringLiteral( "velocity/Maximums_y" ) << QStringLiteral( "velocity/Maximums_mag" ) << QStringLiteral( "velocity/Maximums_dir" ) - << QStringLiteral( "velocity/Minimums_x" ) << QStringLiteral( "velocity/Minimums_y" ) << QStringLiteral( "velocity/Minimums_mag" ) << QStringLiteral( "velocity/Minimums_dir" ) - << QStringLiteral( "velocity/Time at Maximums" ) << QStringLiteral( "velocity/Time at Minimums" ) << QStringLiteral( "water depth" ); - - for ( int i = 0; i < fieldsName.count(); ++i ) - QCOMPARE( fieldsName.at( i ), resultLayer->fields().at( i ).name() ); - - QgsFeatureIterator featIt = resultLayer->getFeatures(); - QgsFeature feat; - for ( int i = 0; i < 8; ++i ) - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "Point (25 50)" ), feat.geometry().asWkt() ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 0 ).toDouble(), -5.025, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 1 ).toDouble(), 1.424, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 2 ).toDouble(), 5.00, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 1.32e-36, 2 ) ); - QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 0.02776, 2 ) ); - -} - -void TestQgsProcessingAlgs::rasterizeMesh() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:meshrasterize" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); - - QVariantList datasetGroup; - datasetGroup << 1 << 2 << 3; - parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); - - QVariantMap datasetTime; - datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); - QVariantList datasetIndex; - datasetIndex << 1 << 1; - datasetTime[QStringLiteral( "value" )] = datasetIndex; - parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); - - parameters.insert( QStringLiteral( "PIXEL_SIZE" ), 200.0 ); - - parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( QgsProject::instance() ); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - std::unique_ptr outputRaster = std::make_unique< QgsRasterLayer >( results.value( QStringLiteral( "OUTPUT" ) ).toString(), "output", "gdal" ); - QVERIFY( outputRaster ); - QVERIFY( outputRaster->isValid() ); - QgsRasterDataProvider *outputProvider = outputRaster->dataProvider(); - - QCOMPARE( outputProvider->bandCount(), 3 ); - QCOMPARE( outputProvider->xSize(), 10 ); - QCOMPARE( outputProvider->ySize(), 5 ); - - std::unique_ptr outputBlock_1( outputProvider->block( 1, outputRaster->extent(), 10, 5 ) ); - std::unique_ptr outputBlock_2( outputProvider->block( 2, outputRaster->extent(), 10, 5 ) ); - std::unique_ptr outputBlock_3( outputProvider->block( 3, outputRaster->extent(), 10, 5 ) ); - - // load expected result - const QString dataDir = QString( TEST_DATA_DIR ); //defined in CmakeLists.txt - std::unique_ptr expectedRaster = std::make_unique< QgsRasterLayer >( dataDir + "/mesh/rasterized_mesh.tif", "expected", "gdal" ); - QVERIFY( expectedRaster ); - QVERIFY( expectedRaster->isValid() ); - QgsRasterDataProvider *expectedProvider = outputRaster->dataProvider(); - std::unique_ptr expectedBlock_1( expectedProvider->block( 1, expectedRaster->extent(), 10, 5 ) ); - std::unique_ptr expectedBlock_2( expectedProvider->block( 2, expectedRaster->extent(), 10, 5 ) ); - std::unique_ptr expectedBlock_3( expectedProvider->block( 3, expectedRaster->extent(), 10, 5 ) ); - - for ( int ix = 0; ix < 10; ++ix ) - { - for ( int iy = 0; iy < 5; ++iy ) - { - if ( !( std::isnan( outputBlock_1->value( iy, ix ) ) && std::isnan( expectedBlock_1->value( iy, ix ) ) ) ) - QCOMPARE( outputBlock_1->value( iy, ix ), expectedBlock_1->value( iy, ix ) ); - if ( !( std::isnan( outputBlock_2->value( iy, ix ) ) && std::isnan( expectedBlock_2->value( iy, ix ) ) ) ) - QCOMPARE( outputBlock_2->value( iy, ix ), expectedBlock_2->value( iy, ix ) ); - if ( !( std::isnan( outputBlock_2->value( iy, ix ) ) && std::isnan( expectedBlock_2->value( iy, ix ) ) ) ) - QCOMPARE( outputBlock_3->value( iy, ix ), expectedBlock_3->value( iy, ix ) ); - } - } -} - -void TestQgsProcessingAlgs::exportMeshContours() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:meshcontours" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); - - QVariantList datasetGroup; - datasetGroup << 1 << 2 << 3; - parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); - - QVariantMap datasetTime; - datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); - QVariantList datasetIndex; - datasetIndex << 1 << 1; - datasetTime[QStringLiteral( "value" )] = datasetIndex; - parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); - - parameters.insert( QStringLiteral( "OUTPUT_LINES" ), QgsProcessing::TEMPORARY_OUTPUT ); - parameters.insert( QStringLiteral( "OUTPUT_POLYGONS" ), QgsProcessing::TEMPORARY_OUTPUT ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( QgsProject::instance() ); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( !ok ); - - // min>max - parameters.insert( QStringLiteral( "INCREMENT" ), 0.5 ); - parameters.insert( QStringLiteral( "MINIMUM" ), 5.0 ); - parameters.insert( QStringLiteral( "MAXIMUM" ), 2.0 ); - - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( !ok ); - - // min-maxrun( parameters, *context, &feedback, &ok ); - QVERIFY( !ok ); - - // min-maxrun( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QgsVectorLayer *resultLinesLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT_LINES" ) ).toString() ) ); - QVERIFY( resultLinesLayer ); - QVERIFY( resultLinesLayer->isValid() ); - QgsAttributeList attributeList = resultLinesLayer->attributeList(); - QCOMPARE( resultLinesLayer->fields().count(), 3 ); - QCOMPARE( resultLinesLayer->fields().at( 0 ).name(), QStringLiteral( "group" ) ); - QCOMPARE( resultLinesLayer->fields().at( 1 ).name(), QStringLiteral( "time" ) ); - QCOMPARE( resultLinesLayer->fields().at( 2 ).name(), QStringLiteral( "value" ) ); - - QCOMPARE( resultLinesLayer->featureCount(), 4l ); - QgsFeatureIterator featIt = resultLinesLayer->getFeatures(); - QgsFeature feat; - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "LineStringZ (1250 3000 20, 1250 2250 27.5, 1250 2000 22.5)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexScalarDataset" ) ); - QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.25 ); - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "LineStringZ (1006.94319345290614365 3000 10.27772773811624596, 1000 2976.48044676110157525 10.23519553238898538)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexVectorDataset" ) ); - QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.25 ); - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "LineStringZ (2009.71706923721990279 2990.28293076277986984 49.90282930762779756, 2462.15304528350043256 2000 34.62153045283500319)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexVectorDataset" ) ); - QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 4.25 ); - featIt.nextFeature( feat ); - QCOMPARE( QStringLiteral( "LineStringZ (1500 3000 30, 1500 2500 35, 1500 2000 25)" ), feat.geometry().asWkt() ); - QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "FaceScalarDataset" ) ); - QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.25 ); - - QgsVectorLayer *resultpolygonLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT_POLYGONS" ) ).toString() ) ); - QVERIFY( resultpolygonLayer ); - QVERIFY( resultpolygonLayer->isValid() ); - attributeList = resultpolygonLayer->attributeList(); - QCOMPARE( resultpolygonLayer->fields().count(), 4 ); - QCOMPARE( resultpolygonLayer->fields().at( 0 ).name(), QStringLiteral( "group" ) ); - QCOMPARE( resultpolygonLayer->fields().at( 1 ).name(), QStringLiteral( "time" ) ); - QCOMPARE( resultpolygonLayer->fields().at( 2 ).name(), QStringLiteral( "min_value" ) ); - QCOMPARE( resultpolygonLayer->fields().at( 3 ).name(), QStringLiteral( "max_value" ) ); - - QCOMPARE( resultpolygonLayer->featureCount(), 6l ); - featIt = resultpolygonLayer->getFeatures(); - featIt.nextFeature( feat ); - QgsGeometry geom = feat.geometry(); - geom.normalize(); - QCOMPARE( geom.asWkt(), QStringLiteral( "PolygonZ ((1000 2000 20, 1000 3000 10, 1250 3000 20, 1250 2250 27.5, 1250 2000 22.5, 1000 2000 20))" ) ); - QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexScalarDataset" ) ); - QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 0.25 ); - QCOMPARE( feat.attributes().at( 3 ).toDouble(), 2.25 ); - featIt.nextFeature( feat ); - geom = feat.geometry(); - geom.normalize(); - QCOMPARE( geom.asWkt(), QStringLiteral( "PolygonZ ((1250 2000 22.5, 1250 2250 27.5, 1250 3000 20, 2000 3000 50, 3000 2000 40, 2000 2000 30, 1250 2000 22.5))" ) ); - QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexScalarDataset" ) ); - QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.25 ); - QCOMPARE( feat.attributes().at( 3 ).toDouble(), 4.25 ); - featIt.nextFeature( feat ); - geom = feat.geometry(); - geom.normalize(); - QCOMPARE( geom.asWkt( 2 ), QStringLiteral( "PolygonZ ((1000 2976.48 10.24, 1000 3000 10, 1006.94 3000 10.28, 1000 2976.48 10.24))" ) ); - QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexVectorDataset" ) ); - QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 0.25 ); - QCOMPARE( feat.attributes().at( 3 ).toDouble(), 2.25 ); - featIt.nextFeature( feat ); - featIt.nextFeature( feat ); - geom = feat.geometry(); - geom.normalize(); - QCOMPARE( geom.asWkt(), QStringLiteral( "PolygonZ ((1000 2000 20, 1000 3000 10, 1500 3000 30, 1500 2500 35, 1500 2000 25, 1000 2000 20))" ) ); - QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "FaceScalarDataset" ) ); - QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 0.25 ); - QCOMPARE( feat.attributes().at( 3 ).toDouble(), 2.25 ); - featIt.nextFeature( feat ); - geom = feat.geometry(); - geom.normalize(); - QCOMPARE( geom.asWkt(), QStringLiteral( "PolygonZ ((1500 2000 25, 1500 2500 35, 1500 3000 30, 2000 3000 50, 3000 2000 40, 2000 2000 30, 1500 2000 25))" ) ); - QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "FaceScalarDataset" ) ); - QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); - QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.25 ); - QCOMPARE( feat.attributes().at( 3 ).toDouble(), 4.25 ); - - parameters.insert( QStringLiteral( "CONTOUR_LEVEL_LIST" ), QStringLiteral( "4,2,3" ) ); - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( !ok ); - - parameters.insert( QStringLiteral( "CONTOUR_LEVEL_LIST" ), QStringLiteral( "2,2,3" ) ); - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( !ok ); - - parameters.insert( QStringLiteral( "CONTOUR_LEVEL_LIST" ), QStringLiteral( "1,2,3" ) ); - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); -} - -void TestQgsProcessingAlgs::exportMeshCrossSection() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:meshexportcrosssection" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); - - QVariantList datasetGroup; - datasetGroup << 1 << 2 << 3; - parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); - - QVariantMap datasetTime; - datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); - QVariantList datasetIndex; - datasetIndex << 1 << 1; - datasetTime[QStringLiteral( "value" )] = datasetIndex; - parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); - - parameters.insert( QStringLiteral( "RESOLUTION" ), 100 ); - - const QString outputPath = QDir::tempPath() + "/test_mesh_xs.csv"; - parameters.insert( QStringLiteral( "OUTPUT" ), outputPath ); - - QgsVectorLayer *layerLine = new QgsVectorLayer( QStringLiteral( "LineString" ), - QStringLiteral( "lines_for_xs" ), - QStringLiteral( "memory" ) ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( QgsProject::instance() ); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( !ok ); - - QStringList wktLines; - wktLines << QStringLiteral( "LineString (1500 2200, 2500 2200)" ); - wktLines << QStringLiteral( "LineString (1500 1500, 1500 3200)" ); - - QgsFeatureList flist; - for ( const QString &wkt : wktLines ) - { - QgsFeature feat; - feat.setGeometry( QgsGeometry::fromWkt( wkt ) ); - flist << feat; - } - layerLine->dataProvider()->addFeatures( flist ); - QgsProject::instance()->addMapLayer( layerLine ); QgsProject::instance()->addMapLayer( layerLine ); - parameters.insert( QStringLiteral( "INPUT_LINES" ), layerLine->name() ); - - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QFile outputFile( outputPath ); - QVERIFY( outputFile.open( QIODevice::ReadOnly ) ); - QTextStream textStream( &outputFile ); - const QString header = textStream.readLine(); - QCOMPARE( header, QStringLiteral( "fid,x,y,offset,VertexScalarDataset,VertexVectorDataset,FaceScalarDataset" ) ); - - QStringList expectedLines; - expectedLines << QStringLiteral( "1,1500.00,2200.00,0.00,2.50,3.33,2.00" ) - << QStringLiteral( "1,1600.00,2200.00,100.00,2.60,3.41,2.00" ) - << QStringLiteral( "1,1700.00,2200.00,200.00,2.70,3.48,2.00" ) - << QStringLiteral( "1,1800.00,2200.00,300.00,2.80,3.56,2.00" ) - << QStringLiteral( "1,1900.00,2200.00,400.00,2.90,3.64,2.00" ) - << QStringLiteral( "1,2000.00,2200.00,500.00,3.00,3.72,2.00" ) - << QStringLiteral( "1,2100.00,2200.00,600.00,3.10,3.86,3.00" ) - << QStringLiteral( "1,2200.00,2200.00,700.00,3.20,4.00,3.00" ) - << QStringLiteral( "1,2300.00,2200.00,800.00,3.30,4.14,3.00" ) - << QStringLiteral( "1,2400.00,2200.00,900.00,3.40,4.28,3.00" ) - << QStringLiteral( "1,2500.00,2200.00,1000.00,3.50,4.42,3.00" ) - << QStringLiteral( "2,1500.00,1500.00,0.00, , , " ) - << QStringLiteral( "2,1500.00,1600.00,100.00, , , " ) - << QStringLiteral( "2,1500.00,1700.00,200.00, , , " ) - << QStringLiteral( "2,1500.00,1800.00,300.00, , , " ) - << QStringLiteral( "2,1500.00,1900.00,400.00, , , " ) - << QStringLiteral( "2,1500.00,2000.00,500.00,2.50,3.20,2.00" ) - << QStringLiteral( "2,1500.00,2100.00,600.00,2.50,3.26,2.00" ) - << QStringLiteral( "2,1500.00,2200.00,700.00,2.50,3.33,2.00" ) - << QStringLiteral( "2,1500.00,2300.00,800.00,2.50,3.40,2.00" ) - << QStringLiteral( "2,1500.00,2400.00,900.00,2.50,3.47,2.00" ) - << QStringLiteral( "2,1500.00,2500.00,1000.00,2.50,3.54,2.00" ) - << QStringLiteral( "2,1500.00,2600.00,1100.00,2.50,3.33,2.00" ) - << QStringLiteral( "2,1500.00,2700.00,1200.00,2.50,3.14,2.00" ) - << QStringLiteral( "2,1500.00,2800.00,1300.00,2.50,2.97,2.00" ) - << QStringLiteral( "2,1500.00,2900.00,1400.00,2.50,2.82,2.00" ) - << QStringLiteral( "2,1500.00,3000.00,1500.00,2.50,2.69,2.00" ) - << QStringLiteral( "2,1500.00,3100.00,1600.00, , , " ) - << QStringLiteral( "2,1500.00,3200.00,1700.00, , , " ); - QString line = textStream.readLine(); - int i = 0; - QVERIFY( !line.isEmpty() ); - while ( !line.isEmpty() ) - { - QCOMPARE( line, expectedLines.at( i ) ); - ++i; - line = textStream.readLine(); - } - - QVERIFY( i == expectedLines.count() ); -} - -void TestQgsProcessingAlgs::fileDownloader() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:filedownloader" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "URL" ), QStringLiteral( "https://version.qgis.org/version.txt" ) ); - parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - // verify that temporary outputs have the URL file extension appended - QVERIFY( results.value( QStringLiteral( "OUTPUT" ) ).toString().endsWith( QLatin1String( ".txt" ) ) ); -} - -void TestQgsProcessingAlgs::rasterize() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:rasterize" ) ) ); - QVERIFY( alg != nullptr ); - - const QString outputTif = QDir::tempPath() + "/rasterize_output.tif"; - if ( QFile::exists( outputTif ) ) - QFile::remove( outputTif ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "EXTENT" ), QStringLiteral( "-120,-80,15,55" ) ); - parameters.insert( QStringLiteral( "TILE_SIZE" ), 320 ); - parameters.insert( QStringLiteral( "MAP_UNITS_PER_PIXEL" ), 0.125 ); - parameters.insert( QStringLiteral( "OUTPUT" ), outputTif ); - - // create a temporary project with three layers, but only two are visible - // (to test that the algorithm in the default setup without defined LAYERS or MAP_THEME uses only vsisible - // layers that and in the correct order) - QgsProject project; - const QString dataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt - QgsVectorLayer *pointsLayer = new QgsVectorLayer( dataDir + "/points.shp", QStringLiteral( "points" ), QStringLiteral( "ogr" ) ); - QgsVectorLayer *linesLayer = new QgsVectorLayer( dataDir + "/lines.shp", QStringLiteral( "lines" ), QStringLiteral( "ogr" ) ); - QgsVectorLayer *polygonLayer = new QgsVectorLayer( dataDir + "/polys.shp", QStringLiteral( "polygons" ), QStringLiteral( "ogr" ) ); - QVERIFY( pointsLayer->isValid() && linesLayer->isValid() && polygonLayer->isValid() ); - project.addMapLayers( QList() << pointsLayer << linesLayer << polygonLayer ); - QgsLayerTreeLayer *nodePolygons = project.layerTreeRoot()->findLayer( polygonLayer ); - QVERIFY( nodePolygons ); - nodePolygons->setItemVisibilityChecked( false ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( &project ); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - QVERIFY( QFile::exists( outputTif ) ); - - QgsRenderChecker checker; - checker.setControlPathPrefix( QStringLiteral( "processing_algorithm" ) ); - checker.setControlExtension( "tif" ); - checker.setControlName( "expected_rasterize" ); - checker.setRenderedImage( outputTif ); - QVERIFY( checker.compareImages( "rasterize", 500 ) ); -} - -void TestQgsProcessingAlgs::convertGpxFeatureType() -{ - // test generation of babel argument lists - QStringList processArgs; - QStringList logArgs; - - QgsConvertGpxFeatureTypeAlgorithm::createArgumentLists( QStringLiteral( "/home/me/my input file.gpx" ), - QStringLiteral( "/home/me/my output file.gpx" ), - QgsConvertGpxFeatureTypeAlgorithm::WaypointsFromRoute, - processArgs, logArgs ); - QCOMPARE( processArgs, QStringList( - { - QStringLiteral( "-i" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-f" ), - QStringLiteral( "/home/me/my input file.gpx" ), - QStringLiteral( "-x" ), - QStringLiteral( "transform,wpt=rte,del" ), - QStringLiteral( "-o" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-F" ), - QStringLiteral( "/home/me/my output file.gpx" ) - } ) ); - // when showing the babel command, filenames should be wrapped in "", which is what QProcess does internally (hence the processArgs don't have these) - QCOMPARE( logArgs, QStringList( - { - QStringLiteral( "-i" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-f" ), - QStringLiteral( "\"/home/me/my input file.gpx\"" ), - QStringLiteral( "-x" ), - QStringLiteral( "transform,wpt=rte,del" ), - QStringLiteral( "-o" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-F" ), - QStringLiteral( "\"/home/me/my output file.gpx\"" ) - } ) ); - - logArgs.clear(); - processArgs.clear(); - QgsConvertGpxFeatureTypeAlgorithm::createArgumentLists( QStringLiteral( "/home/me/my input file.gpx" ), - QStringLiteral( "/home/me/my output file.gpx" ), - QgsConvertGpxFeatureTypeAlgorithm::WaypointsFromTrack, - processArgs, logArgs ); - QCOMPARE( processArgs, QStringList( - { - QStringLiteral( "-i" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-f" ), - QStringLiteral( "/home/me/my input file.gpx" ), - QStringLiteral( "-x" ), - QStringLiteral( "transform,wpt=trk,del" ), - QStringLiteral( "-o" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-F" ), - QStringLiteral( "/home/me/my output file.gpx" ) - } ) ); - // when showing the babel command, filenames should be wrapped in "", which is what QProcess does internally (hence the processArgs don't have these) - QCOMPARE( logArgs, QStringList( - { - QStringLiteral( "-i" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-f" ), - QStringLiteral( "\"/home/me/my input file.gpx\"" ), - QStringLiteral( "-x" ), - QStringLiteral( "transform,wpt=trk,del" ), - QStringLiteral( "-o" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-F" ), - QStringLiteral( "\"/home/me/my output file.gpx\"" ) - } ) ); - - logArgs.clear(); - processArgs.clear(); - - QgsConvertGpxFeatureTypeAlgorithm::createArgumentLists( QStringLiteral( "/home/me/my input file.gpx" ), - QStringLiteral( "/home/me/my output file.gpx" ), - QgsConvertGpxFeatureTypeAlgorithm::RouteFromWaypoints, - processArgs, logArgs ); - QCOMPARE( processArgs, QStringList( - { - QStringLiteral( "-i" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-f" ), - QStringLiteral( "/home/me/my input file.gpx" ), - QStringLiteral( "-x" ), - QStringLiteral( "transform,rte=wpt,del" ), - QStringLiteral( "-o" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-F" ), - QStringLiteral( "/home/me/my output file.gpx" ) - } ) ); - // when showing the babel command, filenames should be wrapped in "", which is what QProcess does internally (hence the processArgs don't have these) - QCOMPARE( logArgs, QStringList( - { - QStringLiteral( "-i" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-f" ), - QStringLiteral( "\"/home/me/my input file.gpx\"" ), - QStringLiteral( "-x" ), - QStringLiteral( "transform,rte=wpt,del" ), - QStringLiteral( "-o" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-F" ), - QStringLiteral( "\"/home/me/my output file.gpx\"" ) - } ) ); - - - logArgs.clear(); - processArgs.clear(); - - QgsConvertGpxFeatureTypeAlgorithm::createArgumentLists( QStringLiteral( "/home/me/my input file.gpx" ), - QStringLiteral( "/home/me/my output file.gpx" ), - QgsConvertGpxFeatureTypeAlgorithm::TrackFromWaypoints, - processArgs, logArgs ); - QCOMPARE( processArgs, QStringList( - { - QStringLiteral( "-i" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-f" ), - QStringLiteral( "/home/me/my input file.gpx" ), - QStringLiteral( "-x" ), - QStringLiteral( "transform,trk=wpt,del" ), - QStringLiteral( "-o" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-F" ), - QStringLiteral( "/home/me/my output file.gpx" ) - } ) ); - // when showing the babel command, filenames should be wrapped in "", which is what QProcess does internally (hence the processArgs don't have these) - QCOMPARE( logArgs, QStringList( - { - QStringLiteral( "-i" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-f" ), - QStringLiteral( "\"/home/me/my input file.gpx\"" ), - QStringLiteral( "-x" ), - QStringLiteral( "transform,trk=wpt,del" ), - QStringLiteral( "-o" ), - QStringLiteral( "gpx" ), - QStringLiteral( "-F" ), - QStringLiteral( "\"/home/me/my output file.gpx\"" ) - } ) ); -} - -void TestQgsProcessingAlgs::convertGpsData() -{ - TestProcessingFeedback feedback; - - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:convertgpsdata" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "INPUT" ), QStringLiteral( "%1/GARMIN_ATRK.NVM" ).arg( TEST_DATA_DIR ) ); - parameters.insert( QStringLiteral( "FORMAT" ), QStringLiteral( "garmin_xt" ) ); - parameters.insert( QStringLiteral( "FEATURE_TYPE" ), 0 ); // waypoints - parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); - - bool ok = false; - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - - QVariantMap results; - results = alg->run( parameters, *context, &feedback, &ok ); - // garmin_xt format does not support waypoints, exception should have been raised - QVERIFY( !ok ); - - QCOMPARE( feedback.errors, QStringList() << QStringLiteral( "The GPSBabel format \u201Cgarmin_xt\u201D does not support converting waypoints." ) ); - feedback.errors.clear(); - - parameters.insert( QStringLiteral( "FEATURE_TYPE" ), 1 ); // routes - ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - // garmin_xt format does not support routes, exception should have been raised - QVERIFY( !ok ); - QCOMPARE( feedback.errors, QStringList() << QStringLiteral( "The GPSBabel format \u201Cgarmin_xt\u201D does not support converting routes." ) ); - feedback.errors.clear(); - - parameters.insert( QStringLiteral( "FEATURE_TYPE" ), 2 ); // tracks - ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - // garmin_xt format does support tracks! - QVERIFY( ok ); - - QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT_LAYER" ) ).toString() ) ); - QVERIFY( resultLayer ); - QCOMPARE( resultLayer->providerType(), QStringLiteral( "gpx" ) ); - QCOMPARE( resultLayer->wkbType(), QgsWkbTypes::LineString ); - QCOMPARE( resultLayer->featureCount(), 1LL ); - - // algorithm should also run when given the description for a format, not the format name - parameters.insert( QStringLiteral( "FORMAT" ), QStringLiteral( "Mobile Garmin XT Track files" ) ); - ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT_LAYER" ) ).toString() ) ); - QVERIFY( resultLayer ); - QCOMPARE( resultLayer->providerType(), QStringLiteral( "gpx" ) ); - QCOMPARE( resultLayer->wkbType(), QgsWkbTypes::LineString ); - QCOMPARE( resultLayer->featureCount(), 1LL ); - - // try with a format which doesn't exist - feedback.errors.clear(); - parameters.insert( QStringLiteral( "FORMAT" ), QStringLiteral( "not a format" ) ); - ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( !ok ); - QVERIFY( feedback.errors.value( 0 ).startsWith( QStringLiteral( "Unknown GPSBabel format \u201Cnot a format\u201D." ) ) ); -} - -void TestQgsProcessingAlgs::downloadGpsData() -{ - TestProcessingFeedback feedback; - - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:downloadgpsdata" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "DEVICE" ), QStringLiteral( "xxx" ) ); - parameters.insert( QStringLiteral( "PORT" ), QStringLiteral( "usb:" ) ); - parameters.insert( QStringLiteral( "FEATURE_TYPE" ), 0 ); // waypoints - parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); - - bool ok = false; - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - - QVariantMap results; - results = alg->run( parameters, *context, &feedback, &ok ); - // invalid device - QVERIFY( !ok ); - - QVERIFY( feedback.errors.value( 0 ).startsWith( QStringLiteral( "Unknown GPSBabel device \u201Cxxx\u201D. Valid devices are:" ) ) ); - feedback.errors.clear(); - - parameters.insert( QStringLiteral( "DEVICE" ), QStringLiteral( "Garmin serial" ) ); - parameters.insert( QStringLiteral( "PORT" ), QStringLiteral( "not a port" ) ); - ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - // invalid port - QVERIFY( !ok ); - QVERIFY( feedback.errors.value( 0 ).startsWith( QStringLiteral( "Unknown port \u201Cnot a port\u201D. Valid ports are:" ) ) ); - feedback.errors.clear(); -} - -void TestQgsProcessingAlgs::uploadGpsData() -{ - TestProcessingFeedback feedback; - - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:downloadgpsdata" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "DEVICE" ), QStringLiteral( "xxx" ) ); - parameters.insert( QStringLiteral( "PORT" ), QStringLiteral( "usb:" ) ); - parameters.insert( QStringLiteral( "FEATURE_TYPE" ), 0 ); // waypoints - parameters.insert( QStringLiteral( "INPUT" ), QStringLiteral( "%1/layers.gpx" ).arg( TEST_DATA_DIR ) ); - - bool ok = false; - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - - QVariantMap results; - results = alg->run( parameters, *context, &feedback, &ok ); - // invalid device - QVERIFY( !ok ); - - QVERIFY( feedback.errors.value( 0 ).startsWith( QStringLiteral( "Unknown GPSBabel device \u201Cxxx\u201D. Valid devices are:" ) ) ); - feedback.errors.clear(); - - parameters.insert( QStringLiteral( "DEVICE" ), QStringLiteral( "Garmin serial" ) ); - parameters.insert( QStringLiteral( "PORT" ), QStringLiteral( "not a port" ) ); - ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - // invalid port - QVERIFY( !ok ); - QVERIFY( feedback.errors.value( 0 ).startsWith( QStringLiteral( "Unknown port \u201Cnot a port\u201D. Valid ports are:" ) ) ); - feedback.errors.clear(); -} - -void TestQgsProcessingAlgs::transferMainAnnotationLayer() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:transferannotationsfrommain" ) ) ); - QVERIFY( alg != nullptr ); - - QgsProject p; - p.mainAnnotationLayer()->addItem( new QgsAnnotationMarkerItem( QgsPoint( 1, 2 ) ) ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( &p ); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - - QVariantMap parameters; - parameters.insert( QStringLiteral( "LAYER_NAME" ), QStringLiteral( "my annotations" ) ); - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QCOMPARE( p.mainAnnotationLayer()->items().size(), 0 ); - QgsAnnotationLayer *newLayer = qobject_cast< QgsAnnotationLayer * >( p.mapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); - QCOMPARE( newLayer->name(), QStringLiteral( "my annotations" ) ); - QCOMPARE( newLayer->items().size(), 1 ); -} - -void TestQgsProcessingAlgs::exportMeshTimeSeries() -{ - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:meshexporttimeseries" ) ) ); - QVERIFY( alg != nullptr ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); - - QVariantList datasetGroup; - datasetGroup << 1 << 2 << 3; - parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); - - QVariantMap datasetStartTime; - datasetStartTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); - QVariantList datasetIndexStart; - datasetIndexStart << 1 << 0; - datasetStartTime[QStringLiteral( "value" )] = datasetIndexStart; - parameters.insert( QStringLiteral( "STARTING_TIME" ), datasetStartTime ); - - QVariantMap datasetEndTime; - datasetEndTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); - QVariantList datasetIndexEnd; - datasetIndexEnd << 1 << 1; - datasetEndTime[QStringLiteral( "value" )] = datasetIndexEnd; - parameters.insert( QStringLiteral( "FINISHING_TIME" ), datasetEndTime ); - - const QString outputPath = QDir::tempPath() + "/test_mesh_ts.csv"; - parameters.insert( QStringLiteral( "OUTPUT" ), outputPath ); - - QgsVectorLayer *layerPoints = new QgsVectorLayer( QStringLiteral( "Point" ), - QStringLiteral( "points_for_ts" ), - QStringLiteral( "memory" ) ); - - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( QgsProject::instance() ); - QgsProcessingFeedback feedback; - QVariantMap results; - bool ok = false; - - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( !ok ); - - QStringList wktPoints; - wktPoints << QStringLiteral( "Point (1500 2200)" ); - wktPoints << QStringLiteral( "Point (1500 1500)" ); - wktPoints << QStringLiteral( "Point (2500 2100)" ); - - QgsFeatureList flist; - for ( const QString &wkt : wktPoints ) - { - QgsFeature feat; - feat.setGeometry( QgsGeometry::fromWkt( wkt ) ); - flist << feat; - } - layerPoints->dataProvider()->addFeatures( flist ); - QgsProject::instance()->addMapLayer( layerPoints ); QgsProject::instance()->addMapLayer( layerPoints ); - parameters.insert( QStringLiteral( "INPUT_POINTS" ), layerPoints->name() ); - - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QFile outputFile( outputPath ); - QVERIFY( outputFile.open( QIODevice::ReadOnly ) ); - QTextStream textStream( &outputFile ); - QString header = textStream.readLine(); - QCOMPARE( header, QStringLiteral( "fid,x,y,time,VertexScalarDataset,VertexVectorDataset,FaceScalarDataset" ) ); - - QStringList expectedLines; - expectedLines << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:00:00,1.50,1.92,1.00" ) - << QStringLiteral( "1,1500.00,2200.00,1950-01-01 01:00:00,2.50,3.33,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:00:00,2.50,2.97,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 01:00:00,3.50,4.36,3.00" ); - - QString line = textStream.readLine(); - int i = 0; - QVERIFY( !line.isEmpty() ); - while ( !line.isEmpty() ) - { - QCOMPARE( line, expectedLines.at( i ) ); - ++i; - line = textStream.readLine(); - } - QVERIFY( i == expectedLines.count() ); - outputFile.close(); - - parameters.insert( QStringLiteral( "TIME_STEP" ), 0.1 ); - - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QVERIFY( outputFile.open( QIODevice::ReadOnly ) ); - header = textStream.readLine(); - QCOMPARE( header, QStringLiteral( "fid,x,y,time,VertexScalarDataset,VertexVectorDataset,FaceScalarDataset" ) ); - - expectedLines.clear(); - expectedLines << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:00:00,1.50,1.92,1.00" ) - << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:06:00,1.50,1.92,1.00" ) - << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:12:00,1.50,1.92,1.00" ) - << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:18:00,1.50,1.92,1.00" ) - << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:24:00,1.50,1.92,1.00" ) - << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:30:00,1.50,1.92,1.00" ) - << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:36:00,1.50,1.92,1.00" ) - << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:42:00,1.50,1.92,1.00" ) - << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:48:00,1.50,1.92,1.00" ) - << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:54:00,1.50,1.92,1.00" ) - << QStringLiteral( "1,1500.00,2200.00,1950-01-01 01:00:00,2.50,3.33,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:00:00,2.50,2.97,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:06:00,2.50,2.97,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:12:00,2.50,2.97,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:18:00,2.50,2.97,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:24:00,2.50,2.97,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:30:00,2.50,2.97,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:36:00,2.50,2.97,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:42:00,2.50,2.97,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:48:00,2.50,2.97,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:54:00,2.50,2.97,2.00" ) - << QStringLiteral( "3,2500.00,2100.00,1950-01-01 01:00:00,3.50,4.36,3.00" ); - - line = textStream.readLine(); - i = 0; - QVERIFY( !line.isEmpty() ); - while ( !line.isEmpty() ) - { - QCOMPARE( line, expectedLines.at( i ) ); - ++i; - line = textStream.readLine(); - } - QVERIFY( i == expectedLines.count() ); - outputFile.close(); -} - -void TestQgsProcessingAlgs::extractLabels() -{ - QgsProject project; - QgsVectorLayer *pointsLayer = new QgsVectorLayer( mPointLayerPath, - QStringLiteral( "points" ), QStringLiteral( "ogr" ) ); - QVERIFY( mPointsLayer->isValid() ); - project.addMapLayer( pointsLayer ); - - QgsTextFormat format = QgsTextFormat::fromQFont( QgsFontUtils::getStandardTestFont() ); - format.setSize( 10 ); - QgsPalLayerSettings settings; - settings.fieldName = QStringLiteral( "Class" ); - settings.setFormat( format ); - pointsLayer->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); - - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:extractlabels" ) ) ); - QVERIFY( alg != nullptr ); - - QgsReferencedRectangle extent( QgsRectangle( -120, 20, -80, 50 ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) ); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "EXTENT" ), extent ); - parameters.insert( QStringLiteral( "SCALE" ), 9000000.00 ); - parameters.insert( QStringLiteral( "DPI" ), 96.00 ); - parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); - - bool ok = false; - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - context->setProject( &project ); - QgsProcessingFeedback feedback; - - QVariantMap results; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); - QVERIFY( resultLayer ); - QCOMPARE( resultLayer->wkbType(), QgsWkbTypes::Point ); - QCOMPARE( resultLayer->featureCount(), 17 ); - - QgsFeature feature = resultLayer->getFeature( 1 ); - QVariantMap attributes = feature.attributeMap(); - QCOMPARE( attributes[QStringLiteral( "Layer" )], QStringLiteral( "points" ) ); - QCOMPARE( attributes[QStringLiteral( "FeatureID" )], 1 ); - QCOMPARE( attributes[QStringLiteral( "LabelText" )], QStringLiteral( "Biplane" ) ); - QCOMPARE( attributes[QStringLiteral( "LabelRotation" )], 0.0 ); - QCOMPARE( attributes[QStringLiteral( "Family" )], QStringLiteral( "QGIS Vera Sans" ) ); - QCOMPARE( attributes[QStringLiteral( "Size" )], 9.75 ); - QCOMPARE( attributes[QStringLiteral( "Italic" )], false ); - QCOMPARE( attributes[QStringLiteral( "Bold" )], false ); - QCOMPARE( attributes[QStringLiteral( "FontStyle" )], QStringLiteral( "Roman" ) ); - QCOMPARE( attributes[QStringLiteral( "FontLetterSpacing" )], 0.0 ); - QCOMPARE( attributes[QStringLiteral( "FontWordSpacing" )], 0.0 ); - QCOMPARE( attributes[QStringLiteral( "MultiLineAlignment" )], QStringLiteral( "left" ) ); - QCOMPARE( attributes[QStringLiteral( "MultiLineHeight" )], 1.0 ); -} - -void TestQgsProcessingAlgs::splitVectorLayer() -{ - QgsVectorLayer *layer = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=col1:string" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ); - QVERIFY( layer->isValid() ); - - QgsFeature f; - f.setAttributes( QgsAttributes() << 1 << QVariant() ); - f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "Point (0 0)" ) ) ); - layer->dataProvider()->addFeature( f ); - f.setAttributes( QgsAttributes() << 2 << QStringLiteral( "" ) ); - f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "Point (0 1)" ) ) ); - layer->dataProvider()->addFeature( f ); - f.setAttributes( QgsAttributes() << 3 << QStringLiteral( "value" ) ); - f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "Point (0 2)" ) ) ); - layer->dataProvider()->addFeature( f ); - - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:splitvectorlayer" ) ) ); - QVERIFY( alg != nullptr ); - - QDir outputDir( QDir::tempPath() + "/split_vector/" ); - if ( outputDir.exists() ) - outputDir.removeRecursively(); - - QVariantMap parameters; - parameters.insert( QStringLiteral( "INPUT" ), QVariant::fromValue( layer ) ); - parameters.insert( QStringLiteral( "FIELD" ), QStringLiteral( "col1" ) ); - parameters.insert( QStringLiteral( "FILE_TYPE" ), QStringLiteral( "gpkg" ) ); - parameters.insert( QStringLiteral( "OUTPUT" ), outputDir.absolutePath() ); - - bool ok = false; - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - QgsProcessingFeedback feedback; - QVariantMap results; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QCOMPARE( results.value( QStringLiteral( "OUTPUT_LAYERS" ) ).toList().count(), 3 ); - QDir dataDir( outputDir ); - QStringList entries = dataDir.entryList( QStringList(), QDir::Files | QDir::NoDotAndDotDot ); - QCOMPARE( entries.count(), 3 ); -} - -void TestQgsProcessingAlgs::buffer() -{ - QgsVectorLayer *layer = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=col1:string" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ); - QVERIFY( layer->isValid() ); - - std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:buffer" ) ) ); - QVERIFY( alg != nullptr ); - - // buffering empty layer should produce an empty layer - QVariantMap parameters; - parameters.insert( QStringLiteral( "INPUT" ), QVariant::fromValue( layer ) ); - parameters.insert( QStringLiteral( "DISTANCE" ), 2.0 ); - parameters.insert( QStringLiteral( "SEGMENTS" ), 5 ); - parameters.insert( QStringLiteral( "END_CAP_STYLE" ), 0 ); - parameters.insert( QStringLiteral( "JOIN_STYLE" ), 0 ); - parameters.insert( QStringLiteral( "MITER_LIMIT" ), 0 ); - parameters.insert( QStringLiteral( "DISSOLVE" ), false ); - parameters.insert( QStringLiteral( "OUTPUT" ), QStringLiteral( "memory:" ) ); - - bool ok = false; - std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); - QgsProcessingFeedback feedback; - QVariantMap results; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QVERIFY( !results.value( QStringLiteral( "OUTPUT" ) ).toString().isEmpty() ); - QgsVectorLayer *bufferedLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); - QVERIFY( bufferedLayer->isValid() ); - QCOMPARE( bufferedLayer->wkbType(), QgsWkbTypes::MultiPolygon ); - QCOMPARE( bufferedLayer->featureCount(), layer->featureCount() ); - - // buffering empty layer with dissolve should produce an empty layer - parameters.insert( QStringLiteral( "DISSOLVE" ), true ); - - ok = false; - results = alg->run( parameters, *context, &feedback, &ok ); - QVERIFY( ok ); - - QVERIFY( !results.value( QStringLiteral( "OUTPUT" ) ).toString().isEmpty() ); - bufferedLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); - QVERIFY( bufferedLayer->isValid() ); - QCOMPARE( bufferedLayer->wkbType(), QgsWkbTypes::MultiPolygon ); - QCOMPARE( bufferedLayer->featureCount(), layer->featureCount() ); -} - -bool TestQgsProcessingAlgs::imageCheck( const QString &testName, const QString &renderedImage ) +bool TestQgsProcessingAlgsPt1::imageCheck( const QString &testName, const QString &renderedImage ) { QgsRenderChecker checker; checker.setControlPathPrefix( QStringLiteral( "processing_algorithm" ) ); @@ -7335,5 +5759,5 @@ bool TestQgsProcessingAlgs::imageCheck( const QString &testName, const QString & return equal; } -QGSTEST_MAIN( TestQgsProcessingAlgs ) -#include "testqgsprocessingalgs.moc" +QGSTEST_MAIN( TestQgsProcessingAlgsPt1 ) +#include "testqgsprocessingalgspt1.moc" diff --git a/tests/src/analysis/testqgsprocessingalgspt2.cpp b/tests/src/analysis/testqgsprocessingalgspt2.cpp new file mode 100644 index 000000000000..045e51f1a940 --- /dev/null +++ b/tests/src/analysis/testqgsprocessingalgspt2.cpp @@ -0,0 +1,1883 @@ +/*************************************************************************** + testqgsprocessingalgspt2.cpp + --------------------- + begin : November 2017 + copyright : (C) 2017 by Nyall Dawson + email : nyall dot dawson at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "limits" + +#include "qgstest.h" +#include "qgsprocessingregistry.h" +#include "qgsprocessingprovider.h" +#include "qgsprocessingutils.h" +#include "qgsprocessingalgorithm.h" +#include "qgsprocessingcontext.h" +#include "qgsprocessingmodelalgorithm.h" +#include "qgsnativealgorithms.h" +#include "qgsalgorithmfillnodata.h" +#include "qgsalgorithmlinedensity.h" +#include "qgsalgorithmimportphotos.h" +#include "qgsalgorithmtransform.h" +#include "qgsalgorithmkmeansclustering.h" +#include "qgsvectorlayer.h" +#include "qgscategorizedsymbolrenderer.h" +#include "qgssinglesymbolrenderer.h" +#include "qgsmultipolygon.h" +#include "qgsrasteranalysisutils.h" +#include "qgsrasteranalysisutils.cpp" +#include "qgsrasterfilewriter.h" +#include "qgsreclassifyutils.h" +#include "qgsalgorithmrasterlogicalop.h" +#include "qgsprintlayout.h" +#include "qgslayertree.h" +#include "qgslayoutmanager.h" +#include "qgslayoutitemmap.h" +#include "qgsmarkersymbollayer.h" +#include "qgsrulebasedrenderer.h" +#include "qgspallabeling.h" +#include "qgsrastershader.h" +#include "qgssinglebandpseudocolorrenderer.h" +#include "qgslayoutitemscalebar.h" +#include "annotations/qgstextannotation.h" +#include "qgsfontutils.h" +#include "annotations/qgsannotationmanager.h" +#include "qgsvectorlayerlabeling.h" +#include "qgsstyle.h" +#include "qgsbookmarkmanager.h" +#include "qgsexpressioncontextutils.h" +#include "qgsrenderchecker.h" +#include "qgsrelationmanager.h" +#include "qgsmeshlayer.h" +#include "qgsmarkersymbol.h" +#include "qgsfillsymbol.h" +#include "qgsalgorithmgpsbabeltools.h" +#include "qgsannotationlayer.h" +#include "qgsannotationmarkeritem.h" +#include "qgscolorrampimpl.h" +#include "qgstextformat.h" + +class TestQgsProcessingAlgsPt2: public QObject +{ + Q_OBJECT + + private: + + /** + * Helper function to get a feature based algorithm. + */ + std::unique_ptr featureBasedAlg( const QString &id ); + + QgsFeature runForFeature( const std::unique_ptr &alg, QgsFeature feature, const QString &layerType, QVariantMap parameters = QVariantMap() ); + + 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 init() {} // will be called before each testfunction is executed. + void cleanup() {} // will be called after every testfunction. + +#ifndef QT_NO_PRINTER + void exportLayoutPdf(); + void exportLayoutPng(); + void exportAtlasLayoutPdf(); + void exportAtlasLayoutPdfMultiple(); + void exportAtlasLayoutPng(); +#endif + + void tinMeshCreation(); + void exportMeshVertices(); + void exportMeshFaces(); + void exportMeshEdges(); + void exportMeshOnGrid(); + void rasterizeMesh(); + void exportMeshContours(); + void exportMeshCrossSection(); + void exportMeshTimeSeries(); + + void fileDownloader(); + + void rasterize(); + + void convertGpxFeatureType(); + void convertGpsData(); + void downloadGpsData(); + void uploadGpsData(); + void transferMainAnnotationLayer(); + + void extractLabels(); + + void splitVectorLayer(); + void buffer(); + + private: + + bool imageCheck( const QString &testName, const QString &renderedImage ); + + QString mPointLayerPath; + QgsVectorLayer *mPointsLayer = nullptr; + QgsVectorLayer *mPolygonLayer = nullptr; + + void exportToSpreadsheet( const QString &outputPath ); +}; + +std::unique_ptr TestQgsProcessingAlgsPt2::featureBasedAlg( const QString &id ) +{ + return std::unique_ptr( static_cast( QgsApplication::processingRegistry()->createAlgorithmById( id ) ) ); +} + +QgsFeature TestQgsProcessingAlgsPt2::runForFeature( const std::unique_ptr< QgsProcessingFeatureBasedAlgorithm > &alg, QgsFeature feature, const QString &layerType, QVariantMap parameters ) +{ + Q_ASSERT( alg.get() ); + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + QgsProject p; + context->setProject( &p ); + + QgsProcessingFeedback feedback; + context->setFeedback( &feedback ); + + std::unique_ptr inputLayer( std::make_unique( layerType, QStringLiteral( "layer" ), QStringLiteral( "memory" ) ) ); + inputLayer->dataProvider()->addFeature( feature ); + + parameters.insert( QStringLiteral( "INPUT" ), QVariant::fromValue( inputLayer.get() ) ); + + parameters.insert( QStringLiteral( "OUTPUT" ), QStringLiteral( "memory:" ) ); + + bool ok = false; + const auto res = alg->run( parameters, *context, &feedback, &ok ); + QgsFeature result; + + std::unique_ptr outputLayer( qobject_cast< QgsVectorLayer * >( context->getMapLayer( res.value( QStringLiteral( "OUTPUT" ) ).toString() ) ) ); + outputLayer->getFeatures().nextFeature( result ); + + return result; +} + +void TestQgsProcessingAlgsPt2::initTestCase() +{ + QgsApplication::init(); + QgsApplication::initQgis(); + + // Set up the QgsSettings environment + QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) ); + QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) ); + QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) ); + + QgsApplication::processingRegistry()->addProvider( new QgsNativeAlgorithms( QgsApplication::processingRegistry() ) ); + + const QString dataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt + + const QString pointsFileName = dataDir + "/points.shp"; + const QFileInfo pointFileInfo( pointsFileName ); + mPointLayerPath = pointFileInfo.filePath(); + mPointsLayer = new QgsVectorLayer( mPointLayerPath, + QStringLiteral( "points" ), QStringLiteral( "ogr" ) ); + QVERIFY( mPointsLayer->isValid() ); + // Register the layer with the registry + QgsProject::instance()->addMapLayers( + QList() << mPointsLayer ); + + // + //create a poly layer that will be used in all tests... + // + const QString polysFileName = dataDir + "/polys.shp"; + const QFileInfo polyFileInfo( polysFileName ); + mPolygonLayer = new QgsVectorLayer( polyFileInfo.filePath(), + QStringLiteral( "polygons" ), QStringLiteral( "ogr" ) ); + // Register the layer with the registry + QgsProject::instance()->addMapLayers( + QList() << mPolygonLayer ); + QVERIFY( mPolygonLayer->isValid() ); + + //add a mesh layer + const QString uri( dataDir + "/mesh/quad_and_triangle.2dm" ); + const QString meshLayerName = QStringLiteral( "mesh layer" ); + QgsMeshLayer *meshLayer = new QgsMeshLayer( uri, meshLayerName, QStringLiteral( "mdal" ) ); + // Register the layer with the registry + QgsProject::instance()->addMapLayer( meshLayer ); + QVERIFY( meshLayer->isValid() ); + meshLayer->addDatasets( dataDir + "/mesh/quad_and_triangle_vertex_scalar.dat" ); + meshLayer->addDatasets( dataDir + "/mesh/quad_and_triangle_vertex_vector.dat" ); + meshLayer->addDatasets( dataDir + "/mesh/quad_and_triangle_els_face_scalar.dat" ); + meshLayer->addDatasets( dataDir + "/mesh/quad_and_triangle_els_face_vector.dat" ); + QCOMPARE( meshLayer->datasetGroupCount(), 5 ); + + //add a 1D mesh layer + const QString uri1d( dataDir + "/mesh/lines.2dm" ); + const QString meshLayer1dName = QStringLiteral( "mesh layer 1D" ); + QgsMeshLayer *meshLayer1d = new QgsMeshLayer( uri1d, meshLayer1dName, QStringLiteral( "mdal" ) ); + // Register the layer with the registry + QgsProject::instance()->addMapLayer( meshLayer1d ); + QVERIFY( meshLayer1d->isValid() ); + meshLayer1d->addDatasets( dataDir + "/mesh/lines_els_scalar.dat" ); + meshLayer1d->addDatasets( dataDir + "/mesh/lines_els_vector.dat" ); + QCOMPARE( meshLayer1d->datasetGroupCount(), 3 ); +} + +void TestQgsProcessingAlgsPt2::cleanupTestCase() +{ + QgsApplication::exitQgis(); +} + +QVariantMap pkgAlg( const QStringList &layers, const QString &outputGpkg, bool overwrite, bool selectedFeaturesOnly, bool saveMetadata, bool *ok ) +{ + const QgsProcessingAlgorithm *package( QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:package" ) ) ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( QgsProject::instance() ); + + QgsProcessingFeedback feedback; + + QVariantMap parameters; + parameters.insert( QStringLiteral( "LAYERS" ), layers ); + parameters.insert( QStringLiteral( "OUTPUT" ), outputGpkg ); + parameters.insert( QStringLiteral( "OVERWRITE" ), overwrite ); + parameters.insert( QStringLiteral( "SELECTED_FEATURES_ONLY" ), selectedFeaturesOnly ); + parameters.insert( QStringLiteral( "SAVE_METADATA" ), saveMetadata ); + return package->run( parameters, *context, &feedback, ok ); +} + +void TestQgsProcessingAlgsPt2::exportToSpreadsheet( const QString &outputPath ) +{ + if ( QFile::exists( outputPath ) ) + QFile::remove( outputPath ); + + QVariantMap parameters; + const QStringList layers = QStringList() << mPointsLayer->id() << mPolygonLayer->id(); + bool ok = false; + + const QgsProcessingAlgorithm *alg( QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:exporttospreadsheet" ) ) ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( QgsProject::instance() ); + + QgsProcessingFeedback feedback; + + parameters.insert( QStringLiteral( "LAYERS" ), layers ); + parameters.insert( QStringLiteral( "OUTPUT" ), outputPath ); + parameters.insert( QStringLiteral( "OVERWRITE" ), false ); + const QVariantMap results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QVERIFY( !results.value( QStringLiteral( "OUTPUT" ) ).toString().isEmpty() ); + std::unique_ptr< QgsVectorLayer > pointLayer = std::make_unique< QgsVectorLayer >( outputPath + "|layername=points", "points", "ogr" ); + QVERIFY( pointLayer->isValid() ); + QCOMPARE( pointLayer->featureCount(), mPointsLayer->featureCount() ); + pointLayer.reset(); + std::unique_ptr< QgsVectorLayer > polygonLayer = std::make_unique< QgsVectorLayer >( outputPath + "|layername=polygons", "polygons", "ogr" ); + QVERIFY( polygonLayer->isValid() ); + QCOMPARE( polygonLayer->featureCount(), mPolygonLayer->featureCount() ); + polygonLayer.reset(); + + std::unique_ptr rectangles = std::make_unique( QStringLiteral( TEST_DATA_DIR ) + "/rectangles.shp", + QStringLiteral( "rectangles" ), QStringLiteral( "ogr" ) ); + QgsProject::instance()->addMapLayers( QList() << rectangles.get() ); + + // Test adding an additional layer (overwrite disabled) + parameters.insert( QStringLiteral( "LAYERS" ), QStringList() << rectangles->id() ); + const QVariantMap results2 = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QVERIFY( !results2.value( QStringLiteral( "OUTPUT" ) ).toString().isEmpty() ); + std::unique_ptr< QgsVectorLayer > rectanglesPackagedLayer = std::make_unique< QgsVectorLayer >( outputPath + "|layername=rectangles", "points", "ogr" ); + QVERIFY( rectanglesPackagedLayer->isValid() ); + QCOMPARE( rectanglesPackagedLayer->featureCount(), rectangles->featureCount() ); + rectanglesPackagedLayer.reset(); + + pointLayer = std::make_unique< QgsVectorLayer >( outputPath + "|layername=points", "points", "ogr" ); + QVERIFY( pointLayer->isValid() ); + pointLayer.reset(); + + // And finally, test with overwrite enabled + parameters.insert( QStringLiteral( "OVERWRITE" ), true ); + const QVariantMap results3 = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QVERIFY( !results3.value( QStringLiteral( "OUTPUT" ) ).toString().isEmpty() ); + rectanglesPackagedLayer = std::make_unique< QgsVectorLayer >( outputPath + "|layername=rectangles", "points", "ogr" ); + QVERIFY( rectanglesPackagedLayer->isValid() ); + QCOMPARE( rectanglesPackagedLayer->featureCount(), rectangles->featureCount() ); + + pointLayer = std::make_unique< QgsVectorLayer >( outputPath + "|layername=points", "points", "ogr" ); + QVERIFY( !pointLayer->isValid() ); // It's gone -- the xlsx was recreated with a single layer +} + +#ifndef QT_NO_PRINTER +void TestQgsProcessingAlgsPt2::exportLayoutPdf() +{ + QgsProject p; + QgsPrintLayout *layout = new QgsPrintLayout( &p ); + layout->initializeDefaults(); + layout->setName( QStringLiteral( "my layout" ) ); + p.layoutManager()->addLayout( layout ); + + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:printlayouttopdf" ) ) ); + QVERIFY( alg != nullptr ); + + const QString outputPdf = QDir::tempPath() + "/my_layout.pdf"; + if ( QFile::exists( outputPdf ) ) + QFile::remove( outputPdf ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "missing" ) ); + parameters.insert( QStringLiteral( "OUTPUT" ), outputPdf ); + + bool ok = false; + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( &p ); + QgsProcessingFeedback feedback; + QVariantMap results; + results = alg->run( parameters, *context, &feedback, &ok ); + // invalid layout name + QVERIFY( !ok ); + QVERIFY( !QFile::exists( outputPdf ) ); + + parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "my layout" ) ); + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QVERIFY( QFile::exists( outputPdf ) ); +} + +void TestQgsProcessingAlgsPt2::exportLayoutPng() +{ + QgsProject p; + QgsPrintLayout *layout = new QgsPrintLayout( &p ); + layout->initializeDefaults(); + layout->setName( QStringLiteral( "my layout" ) ); + + QgsLayoutItemMap *map = new QgsLayoutItemMap( layout ); + map->setBackgroundEnabled( false ); + map->setFrameEnabled( false ); + map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) ); + layout->addLayoutItem( map ); + map->setExtent( mPointsLayer->extent() ); + + p.layoutManager()->addLayout( layout ); + + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:printlayouttoimage" ) ) ); + QVERIFY( alg != nullptr ); + + QString outputPng = QDir::tempPath() + "/my_layout.png"; + if ( QFile::exists( outputPng ) ) + QFile::remove( outputPng ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "missing" ) ); + parameters.insert( QStringLiteral( "OUTPUT" ), outputPng ); + + bool ok = false; + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( &p ); + QgsProcessingFeedback feedback; + QVariantMap results; + results = alg->run( parameters, *context, &feedback, &ok ); + // invalid layout name + QVERIFY( !ok ); + QVERIFY( !QFile::exists( outputPng ) ); + + parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "my layout" ) ); + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + QVERIFY( QFile::exists( outputPng ) ); + + outputPng = QDir::tempPath() + "/my_layout_custom_layers.png"; + if ( QFile::exists( outputPng ) ) + QFile::remove( outputPng ); + + parameters.insert( QStringLiteral( "OUTPUT" ), outputPng ); + parameters.insert( QStringLiteral( "LAYERS" ), QVariantList() << QVariant::fromValue( mPointsLayer ) ); + parameters.insert( QStringLiteral( "DPI" ), 96 ); + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + QVERIFY( QFile::exists( outputPng ) ); + QVERIFY( imageCheck( "export_layout_custom_layers", outputPng ) ); +} + +void TestQgsProcessingAlgsPt2::exportAtlasLayoutPdf() +{ + QgsMapLayer *polygonLayer = mPolygonLayer->clone(); + QgsProject p; + p.addMapLayers( QList() << polygonLayer ); + + QgsPrintLayout *layout = new QgsPrintLayout( &p ); + layout->initializeDefaults(); + layout->setName( QStringLiteral( "my layout" ) ); + + QgsLayoutItemMap *map = new QgsLayoutItemMap( layout ); + map->setBackgroundEnabled( false ); + map->setFrameEnabled( false ); + map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) ); + layout->addLayoutItem( map ); + map->setExtent( polygonLayer->extent() ); + + p.layoutManager()->addLayout( layout ); + + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:atlaslayouttopdf" ) ) ); + QVERIFY( alg != nullptr ); + + const QString outputPdf = QDir::tempPath() + "/my_atlas_layout.pdf"; + if ( QFile::exists( outputPdf ) ) + QFile::remove( outputPdf ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "my layout" ) ); + parameters.insert( QStringLiteral( "COVERAGE_LAYER" ), QVariant::fromValue( polygonLayer ) ); + parameters.insert( QStringLiteral( "OUTPUT" ), outputPdf ); + parameters.insert( QStringLiteral( "DPI" ), 96 ); + + bool ok = false; + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( &p ); + QgsProcessingFeedback feedback; + QVariantMap results; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QVERIFY( QFile::exists( outputPdf ) ); +} + +void TestQgsProcessingAlgsPt2::exportAtlasLayoutPdfMultiple() +{ + QgsMapLayer *polygonLayer = mPolygonLayer->clone(); + QgsProject p; + p.addMapLayers( QList() << polygonLayer ); + + QgsPrintLayout *layout = new QgsPrintLayout( &p ); + layout->initializeDefaults(); + layout->setName( QStringLiteral( "my layout" ) ); + + QgsLayoutItemMap *map = new QgsLayoutItemMap( layout ); + map->setBackgroundEnabled( false ); + map->setFrameEnabled( false ); + map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) ); + layout->addLayoutItem( map ); + map->setExtent( polygonLayer->extent() ); + + p.layoutManager()->addLayout( layout ); + + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:atlaslayouttomultiplepdf" ) ) ); + QVERIFY( alg != nullptr ); + + const QString outputPdfDir = QDir::tempPath() + "/atlas_pdf"; + if ( QFile::exists( outputPdfDir ) ) + QDir().rmdir( outputPdfDir ); + + QDir().mkdir( outputPdfDir ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "my layout" ) ); + parameters.insert( QStringLiteral( "COVERAGE_LAYER" ), QVariant::fromValue( polygonLayer ) ); + parameters.insert( QStringLiteral( "OUTPUT_FOLDER" ), outputPdfDir ); + parameters.insert( QStringLiteral( "DPI" ), 96 ); + + bool ok = false; + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( &p ); + QgsProcessingFeedback feedback; + QVariantMap results; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QVERIFY( QFile::exists( outputPdfDir + "/output_1.pdf" ) ); + QVERIFY( QFile::exists( outputPdfDir + "/output_2.pdf" ) ); + QVERIFY( QFile::exists( outputPdfDir + "/output_3.pdf" ) ); +} + +void TestQgsProcessingAlgsPt2::exportAtlasLayoutPng() +{ + QgsMapLayer *polygonLayer = mPolygonLayer->clone(); + QgsProject p; + p.addMapLayers( QList() << polygonLayer ); + + QgsPrintLayout *layout = new QgsPrintLayout( &p ); + layout->initializeDefaults(); + layout->setName( QStringLiteral( "my layout" ) ); + + QgsLayoutItemMap *map = new QgsLayoutItemMap( layout ); + map->setBackgroundEnabled( false ); + map->setFrameEnabled( false ); + map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) ); + layout->addLayoutItem( map ); + map->setExtent( polygonLayer->extent() ); + + p.layoutManager()->addLayout( layout ); + + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:atlaslayouttoimage" ) ) ); + QVERIFY( alg != nullptr ); + + const QDir tempDir( QDir::tempPath() ); + if ( !tempDir.mkdir( "my_atlas" ) ) + { + const QDir dir( QDir::tempPath() + "/my_atlas" ); + const QStringList files = dir.entryList( QStringList() << "*.*", QDir::Files ); + for ( const QString &file : files ) + QFile::remove( QDir::tempPath() + "/my_atlas/" + file ); + } + + QVariantMap parameters; + parameters.insert( QStringLiteral( "LAYOUT" ), QStringLiteral( "my layout" ) ); + parameters.insert( QStringLiteral( "COVERAGE_LAYER" ), QVariant::fromValue( polygonLayer ) ); + parameters.insert( QStringLiteral( "FOLDER" ), QString( QDir::tempPath() + "/my_atlas" ) ); + parameters.insert( QStringLiteral( "FILENAME_EXPRESSION" ), QStringLiteral( "'export_'||@atlas_featurenumber" ) ); + parameters.insert( QStringLiteral( "DPI" ), 96 ); + + bool ok = false; + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( &p ); + QgsProcessingFeedback feedback; + QVariantMap results; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QVERIFY( QFile::exists( QDir::tempPath() + "/my_atlas/export_1.png" ) ); + QVERIFY( QFile::exists( QDir::tempPath() + "/my_atlas/export_10.png" ) ); + QVERIFY( imageCheck( "export_atlas", QDir::tempPath() + "/my_atlas/export_1.png" ) ); + + parameters[QStringLiteral( "FILENAME_EXPRESSION" )] = QStringLiteral( "'custom_'||@atlas_featurenumber" ); + parameters.insert( QStringLiteral( "LAYERS" ), QVariantList() << QVariant::fromValue( mPointsLayer ) ); + + ok = false; + results.clear(); + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QVERIFY( QFile::exists( QDir::tempPath() + "/my_atlas/custom_1.png" ) ); + QVERIFY( QFile::exists( QDir::tempPath() + "/my_atlas/custom_10.png" ) ); + QVERIFY( imageCheck( "export_atlas_custom_layers", QDir::tempPath() + "/my_atlas/custom_1.png" ) ); +} +#endif + +void TestQgsProcessingAlgsPt2::tinMeshCreation() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:tinmeshcreation" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantList inputLayers; + + QVariantMap pointLayer; + pointLayer[QStringLiteral( "source" )] = "points"; + pointLayer[QStringLiteral( "type" )] = 0; + pointLayer[QStringLiteral( "attributeIndex" )] = mPointsLayer->fields().indexOf( "Importance" ); + + inputLayers.append( pointLayer ); + + QVariantMap polyLayer; + polyLayer[QStringLiteral( "source" )] = "polygons"; + polyLayer[QStringLiteral( "type" )] = 2; + polyLayer[QStringLiteral( "attributeIndex" )] = mPolygonLayer->fields().indexOf( "Value" ); + + inputLayers.append( polyLayer ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "SOURCE_DATA" ), inputLayers ); + parameters.insert( QStringLiteral( "OUTPUT_MESH" ), QString( QDir::tempPath() + "/meshLayer.2dm" ) ); + parameters.insert( QStringLiteral( "MESH_FORMAT" ), 0 ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( QgsProject::instance() ); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QgsMeshLayer meshLayer( QDir::tempPath() + "/meshLayer.2dm", "mesh", "mdal" ); + QVERIFY( meshLayer.isValid() ); + + QgsMeshDataProvider *provider = meshLayer.dataProvider(); + QCOMPARE( provider->vertexCount(), 627 ); + QCOMPARE( provider->faceCount(), 1218 ); + + meshLayer.updateTriangularMesh(); + QVERIFY( qgsDoubleNear( meshLayer.datasetValue( QgsMeshDatasetIndex( 0, 0 ), QgsPointXY( -103.0, 39.0 ) ).scalar(), 20.0, 0.001 ) ); + QVERIFY( qgsDoubleNear( meshLayer.datasetValue( QgsMeshDatasetIndex( 0, 0 ), QgsPointXY( -86.0, 35.0 ) ).scalar(), 1.855, 0.001 ) ) ; +} + +void TestQgsProcessingAlgsPt2::exportMeshVertices() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:exportmeshvertices" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); + + QVariantList datasetGroup; + datasetGroup << 1 << 2; + parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); + + QVariantMap datasetTime; + datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); + QVariantList datasetIndex; + datasetIndex << 1 << 1; + datasetTime[QStringLiteral( "value" )] = datasetIndex; + parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); + + parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); + parameters.insert( QStringLiteral( "VECTOR_OPTION" ), 2 ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( QgsProject::instance() ); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); + QVERIFY( resultLayer ); + QVERIFY( resultLayer->isValid() ); + QVERIFY( resultLayer->geometryType() == QgsWkbTypes::PointGeometry ); + QCOMPARE( resultLayer->featureCount(), 5l ); + const QgsAttributeList attributeList = resultLayer->attributeList(); + QCOMPARE( resultLayer->fields().count(), 5 ); + QCOMPARE( resultLayer->fields().at( 0 ).name(), QStringLiteral( "VertexScalarDataset" ) ); + QCOMPARE( resultLayer->fields().at( 1 ).name(), QStringLiteral( "VertexVectorDataset_x" ) ); + QCOMPARE( resultLayer->fields().at( 2 ).name(), QStringLiteral( "VertexVectorDataset_y" ) ); + QCOMPARE( resultLayer->fields().at( 3 ).name(), QStringLiteral( "VertexVectorDataset_mag" ) ); + QCOMPARE( resultLayer->fields().at( 4 ).name(), QStringLiteral( "VertexVectorDataset_dir" ) ); + + QgsFeatureIterator featIt = resultLayer->getFeatures(); + QgsFeature feat; + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "PointZ (1000 2000 20)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toDouble(), 2.0 ); + QCOMPARE( feat.attributes().at( 1 ).toDouble(), 2.0 ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.0 ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 2.828, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); + + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "PointZ (2000 2000 30)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toDouble(), 3.0 ); + QCOMPARE( feat.attributes().at( 1 ).toDouble(), 3.0 ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.0 ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 3.605, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 56.3099, 2 ) ); + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "PointZ (3000 2000 40)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toDouble(), 4.0 ); + QCOMPARE( feat.attributes().at( 1 ).toDouble(), 4.0 ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 3.0 ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 5.0, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 53.130, 2 ) ); + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "PointZ (2000 3000 50)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toDouble(), 3.0 ); + QCOMPARE( feat.attributes().at( 1 ).toDouble(), 3.0 ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 3.0 ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 4.242, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45, 2 ) ); + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "PointZ (1000 3000 10)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toDouble(), 2.0 ); + QCOMPARE( feat.attributes().at( 1 ).toDouble(), 2.0 ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), -1.0 ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 2.236, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 116.565, 2 ) ); +} + +void TestQgsProcessingAlgsPt2::exportMeshFaces() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:exportmeshfaces" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); + + QVariantList datasetGroup; + datasetGroup << 3 << 4; + parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); + + QVariantMap datasetTime; + datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); + QVariantList datasetIndex; + datasetIndex << 1 << 1; + datasetTime[QStringLiteral( "value" )] = datasetIndex; + parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); + + parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); + parameters.insert( QStringLiteral( "VECTOR_OPTION" ), 2 ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( QgsProject::instance() ); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); + QVERIFY( resultLayer ); + QVERIFY( resultLayer->isValid() ); + QVERIFY( resultLayer->geometryType() == QgsWkbTypes::PolygonGeometry ); + QCOMPARE( resultLayer->featureCount(), 2l ); + const QgsAttributeList attributeList = resultLayer->attributeList(); + QCOMPARE( resultLayer->fields().count(), 5 ); + QCOMPARE( resultLayer->fields().at( 0 ).name(), QStringLiteral( "FaceScalarDataset" ) ); + QCOMPARE( resultLayer->fields().at( 1 ).name(), QStringLiteral( "FaceVectorDataset_x" ) ); + QCOMPARE( resultLayer->fields().at( 2 ).name(), QStringLiteral( "FaceVectorDataset_y" ) ); + QCOMPARE( resultLayer->fields().at( 3 ).name(), QStringLiteral( "FaceVectorDataset_mag" ) ); + QCOMPARE( resultLayer->fields().at( 4 ).name(), QStringLiteral( "FaceVectorDataset_dir" ) ); + + QgsFeatureIterator featIt = resultLayer->getFeatures(); + QgsFeature feat; + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "PolygonZ ((1000 2000 20, 2000 2000 30, 2000 3000 50, 1000 3000 10, 1000 2000 20))" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toDouble(), 2.0 ); + QCOMPARE( feat.attributes().at( 1 ).toDouble(), 2.0 ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.0 ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 2.828, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); + + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "PolygonZ ((2000 2000 30, 3000 2000 40, 2000 3000 50, 2000 2000 30))" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toDouble(), 3.0 ); + QCOMPARE( feat.attributes().at( 1 ).toDouble(), 3.0 ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 3.0 ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 4.242, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); +} + +void TestQgsProcessingAlgsPt2::exportMeshEdges() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:exportmeshedges" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "INPUT" ), "mesh layer 1D" ); + + QVariantList datasetGroup; + datasetGroup << 1 << 2; + parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); + + QVariantMap datasetTime; + datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); + QVariantList datasetIndex; + datasetIndex << 1 << 1; + datasetTime[QStringLiteral( "value" )] = datasetIndex; + parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); + + parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); + parameters.insert( QStringLiteral( "VECTOR_OPTION" ), 2 ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( QgsProject::instance() ); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); + QVERIFY( resultLayer ); + QVERIFY( resultLayer->isValid() ); + QVERIFY( resultLayer->geometryType() == QgsWkbTypes::LineGeometry ); + QCOMPARE( resultLayer->featureCount(), 3l ); + const QgsAttributeList attributeList = resultLayer->attributeList(); + QCOMPARE( resultLayer->fields().count(), 5 ); + QCOMPARE( resultLayer->fields().at( 0 ).name(), QStringLiteral( "EdgeScalarDataset" ) ); + QCOMPARE( resultLayer->fields().at( 1 ).name(), QStringLiteral( "EdgeVectorDataset_x" ) ); + QCOMPARE( resultLayer->fields().at( 2 ).name(), QStringLiteral( "EdgeVectorDataset_y" ) ); + QCOMPARE( resultLayer->fields().at( 3 ).name(), QStringLiteral( "EdgeVectorDataset_mag" ) ); + QCOMPARE( resultLayer->fields().at( 4 ).name(), QStringLiteral( "EdgeVectorDataset_dir" ) ); + + QgsFeatureIterator featIt = resultLayer->getFeatures(); + QgsFeature feat; + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "LineStringZ (1000 2000 20, 2000 2000 30)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toDouble(), 2.0 ); + QCOMPARE( feat.attributes().at( 1 ).toDouble(), 2.0 ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.0 ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 2.828, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); + + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "LineStringZ (2000 2000 30, 3000 2000 40)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toDouble(), 3.0 ); + QCOMPARE( feat.attributes().at( 1 ).toDouble(), 3.0 ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 3.0 ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 4.242, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); + + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "LineStringZ (3000 2000 40, 2000 3000 50)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toDouble(), 4.0 ); + QCOMPARE( feat.attributes().at( 1 ).toDouble(), 4.0 ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 4.0 ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 5.656, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) ); +} + +void TestQgsProcessingAlgsPt2::exportMeshOnGrid() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:exportmeshongrid" ) ) ); + QVERIFY( alg != nullptr ); + + const QString dataDir = QString( TEST_DATA_DIR ); //defined in CmakeLists.txt + const QString meshUri( dataDir + "/mesh/trap_steady_05_3D.nc" ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "INPUT" ), meshUri ); + + QVariantList datasetGroup; + for ( int i = 0; i < 12; ++i ) + datasetGroup.append( i ); + parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); + + QVariantMap datasetTime; + datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); + QVariantList datasetIndex; + datasetIndex << 1 << 1; + datasetTime[QStringLiteral( "value" )] = datasetIndex; + parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); + + parameters.insert( QStringLiteral( "GRID_SPACING" ), 25.0 ); + + parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); + parameters.insert( QStringLiteral( "VECTOR_OPTION" ), 2 ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( QgsProject::instance() ); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); + QVERIFY( resultLayer ); + QVERIFY( resultLayer->isValid() ); + QVERIFY( resultLayer->geometryType() == QgsWkbTypes::PointGeometry ); + QCOMPARE( resultLayer->featureCount(), 205l ); + const QgsAttributeList attributeList = resultLayer->attributeList(); + QCOMPARE( resultLayer->fields().count(), 21 ); + QStringList fieldsName; + fieldsName << QStringLiteral( "Bed Elevation" ) << QStringLiteral( "temperature" ) << QStringLiteral( "temperature/Maximums" ) + << QStringLiteral( "temperature/Minimums" ) << QStringLiteral( "temperature/Time at Maximums" ) << QStringLiteral( "temperature/Time at Minimums" ) + << QStringLiteral( "velocity_x" ) << QStringLiteral( "velocity_y" ) << QStringLiteral( "velocity_mag" ) << QStringLiteral( "velocity_dir" ) + << QStringLiteral( "velocity/Maximums_x" ) << QStringLiteral( "velocity/Maximums_y" ) << QStringLiteral( "velocity/Maximums_mag" ) << QStringLiteral( "velocity/Maximums_dir" ) + << QStringLiteral( "velocity/Minimums_x" ) << QStringLiteral( "velocity/Minimums_y" ) << QStringLiteral( "velocity/Minimums_mag" ) << QStringLiteral( "velocity/Minimums_dir" ) + << QStringLiteral( "velocity/Time at Maximums" ) << QStringLiteral( "velocity/Time at Minimums" ) << QStringLiteral( "water depth" ); + + for ( int i = 0; i < fieldsName.count(); ++i ) + QCOMPARE( fieldsName.at( i ), resultLayer->fields().at( i ).name() ); + + QgsFeatureIterator featIt = resultLayer->getFeatures(); + QgsFeature feat; + for ( int i = 0; i < 8; ++i ) + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "Point (25 50)" ), feat.geometry().asWkt() ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 0 ).toDouble(), -5.025, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 1 ).toDouble(), 1.424, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 2 ).toDouble(), 5.00, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 1.32e-36, 2 ) ); + QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 0.02776, 2 ) ); + +} + +void TestQgsProcessingAlgsPt2::rasterizeMesh() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:meshrasterize" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); + + QVariantList datasetGroup; + datasetGroup << 1 << 2 << 3; + parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); + + QVariantMap datasetTime; + datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); + QVariantList datasetIndex; + datasetIndex << 1 << 1; + datasetTime[QStringLiteral( "value" )] = datasetIndex; + parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); + + parameters.insert( QStringLiteral( "PIXEL_SIZE" ), 200.0 ); + + parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( QgsProject::instance() ); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + std::unique_ptr outputRaster = std::make_unique< QgsRasterLayer >( results.value( QStringLiteral( "OUTPUT" ) ).toString(), "output", "gdal" ); + QVERIFY( outputRaster ); + QVERIFY( outputRaster->isValid() ); + QgsRasterDataProvider *outputProvider = outputRaster->dataProvider(); + + QCOMPARE( outputProvider->bandCount(), 3 ); + QCOMPARE( outputProvider->xSize(), 10 ); + QCOMPARE( outputProvider->ySize(), 5 ); + + std::unique_ptr outputBlock_1( outputProvider->block( 1, outputRaster->extent(), 10, 5 ) ); + std::unique_ptr outputBlock_2( outputProvider->block( 2, outputRaster->extent(), 10, 5 ) ); + std::unique_ptr outputBlock_3( outputProvider->block( 3, outputRaster->extent(), 10, 5 ) ); + + // load expected result + const QString dataDir = QString( TEST_DATA_DIR ); //defined in CmakeLists.txt + std::unique_ptr expectedRaster = std::make_unique< QgsRasterLayer >( dataDir + "/mesh/rasterized_mesh.tif", "expected", "gdal" ); + QVERIFY( expectedRaster ); + QVERIFY( expectedRaster->isValid() ); + QgsRasterDataProvider *expectedProvider = outputRaster->dataProvider(); + std::unique_ptr expectedBlock_1( expectedProvider->block( 1, expectedRaster->extent(), 10, 5 ) ); + std::unique_ptr expectedBlock_2( expectedProvider->block( 2, expectedRaster->extent(), 10, 5 ) ); + std::unique_ptr expectedBlock_3( expectedProvider->block( 3, expectedRaster->extent(), 10, 5 ) ); + + for ( int ix = 0; ix < 10; ++ix ) + { + for ( int iy = 0; iy < 5; ++iy ) + { + if ( !( std::isnan( outputBlock_1->value( iy, ix ) ) && std::isnan( expectedBlock_1->value( iy, ix ) ) ) ) + QCOMPARE( outputBlock_1->value( iy, ix ), expectedBlock_1->value( iy, ix ) ); + if ( !( std::isnan( outputBlock_2->value( iy, ix ) ) && std::isnan( expectedBlock_2->value( iy, ix ) ) ) ) + QCOMPARE( outputBlock_2->value( iy, ix ), expectedBlock_2->value( iy, ix ) ); + if ( !( std::isnan( outputBlock_2->value( iy, ix ) ) && std::isnan( expectedBlock_2->value( iy, ix ) ) ) ) + QCOMPARE( outputBlock_3->value( iy, ix ), expectedBlock_3->value( iy, ix ) ); + } + } +} + +void TestQgsProcessingAlgsPt2::exportMeshContours() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:meshcontours" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); + + QVariantList datasetGroup; + datasetGroup << 1 << 2 << 3; + parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); + + QVariantMap datasetTime; + datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); + QVariantList datasetIndex; + datasetIndex << 1 << 1; + datasetTime[QStringLiteral( "value" )] = datasetIndex; + parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); + + parameters.insert( QStringLiteral( "OUTPUT_LINES" ), QgsProcessing::TEMPORARY_OUTPUT ); + parameters.insert( QStringLiteral( "OUTPUT_POLYGONS" ), QgsProcessing::TEMPORARY_OUTPUT ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( QgsProject::instance() ); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( !ok ); + + // min>max + parameters.insert( QStringLiteral( "INCREMENT" ), 0.5 ); + parameters.insert( QStringLiteral( "MINIMUM" ), 5.0 ); + parameters.insert( QStringLiteral( "MAXIMUM" ), 2.0 ); + + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( !ok ); + + // min-maxrun( parameters, *context, &feedback, &ok ); + QVERIFY( !ok ); + + // min-maxrun( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QgsVectorLayer *resultLinesLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT_LINES" ) ).toString() ) ); + QVERIFY( resultLinesLayer ); + QVERIFY( resultLinesLayer->isValid() ); + QgsAttributeList attributeList = resultLinesLayer->attributeList(); + QCOMPARE( resultLinesLayer->fields().count(), 3 ); + QCOMPARE( resultLinesLayer->fields().at( 0 ).name(), QStringLiteral( "group" ) ); + QCOMPARE( resultLinesLayer->fields().at( 1 ).name(), QStringLiteral( "time" ) ); + QCOMPARE( resultLinesLayer->fields().at( 2 ).name(), QStringLiteral( "value" ) ); + + QCOMPARE( resultLinesLayer->featureCount(), 4l ); + QgsFeatureIterator featIt = resultLinesLayer->getFeatures(); + QgsFeature feat; + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "LineStringZ (1250 3000 20, 1250 2250 27.5, 1250 2000 22.5)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexScalarDataset" ) ); + QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.25 ); + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "LineStringZ (1006.94319345290614365 3000 10.27772773811624596, 1000 2976.48044676110157525 10.23519553238898538)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexVectorDataset" ) ); + QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.25 ); + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "LineStringZ (2009.71706923721990279 2990.28293076277986984 49.90282930762779756, 2462.15304528350043256 2000 34.62153045283500319)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexVectorDataset" ) ); + QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 4.25 ); + featIt.nextFeature( feat ); + QCOMPARE( QStringLiteral( "LineStringZ (1500 3000 30, 1500 2500 35, 1500 2000 25)" ), feat.geometry().asWkt() ); + QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "FaceScalarDataset" ) ); + QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.25 ); + + QgsVectorLayer *resultpolygonLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT_POLYGONS" ) ).toString() ) ); + QVERIFY( resultpolygonLayer ); + QVERIFY( resultpolygonLayer->isValid() ); + attributeList = resultpolygonLayer->attributeList(); + QCOMPARE( resultpolygonLayer->fields().count(), 4 ); + QCOMPARE( resultpolygonLayer->fields().at( 0 ).name(), QStringLiteral( "group" ) ); + QCOMPARE( resultpolygonLayer->fields().at( 1 ).name(), QStringLiteral( "time" ) ); + QCOMPARE( resultpolygonLayer->fields().at( 2 ).name(), QStringLiteral( "min_value" ) ); + QCOMPARE( resultpolygonLayer->fields().at( 3 ).name(), QStringLiteral( "max_value" ) ); + + QCOMPARE( resultpolygonLayer->featureCount(), 6l ); + featIt = resultpolygonLayer->getFeatures(); + featIt.nextFeature( feat ); + QgsGeometry geom = feat.geometry(); + geom.normalize(); + QCOMPARE( geom.asWkt(), QStringLiteral( "PolygonZ ((1000 2000 20, 1000 3000 10, 1250 3000 20, 1250 2250 27.5, 1250 2000 22.5, 1000 2000 20))" ) ); + QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexScalarDataset" ) ); + QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 0.25 ); + QCOMPARE( feat.attributes().at( 3 ).toDouble(), 2.25 ); + featIt.nextFeature( feat ); + geom = feat.geometry(); + geom.normalize(); + QCOMPARE( geom.asWkt(), QStringLiteral( "PolygonZ ((1250 2000 22.5, 1250 2250 27.5, 1250 3000 20, 2000 3000 50, 3000 2000 40, 2000 2000 30, 1250 2000 22.5))" ) ); + QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexScalarDataset" ) ); + QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.25 ); + QCOMPARE( feat.attributes().at( 3 ).toDouble(), 4.25 ); + featIt.nextFeature( feat ); + geom = feat.geometry(); + geom.normalize(); + QCOMPARE( geom.asWkt( 2 ), QStringLiteral( "PolygonZ ((1000 2976.48 10.24, 1000 3000 10, 1006.94 3000 10.28, 1000 2976.48 10.24))" ) ); + QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "VertexVectorDataset" ) ); + QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 0.25 ); + QCOMPARE( feat.attributes().at( 3 ).toDouble(), 2.25 ); + featIt.nextFeature( feat ); + featIt.nextFeature( feat ); + geom = feat.geometry(); + geom.normalize(); + QCOMPARE( geom.asWkt(), QStringLiteral( "PolygonZ ((1000 2000 20, 1000 3000 10, 1500 3000 30, 1500 2500 35, 1500 2000 25, 1000 2000 20))" ) ); + QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "FaceScalarDataset" ) ); + QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 0.25 ); + QCOMPARE( feat.attributes().at( 3 ).toDouble(), 2.25 ); + featIt.nextFeature( feat ); + geom = feat.geometry(); + geom.normalize(); + QCOMPARE( geom.asWkt(), QStringLiteral( "PolygonZ ((1500 2000 25, 1500 2500 35, 1500 3000 30, 2000 3000 50, 3000 2000 40, 2000 2000 30, 1500 2000 25))" ) ); + QCOMPARE( feat.attributes().at( 0 ).toString(), QStringLiteral( "FaceScalarDataset" ) ); + QCOMPARE( feat.attributes().at( 1 ).toString(), QStringLiteral( "1950-01-01 01:00:00" ) ); + QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.25 ); + QCOMPARE( feat.attributes().at( 3 ).toDouble(), 4.25 ); + + parameters.insert( QStringLiteral( "CONTOUR_LEVEL_LIST" ), QStringLiteral( "4,2,3" ) ); + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( !ok ); + + parameters.insert( QStringLiteral( "CONTOUR_LEVEL_LIST" ), QStringLiteral( "2,2,3" ) ); + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( !ok ); + + parameters.insert( QStringLiteral( "CONTOUR_LEVEL_LIST" ), QStringLiteral( "1,2,3" ) ); + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); +} + +void TestQgsProcessingAlgsPt2::exportMeshCrossSection() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:meshexportcrosssection" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); + + QVariantList datasetGroup; + datasetGroup << 1 << 2 << 3; + parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); + + QVariantMap datasetTime; + datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); + QVariantList datasetIndex; + datasetIndex << 1 << 1; + datasetTime[QStringLiteral( "value" )] = datasetIndex; + parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime ); + + parameters.insert( QStringLiteral( "RESOLUTION" ), 100 ); + + const QString outputPath = QDir::tempPath() + "/test_mesh_xs.csv"; + parameters.insert( QStringLiteral( "OUTPUT" ), outputPath ); + + QgsVectorLayer *layerLine = new QgsVectorLayer( QStringLiteral( "LineString" ), + QStringLiteral( "lines_for_xs" ), + QStringLiteral( "memory" ) ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( QgsProject::instance() ); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( !ok ); + + QStringList wktLines; + wktLines << QStringLiteral( "LineString (1500 2200, 2500 2200)" ); + wktLines << QStringLiteral( "LineString (1500 1500, 1500 3200)" ); + + QgsFeatureList flist; + for ( const QString &wkt : wktLines ) + { + QgsFeature feat; + feat.setGeometry( QgsGeometry::fromWkt( wkt ) ); + flist << feat; + } + layerLine->dataProvider()->addFeatures( flist ); + QgsProject::instance()->addMapLayer( layerLine ); QgsProject::instance()->addMapLayer( layerLine ); + parameters.insert( QStringLiteral( "INPUT_LINES" ), layerLine->name() ); + + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QFile outputFile( outputPath ); + QVERIFY( outputFile.open( QIODevice::ReadOnly ) ); + QTextStream textStream( &outputFile ); + const QString header = textStream.readLine(); + QCOMPARE( header, QStringLiteral( "fid,x,y,offset,VertexScalarDataset,VertexVectorDataset,FaceScalarDataset" ) ); + + QStringList expectedLines; + expectedLines << QStringLiteral( "1,1500.00,2200.00,0.00,2.50,3.33,2.00" ) + << QStringLiteral( "1,1600.00,2200.00,100.00,2.60,3.41,2.00" ) + << QStringLiteral( "1,1700.00,2200.00,200.00,2.70,3.48,2.00" ) + << QStringLiteral( "1,1800.00,2200.00,300.00,2.80,3.56,2.00" ) + << QStringLiteral( "1,1900.00,2200.00,400.00,2.90,3.64,2.00" ) + << QStringLiteral( "1,2000.00,2200.00,500.00,3.00,3.72,2.00" ) + << QStringLiteral( "1,2100.00,2200.00,600.00,3.10,3.86,3.00" ) + << QStringLiteral( "1,2200.00,2200.00,700.00,3.20,4.00,3.00" ) + << QStringLiteral( "1,2300.00,2200.00,800.00,3.30,4.14,3.00" ) + << QStringLiteral( "1,2400.00,2200.00,900.00,3.40,4.28,3.00" ) + << QStringLiteral( "1,2500.00,2200.00,1000.00,3.50,4.42,3.00" ) + << QStringLiteral( "2,1500.00,1500.00,0.00, , , " ) + << QStringLiteral( "2,1500.00,1600.00,100.00, , , " ) + << QStringLiteral( "2,1500.00,1700.00,200.00, , , " ) + << QStringLiteral( "2,1500.00,1800.00,300.00, , , " ) + << QStringLiteral( "2,1500.00,1900.00,400.00, , , " ) + << QStringLiteral( "2,1500.00,2000.00,500.00,2.50,3.20,2.00" ) + << QStringLiteral( "2,1500.00,2100.00,600.00,2.50,3.26,2.00" ) + << QStringLiteral( "2,1500.00,2200.00,700.00,2.50,3.33,2.00" ) + << QStringLiteral( "2,1500.00,2300.00,800.00,2.50,3.40,2.00" ) + << QStringLiteral( "2,1500.00,2400.00,900.00,2.50,3.47,2.00" ) + << QStringLiteral( "2,1500.00,2500.00,1000.00,2.50,3.54,2.00" ) + << QStringLiteral( "2,1500.00,2600.00,1100.00,2.50,3.33,2.00" ) + << QStringLiteral( "2,1500.00,2700.00,1200.00,2.50,3.14,2.00" ) + << QStringLiteral( "2,1500.00,2800.00,1300.00,2.50,2.97,2.00" ) + << QStringLiteral( "2,1500.00,2900.00,1400.00,2.50,2.82,2.00" ) + << QStringLiteral( "2,1500.00,3000.00,1500.00,2.50,2.69,2.00" ) + << QStringLiteral( "2,1500.00,3100.00,1600.00, , , " ) + << QStringLiteral( "2,1500.00,3200.00,1700.00, , , " ); + QString line = textStream.readLine(); + int i = 0; + QVERIFY( !line.isEmpty() ); + while ( !line.isEmpty() ) + { + QCOMPARE( line, expectedLines.at( i ) ); + ++i; + line = textStream.readLine(); + } + + QVERIFY( i == expectedLines.count() ); +} + +void TestQgsProcessingAlgsPt2::fileDownloader() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:filedownloader" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "URL" ), QStringLiteral( "https://version.qgis.org/version.txt" ) ); + parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + // verify that temporary outputs have the URL file extension appended + QVERIFY( results.value( QStringLiteral( "OUTPUT" ) ).toString().endsWith( QLatin1String( ".txt" ) ) ); +} + +void TestQgsProcessingAlgsPt2::rasterize() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:rasterize" ) ) ); + QVERIFY( alg != nullptr ); + + const QString outputTif = QDir::tempPath() + "/rasterize_output.tif"; + if ( QFile::exists( outputTif ) ) + QFile::remove( outputTif ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "EXTENT" ), QStringLiteral( "-120,-80,15,55" ) ); + parameters.insert( QStringLiteral( "TILE_SIZE" ), 320 ); + parameters.insert( QStringLiteral( "MAP_UNITS_PER_PIXEL" ), 0.125 ); + parameters.insert( QStringLiteral( "OUTPUT" ), outputTif ); + + // create a temporary project with three layers, but only two are visible + // (to test that the algorithm in the default setup without defined LAYERS or MAP_THEME uses only vsisible + // layers that and in the correct order) + QgsProject project; + const QString dataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt + QgsVectorLayer *pointsLayer = new QgsVectorLayer( dataDir + "/points.shp", QStringLiteral( "points" ), QStringLiteral( "ogr" ) ); + QgsVectorLayer *linesLayer = new QgsVectorLayer( dataDir + "/lines.shp", QStringLiteral( "lines" ), QStringLiteral( "ogr" ) ); + QgsVectorLayer *polygonLayer = new QgsVectorLayer( dataDir + "/polys.shp", QStringLiteral( "polygons" ), QStringLiteral( "ogr" ) ); + QVERIFY( pointsLayer->isValid() && linesLayer->isValid() && polygonLayer->isValid() ); + project.addMapLayers( QList() << pointsLayer << linesLayer << polygonLayer ); + QgsLayerTreeLayer *nodePolygons = project.layerTreeRoot()->findLayer( polygonLayer ); + QVERIFY( nodePolygons ); + nodePolygons->setItemVisibilityChecked( false ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( &project ); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + QVERIFY( QFile::exists( outputTif ) ); + + QgsRenderChecker checker; + checker.setControlPathPrefix( QStringLiteral( "processing_algorithm" ) ); + checker.setControlExtension( "tif" ); + checker.setControlName( "expected_rasterize" ); + checker.setRenderedImage( outputTif ); + QVERIFY( checker.compareImages( "rasterize", 500 ) ); +} + +void TestQgsProcessingAlgsPt2::convertGpxFeatureType() +{ + // test generation of babel argument lists + QStringList processArgs; + QStringList logArgs; + + QgsConvertGpxFeatureTypeAlgorithm::createArgumentLists( QStringLiteral( "/home/me/my input file.gpx" ), + QStringLiteral( "/home/me/my output file.gpx" ), + QgsConvertGpxFeatureTypeAlgorithm::WaypointsFromRoute, + processArgs, logArgs ); + QCOMPARE( processArgs, QStringList( + { + QStringLiteral( "-i" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-f" ), + QStringLiteral( "/home/me/my input file.gpx" ), + QStringLiteral( "-x" ), + QStringLiteral( "transform,wpt=rte,del" ), + QStringLiteral( "-o" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-F" ), + QStringLiteral( "/home/me/my output file.gpx" ) + } ) ); + // when showing the babel command, filenames should be wrapped in "", which is what QProcess does internally (hence the processArgs don't have these) + QCOMPARE( logArgs, QStringList( + { + QStringLiteral( "-i" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-f" ), + QStringLiteral( "\"/home/me/my input file.gpx\"" ), + QStringLiteral( "-x" ), + QStringLiteral( "transform,wpt=rte,del" ), + QStringLiteral( "-o" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-F" ), + QStringLiteral( "\"/home/me/my output file.gpx\"" ) + } ) ); + + logArgs.clear(); + processArgs.clear(); + QgsConvertGpxFeatureTypeAlgorithm::createArgumentLists( QStringLiteral( "/home/me/my input file.gpx" ), + QStringLiteral( "/home/me/my output file.gpx" ), + QgsConvertGpxFeatureTypeAlgorithm::WaypointsFromTrack, + processArgs, logArgs ); + QCOMPARE( processArgs, QStringList( + { + QStringLiteral( "-i" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-f" ), + QStringLiteral( "/home/me/my input file.gpx" ), + QStringLiteral( "-x" ), + QStringLiteral( "transform,wpt=trk,del" ), + QStringLiteral( "-o" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-F" ), + QStringLiteral( "/home/me/my output file.gpx" ) + } ) ); + // when showing the babel command, filenames should be wrapped in "", which is what QProcess does internally (hence the processArgs don't have these) + QCOMPARE( logArgs, QStringList( + { + QStringLiteral( "-i" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-f" ), + QStringLiteral( "\"/home/me/my input file.gpx\"" ), + QStringLiteral( "-x" ), + QStringLiteral( "transform,wpt=trk,del" ), + QStringLiteral( "-o" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-F" ), + QStringLiteral( "\"/home/me/my output file.gpx\"" ) + } ) ); + + logArgs.clear(); + processArgs.clear(); + + QgsConvertGpxFeatureTypeAlgorithm::createArgumentLists( QStringLiteral( "/home/me/my input file.gpx" ), + QStringLiteral( "/home/me/my output file.gpx" ), + QgsConvertGpxFeatureTypeAlgorithm::RouteFromWaypoints, + processArgs, logArgs ); + QCOMPARE( processArgs, QStringList( + { + QStringLiteral( "-i" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-f" ), + QStringLiteral( "/home/me/my input file.gpx" ), + QStringLiteral( "-x" ), + QStringLiteral( "transform,rte=wpt,del" ), + QStringLiteral( "-o" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-F" ), + QStringLiteral( "/home/me/my output file.gpx" ) + } ) ); + // when showing the babel command, filenames should be wrapped in "", which is what QProcess does internally (hence the processArgs don't have these) + QCOMPARE( logArgs, QStringList( + { + QStringLiteral( "-i" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-f" ), + QStringLiteral( "\"/home/me/my input file.gpx\"" ), + QStringLiteral( "-x" ), + QStringLiteral( "transform,rte=wpt,del" ), + QStringLiteral( "-o" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-F" ), + QStringLiteral( "\"/home/me/my output file.gpx\"" ) + } ) ); + + + logArgs.clear(); + processArgs.clear(); + + QgsConvertGpxFeatureTypeAlgorithm::createArgumentLists( QStringLiteral( "/home/me/my input file.gpx" ), + QStringLiteral( "/home/me/my output file.gpx" ), + QgsConvertGpxFeatureTypeAlgorithm::TrackFromWaypoints, + processArgs, logArgs ); + QCOMPARE( processArgs, QStringList( + { + QStringLiteral( "-i" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-f" ), + QStringLiteral( "/home/me/my input file.gpx" ), + QStringLiteral( "-x" ), + QStringLiteral( "transform,trk=wpt,del" ), + QStringLiteral( "-o" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-F" ), + QStringLiteral( "/home/me/my output file.gpx" ) + } ) ); + // when showing the babel command, filenames should be wrapped in "", which is what QProcess does internally (hence the processArgs don't have these) + QCOMPARE( logArgs, QStringList( + { + QStringLiteral( "-i" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-f" ), + QStringLiteral( "\"/home/me/my input file.gpx\"" ), + QStringLiteral( "-x" ), + QStringLiteral( "transform,trk=wpt,del" ), + QStringLiteral( "-o" ), + QStringLiteral( "gpx" ), + QStringLiteral( "-F" ), + QStringLiteral( "\"/home/me/my output file.gpx\"" ) + } ) ); +} + +class TestProcessingFeedback : public QgsProcessingFeedback +{ + public: + + void reportError( const QString &error, bool ) override + { + errors << error; + } + + QStringList errors; + +}; + +void TestQgsProcessingAlgsPt2::convertGpsData() +{ + TestProcessingFeedback feedback; + + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:convertgpsdata" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "INPUT" ), QStringLiteral( "%1/GARMIN_ATRK.NVM" ).arg( TEST_DATA_DIR ) ); + parameters.insert( QStringLiteral( "FORMAT" ), QStringLiteral( "garmin_xt" ) ); + parameters.insert( QStringLiteral( "FEATURE_TYPE" ), 0 ); // waypoints + parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); + + bool ok = false; + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + + QVariantMap results; + results = alg->run( parameters, *context, &feedback, &ok ); + // garmin_xt format does not support waypoints, exception should have been raised + QVERIFY( !ok ); + + QCOMPARE( feedback.errors, QStringList() << QStringLiteral( "The GPSBabel format \u201Cgarmin_xt\u201D does not support converting waypoints." ) ); + feedback.errors.clear(); + + parameters.insert( QStringLiteral( "FEATURE_TYPE" ), 1 ); // routes + ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + // garmin_xt format does not support routes, exception should have been raised + QVERIFY( !ok ); + QCOMPARE( feedback.errors, QStringList() << QStringLiteral( "The GPSBabel format \u201Cgarmin_xt\u201D does not support converting routes." ) ); + feedback.errors.clear(); + + parameters.insert( QStringLiteral( "FEATURE_TYPE" ), 2 ); // tracks + ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + // garmin_xt format does support tracks! + QVERIFY( ok ); + + QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT_LAYER" ) ).toString() ) ); + QVERIFY( resultLayer ); + QCOMPARE( resultLayer->providerType(), QStringLiteral( "gpx" ) ); + QCOMPARE( resultLayer->wkbType(), QgsWkbTypes::LineString ); + QCOMPARE( resultLayer->featureCount(), 1LL ); + + // algorithm should also run when given the description for a format, not the format name + parameters.insert( QStringLiteral( "FORMAT" ), QStringLiteral( "Mobile Garmin XT Track files" ) ); + ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT_LAYER" ) ).toString() ) ); + QVERIFY( resultLayer ); + QCOMPARE( resultLayer->providerType(), QStringLiteral( "gpx" ) ); + QCOMPARE( resultLayer->wkbType(), QgsWkbTypes::LineString ); + QCOMPARE( resultLayer->featureCount(), 1LL ); + + // try with a format which doesn't exist + feedback.errors.clear(); + parameters.insert( QStringLiteral( "FORMAT" ), QStringLiteral( "not a format" ) ); + ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( !ok ); + QVERIFY( feedback.errors.value( 0 ).startsWith( QStringLiteral( "Unknown GPSBabel format \u201Cnot a format\u201D." ) ) ); +} + +void TestQgsProcessingAlgsPt2::downloadGpsData() +{ + TestProcessingFeedback feedback; + + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:downloadgpsdata" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "DEVICE" ), QStringLiteral( "xxx" ) ); + parameters.insert( QStringLiteral( "PORT" ), QStringLiteral( "usb:" ) ); + parameters.insert( QStringLiteral( "FEATURE_TYPE" ), 0 ); // waypoints + parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); + + bool ok = false; + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + + QVariantMap results; + results = alg->run( parameters, *context, &feedback, &ok ); + // invalid device + QVERIFY( !ok ); + + QVERIFY( feedback.errors.value( 0 ).startsWith( QStringLiteral( "Unknown GPSBabel device \u201Cxxx\u201D. Valid devices are:" ) ) ); + feedback.errors.clear(); + + parameters.insert( QStringLiteral( "DEVICE" ), QStringLiteral( "Garmin serial" ) ); + parameters.insert( QStringLiteral( "PORT" ), QStringLiteral( "not a port" ) ); + ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + // invalid port + QVERIFY( !ok ); + QVERIFY( feedback.errors.value( 0 ).startsWith( QStringLiteral( "Unknown port \u201Cnot a port\u201D. Valid ports are:" ) ) ); + feedback.errors.clear(); +} + +void TestQgsProcessingAlgsPt2::uploadGpsData() +{ + TestProcessingFeedback feedback; + + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:downloadgpsdata" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "DEVICE" ), QStringLiteral( "xxx" ) ); + parameters.insert( QStringLiteral( "PORT" ), QStringLiteral( "usb:" ) ); + parameters.insert( QStringLiteral( "FEATURE_TYPE" ), 0 ); // waypoints + parameters.insert( QStringLiteral( "INPUT" ), QStringLiteral( "%1/layers.gpx" ).arg( TEST_DATA_DIR ) ); + + bool ok = false; + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + + QVariantMap results; + results = alg->run( parameters, *context, &feedback, &ok ); + // invalid device + QVERIFY( !ok ); + + QVERIFY( feedback.errors.value( 0 ).startsWith( QStringLiteral( "Unknown GPSBabel device \u201Cxxx\u201D. Valid devices are:" ) ) ); + feedback.errors.clear(); + + parameters.insert( QStringLiteral( "DEVICE" ), QStringLiteral( "Garmin serial" ) ); + parameters.insert( QStringLiteral( "PORT" ), QStringLiteral( "not a port" ) ); + ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + // invalid port + QVERIFY( !ok ); + QVERIFY( feedback.errors.value( 0 ).startsWith( QStringLiteral( "Unknown port \u201Cnot a port\u201D. Valid ports are:" ) ) ); + feedback.errors.clear(); +} + +void TestQgsProcessingAlgsPt2::transferMainAnnotationLayer() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:transferannotationsfrommain" ) ) ); + QVERIFY( alg != nullptr ); + + QgsProject p; + p.mainAnnotationLayer()->addItem( new QgsAnnotationMarkerItem( QgsPoint( 1, 2 ) ) ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( &p ); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + + QVariantMap parameters; + parameters.insert( QStringLiteral( "LAYER_NAME" ), QStringLiteral( "my annotations" ) ); + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QCOMPARE( p.mainAnnotationLayer()->items().size(), 0 ); + QgsAnnotationLayer *newLayer = qobject_cast< QgsAnnotationLayer * >( p.mapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); + QCOMPARE( newLayer->name(), QStringLiteral( "my annotations" ) ); + QCOMPARE( newLayer->items().size(), 1 ); +} + +void TestQgsProcessingAlgsPt2::exportMeshTimeSeries() +{ + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:meshexporttimeseries" ) ) ); + QVERIFY( alg != nullptr ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" ); + + QVariantList datasetGroup; + datasetGroup << 1 << 2 << 3; + parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup ); + + QVariantMap datasetStartTime; + datasetStartTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); + QVariantList datasetIndexStart; + datasetIndexStart << 1 << 0; + datasetStartTime[QStringLiteral( "value" )] = datasetIndexStart; + parameters.insert( QStringLiteral( "STARTING_TIME" ), datasetStartTime ); + + QVariantMap datasetEndTime; + datasetEndTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" ); + QVariantList datasetIndexEnd; + datasetIndexEnd << 1 << 1; + datasetEndTime[QStringLiteral( "value" )] = datasetIndexEnd; + parameters.insert( QStringLiteral( "FINISHING_TIME" ), datasetEndTime ); + + const QString outputPath = QDir::tempPath() + "/test_mesh_ts.csv"; + parameters.insert( QStringLiteral( "OUTPUT" ), outputPath ); + + QgsVectorLayer *layerPoints = new QgsVectorLayer( QStringLiteral( "Point" ), + QStringLiteral( "points_for_ts" ), + QStringLiteral( "memory" ) ); + + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( QgsProject::instance() ); + QgsProcessingFeedback feedback; + QVariantMap results; + bool ok = false; + + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( !ok ); + + QStringList wktPoints; + wktPoints << QStringLiteral( "Point (1500 2200)" ); + wktPoints << QStringLiteral( "Point (1500 1500)" ); + wktPoints << QStringLiteral( "Point (2500 2100)" ); + + QgsFeatureList flist; + for ( const QString &wkt : wktPoints ) + { + QgsFeature feat; + feat.setGeometry( QgsGeometry::fromWkt( wkt ) ); + flist << feat; + } + layerPoints->dataProvider()->addFeatures( flist ); + QgsProject::instance()->addMapLayer( layerPoints ); QgsProject::instance()->addMapLayer( layerPoints ); + parameters.insert( QStringLiteral( "INPUT_POINTS" ), layerPoints->name() ); + + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QFile outputFile( outputPath ); + QVERIFY( outputFile.open( QIODevice::ReadOnly ) ); + QTextStream textStream( &outputFile ); + QString header = textStream.readLine(); + QCOMPARE( header, QStringLiteral( "fid,x,y,time,VertexScalarDataset,VertexVectorDataset,FaceScalarDataset" ) ); + + QStringList expectedLines; + expectedLines << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:00:00,1.50,1.92,1.00" ) + << QStringLiteral( "1,1500.00,2200.00,1950-01-01 01:00:00,2.50,3.33,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:00:00,2.50,2.97,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 01:00:00,3.50,4.36,3.00" ); + + QString line = textStream.readLine(); + int i = 0; + QVERIFY( !line.isEmpty() ); + while ( !line.isEmpty() ) + { + QCOMPARE( line, expectedLines.at( i ) ); + ++i; + line = textStream.readLine(); + } + QVERIFY( i == expectedLines.count() ); + outputFile.close(); + + parameters.insert( QStringLiteral( "TIME_STEP" ), 0.1 ); + + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QVERIFY( outputFile.open( QIODevice::ReadOnly ) ); + header = textStream.readLine(); + QCOMPARE( header, QStringLiteral( "fid,x,y,time,VertexScalarDataset,VertexVectorDataset,FaceScalarDataset" ) ); + + expectedLines.clear(); + expectedLines << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:00:00,1.50,1.92,1.00" ) + << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:06:00,1.50,1.92,1.00" ) + << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:12:00,1.50,1.92,1.00" ) + << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:18:00,1.50,1.92,1.00" ) + << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:24:00,1.50,1.92,1.00" ) + << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:30:00,1.50,1.92,1.00" ) + << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:36:00,1.50,1.92,1.00" ) + << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:42:00,1.50,1.92,1.00" ) + << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:48:00,1.50,1.92,1.00" ) + << QStringLiteral( "1,1500.00,2200.00,1950-01-01 00:54:00,1.50,1.92,1.00" ) + << QStringLiteral( "1,1500.00,2200.00,1950-01-01 01:00:00,2.50,3.33,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:00:00,2.50,2.97,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:06:00,2.50,2.97,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:12:00,2.50,2.97,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:18:00,2.50,2.97,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:24:00,2.50,2.97,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:30:00,2.50,2.97,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:36:00,2.50,2.97,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:42:00,2.50,2.97,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:48:00,2.50,2.97,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 00:54:00,2.50,2.97,2.00" ) + << QStringLiteral( "3,2500.00,2100.00,1950-01-01 01:00:00,3.50,4.36,3.00" ); + + line = textStream.readLine(); + i = 0; + QVERIFY( !line.isEmpty() ); + while ( !line.isEmpty() ) + { + QCOMPARE( line, expectedLines.at( i ) ); + ++i; + line = textStream.readLine(); + } + QVERIFY( i == expectedLines.count() ); + outputFile.close(); +} + +void TestQgsProcessingAlgsPt2::extractLabels() +{ + QgsProject project; + QgsVectorLayer *pointsLayer = new QgsVectorLayer( mPointLayerPath, + QStringLiteral( "points" ), QStringLiteral( "ogr" ) ); + QVERIFY( mPointsLayer->isValid() ); + project.addMapLayer( pointsLayer ); + + QgsTextFormat format = QgsTextFormat::fromQFont( QgsFontUtils::getStandardTestFont() ); + format.setSize( 10 ); + QgsPalLayerSettings settings; + settings.fieldName = QStringLiteral( "Class" ); + settings.setFormat( format ); + pointsLayer->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); + + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:extractlabels" ) ) ); + QVERIFY( alg != nullptr ); + + QgsReferencedRectangle extent( QgsRectangle( -120, 20, -80, 50 ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "EXTENT" ), extent ); + parameters.insert( QStringLiteral( "SCALE" ), 9000000.00 ); + parameters.insert( QStringLiteral( "DPI" ), 96.00 ); + parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT ); + + bool ok = false; + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + context->setProject( &project ); + QgsProcessingFeedback feedback; + + QVariantMap results; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); + QVERIFY( resultLayer ); + QCOMPARE( resultLayer->wkbType(), QgsWkbTypes::Point ); + QCOMPARE( resultLayer->featureCount(), 17 ); + + QgsFeature feature = resultLayer->getFeature( 1 ); + QVariantMap attributes = feature.attributeMap(); + QCOMPARE( attributes[QStringLiteral( "Layer" )], QStringLiteral( "points" ) ); + QCOMPARE( attributes[QStringLiteral( "FeatureID" )], 1 ); + QCOMPARE( attributes[QStringLiteral( "LabelText" )], QStringLiteral( "Biplane" ) ); + QCOMPARE( attributes[QStringLiteral( "LabelRotation" )], 0.0 ); + QCOMPARE( attributes[QStringLiteral( "Family" )], QStringLiteral( "QGIS Vera Sans" ) ); + QCOMPARE( attributes[QStringLiteral( "Size" )], 9.75 ); + QCOMPARE( attributes[QStringLiteral( "Italic" )], false ); + QCOMPARE( attributes[QStringLiteral( "Bold" )], false ); + QCOMPARE( attributes[QStringLiteral( "FontStyle" )], QStringLiteral( "Roman" ) ); + QCOMPARE( attributes[QStringLiteral( "FontLetterSpacing" )], 0.0 ); + QCOMPARE( attributes[QStringLiteral( "FontWordSpacing" )], 0.0 ); + QCOMPARE( attributes[QStringLiteral( "MultiLineAlignment" )], QStringLiteral( "left" ) ); + QCOMPARE( attributes[QStringLiteral( "MultiLineHeight" )], 1.0 ); +} + +void TestQgsProcessingAlgsPt2::splitVectorLayer() +{ + QgsVectorLayer *layer = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=col1:string" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ); + QVERIFY( layer->isValid() ); + + QgsFeature f; + f.setAttributes( QgsAttributes() << 1 << QVariant() ); + f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "Point (0 0)" ) ) ); + layer->dataProvider()->addFeature( f ); + f.setAttributes( QgsAttributes() << 2 << QStringLiteral( "" ) ); + f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "Point (0 1)" ) ) ); + layer->dataProvider()->addFeature( f ); + f.setAttributes( QgsAttributes() << 3 << QStringLiteral( "value" ) ); + f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "Point (0 2)" ) ) ); + layer->dataProvider()->addFeature( f ); + + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:splitvectorlayer" ) ) ); + QVERIFY( alg != nullptr ); + + QDir outputDir( QDir::tempPath() + "/split_vector/" ); + if ( outputDir.exists() ) + outputDir.removeRecursively(); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "INPUT" ), QVariant::fromValue( layer ) ); + parameters.insert( QStringLiteral( "FIELD" ), QStringLiteral( "col1" ) ); + parameters.insert( QStringLiteral( "FILE_TYPE" ), QStringLiteral( "gpkg" ) ); + parameters.insert( QStringLiteral( "OUTPUT" ), outputDir.absolutePath() ); + + bool ok = false; + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + QgsProcessingFeedback feedback; + QVariantMap results; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QCOMPARE( results.value( QStringLiteral( "OUTPUT_LAYERS" ) ).toList().count(), 3 ); + QDir dataDir( outputDir ); + QStringList entries = dataDir.entryList( QStringList(), QDir::Files | QDir::NoDotAndDotDot ); + QCOMPARE( entries.count(), 3 ); +} + +void TestQgsProcessingAlgsPt2::buffer() +{ + QgsVectorLayer *layer = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=col1:string" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ); + QVERIFY( layer->isValid() ); + + std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:buffer" ) ) ); + QVERIFY( alg != nullptr ); + + // buffering empty layer should produce an empty layer + QVariantMap parameters; + parameters.insert( QStringLiteral( "INPUT" ), QVariant::fromValue( layer ) ); + parameters.insert( QStringLiteral( "DISTANCE" ), 2.0 ); + parameters.insert( QStringLiteral( "SEGMENTS" ), 5 ); + parameters.insert( QStringLiteral( "END_CAP_STYLE" ), 0 ); + parameters.insert( QStringLiteral( "JOIN_STYLE" ), 0 ); + parameters.insert( QStringLiteral( "MITER_LIMIT" ), 0 ); + parameters.insert( QStringLiteral( "DISSOLVE" ), false ); + parameters.insert( QStringLiteral( "OUTPUT" ), QStringLiteral( "memory:" ) ); + + bool ok = false; + std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >(); + QgsProcessingFeedback feedback; + QVariantMap results; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QVERIFY( !results.value( QStringLiteral( "OUTPUT" ) ).toString().isEmpty() ); + QgsVectorLayer *bufferedLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); + QVERIFY( bufferedLayer->isValid() ); + QCOMPARE( bufferedLayer->wkbType(), QgsWkbTypes::MultiPolygon ); + QCOMPARE( bufferedLayer->featureCount(), layer->featureCount() ); + + // buffering empty layer with dissolve should produce an empty layer + parameters.insert( QStringLiteral( "DISSOLVE" ), true ); + + ok = false; + results = alg->run( parameters, *context, &feedback, &ok ); + QVERIFY( ok ); + + QVERIFY( !results.value( QStringLiteral( "OUTPUT" ) ).toString().isEmpty() ); + bufferedLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) ); + QVERIFY( bufferedLayer->isValid() ); + QCOMPARE( bufferedLayer->wkbType(), QgsWkbTypes::MultiPolygon ); + QCOMPARE( bufferedLayer->featureCount(), layer->featureCount() ); +} + +bool TestQgsProcessingAlgsPt2::imageCheck( const QString &testName, const QString &renderedImage ) +{ + QgsRenderChecker checker; + checker.setControlPathPrefix( QStringLiteral( "processing_algorithm" ) ); + checker.setControlName( "expected_" + testName ); + checker.setRenderedImage( renderedImage ); + checker.setSizeTolerance( 3, 3 ); + const bool equal = checker.compareImages( testName, 500 ); + return equal; +} + +QGSTEST_MAIN( TestQgsProcessingAlgsPt2 ) +#include "testqgsprocessingalgspt2.moc"