QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
Loading...
Searching...
No Matches
qgstestutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgstestutils.cpp
3 --------------------
4 begin : January 2018
5 copyright : (C) 2018 by Nyall Dawson
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgstestutils.h"
17
18#include "qgsconnectionpool.h"
20
21#include <QCryptographicHash>
22#include <QString>
23#include <QtConcurrentMap>
24
25using namespace Qt::StringLiterals;
26
29
30static void getFeaturesForProvider( const QPair< std::shared_ptr< QgsAbstractFeatureSource >, QgsFeatureRequest > &pair )
31{
32 QgsFeatureIterator it = pair.first->getFeatures( pair.second );
33 QgsFeature f;
34 while ( it.nextFeature( f ) )
35 {
36 }
37}
38
39bool QgsTestUtils::testProviderIteratorThreadSafety( QgsVectorDataProvider *provider, const QgsFeatureRequest &request )
40{
41 constexpr int JOBS_TO_RUN = 100;
42 QList< QPair< std::shared_ptr< QgsAbstractFeatureSource >, QgsFeatureRequest > > jobs;
43 jobs.reserve( JOBS_TO_RUN );
44 for ( int i = 0; i < JOBS_TO_RUN; ++i )
45 {
46 jobs.append( qMakePair( std::shared_ptr< QgsAbstractFeatureSource >( provider->featureSource() ), request ) );
47 }
48
49 //freaking hammer the provider with a ton of concurrent requests.
50 //thread unsafe providers... you better be ready!!!!
51 QtConcurrent::blockingMap( jobs, getFeaturesForProvider );
52
53 return true;
54}
55
56bool QgsTestUtils::compareDomElements( const QDomElement &element1, const QDomElement &element2 )
57{
58 QString tag1 = element1.tagName();
59 tag1.replace( QRegularExpression( ".*:" ), QString() );
60 QString tag2 = element2.tagName();
61 tag2.replace( QRegularExpression( ".*:" ), QString() );
62 if ( tag1 != tag2 )
63 {
64 qDebug( "Different tag names: %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data() );
65 return false;
66 }
67
68 if ( element1.hasAttributes() != element2.hasAttributes() )
69 {
70 qDebug( "Different hasAttributes: %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data() );
71 return false;
72 }
73
74 if ( element1.hasAttributes() )
75 {
76 const QDomNamedNodeMap attrs1 = element1.attributes();
77 const QDomNamedNodeMap attrs2 = element2.attributes();
78
79 if ( attrs1.size() != attrs2.size() )
80 {
81 qDebug( "Different attributes size: %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data() );
82 return false;
83 }
84
85 for ( int i = 0; i < attrs1.size(); ++i )
86 {
87 const QDomNode node1 = attrs1.item( i );
88 const QDomAttr attr1 = node1.toAttr();
89
90 if ( !element2.hasAttribute( attr1.name() ) )
91 {
92 qDebug( "Element2 has not attribute: %s, %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data(), attr1.name().toLatin1().data() );
93 return false;
94 }
95
96 if ( element2.attribute( attr1.name() ) != attr1.value() )
97 {
98 qDebug( "Element2 attribute has not the same value: %s, %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data(), attr1.name().toLatin1().data() );
99 return false;
100 }
101 }
102 }
103
104 if ( element1.hasChildNodes() != element2.hasChildNodes() )
105 {
106 qDebug( "Different childNodes: %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data() );
107 return false;
108 }
109
110 if ( element1.hasChildNodes() )
111 {
112 const QDomNodeList nodes1 = element1.childNodes();
113 const QDomNodeList nodes2 = element2.childNodes();
114
115 if ( nodes1.size() != nodes2.size() )
116 {
117 qDebug( "Different childNodes size: %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data() );
118 return false;
119 }
120
121 for ( int i = 0; i < nodes1.size(); ++i )
122 {
123 const QDomNode node1 = nodes1.at( i );
124 const QDomNode node2 = nodes2.at( i );
125 if ( node1.isElement() && node2.isElement() )
126 {
127 QDomElement elt1 = node1.toElement();
128 QDomElement elt2 = node2.toElement();
129
130 if ( !compareDomElements( elt1, elt2 ) )
131 return false;
132 }
133 else if ( node1.isText() && node2.isText() )
134 {
135 const QDomText txt1 = node1.toText();
136 const QDomText txt2 = node2.toText();
137
138 if ( txt1.data() != txt2.data() )
139 {
140 qDebug( "Different text data: %s %s", tag1.toLatin1().data(), txt1.data().toLatin1().data() );
141 qDebug( "Different text data: %s %s", tag2.toLatin1().data(), txt2.data().toLatin1().data() );
142 return false;
143 }
144 }
145 }
146 }
147
148 if ( element1.text() != element2.text() )
149 {
150 qDebug( "Different text: %s %s", tag1.toLatin1().data(), element1.text().toLatin1().data() );
151 qDebug( "Different text: %s %s", tag2.toLatin1().data(), element2.text().toLatin1().data() );
152 return false;
153 }
154
155 return true;
156}
157
158QString QgsTestUtils::sanitizeFakeHttpEndpoint( const QString &urlString )
159{
160 QString modifiedUrlString = urlString;
161
162 // For REST API using URL subpaths, normalize the subpaths
163 const int afterEndpointStartPos = static_cast<int>( modifiedUrlString.indexOf( "fake_qgis_http_endpoint" ) + strlen( "fake_qgis_http_endpoint" ) );
164 QString afterEndpointStart = modifiedUrlString.mid( afterEndpointStartPos );
165 afterEndpointStart.replace( "/"_L1, "_"_L1 );
166 modifiedUrlString = modifiedUrlString.mid( 0, afterEndpointStartPos ) + afterEndpointStart;
167
168 const qsizetype posQuotationMark = modifiedUrlString.indexOf( '?' );
169 QString args = modifiedUrlString.mid( posQuotationMark );
170 if ( modifiedUrlString.size() > 256 )
171 {
172 args.replace( '/', '_' );
173 args = QCryptographicHash::hash( args.toUtf8(), QCryptographicHash::Md5 ).toHex();
174 }
175 else
176 {
177 args.replace( '?', '_' );
178 args.replace( '&', '_' );
179 args.replace( '<', '_' );
180 args.replace( '>', '_' );
181 args.replace( '\"', '_' );
182 args.replace( '\'', '_' );
183 args.replace( ' ', '_' );
184 args.replace( ':', '_' );
185 args.replace( '/', '_' );
186 args.replace( '\n', '_' );
187 }
188 return modifiedUrlString.mid( 0, posQuotationMark ) + args;
189}
190
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
Base class for vector data providers.
virtual QgsAbstractFeatureSource * featureSource() const =0
Returns feature source object that can be used for querying provider's data.