21#include <QCryptographicHash>
23#include <QtConcurrentMap>
25using namespace Qt::StringLiterals;
30static void getFeaturesForProvider(
const QPair< std::shared_ptr< QgsAbstractFeatureSource >,
QgsFeatureRequest > &pair )
42 constexpr int JOBS_TO_RUN = 100;
43 QList< QPair< std::shared_ptr< QgsAbstractFeatureSource >,
QgsFeatureRequest > > jobs;
44 jobs.reserve( JOBS_TO_RUN );
45 for (
int i = 0; i < JOBS_TO_RUN; ++i )
47 jobs.append( qMakePair( std::shared_ptr< QgsAbstractFeatureSource >( provider->
featureSource() ), request ) );
52 QtConcurrent::blockingMap( jobs, getFeaturesForProvider );
57bool QgsTestUtils::compareDomElements(
const QDomElement &element1,
const QDomElement &element2 )
59 QString tag1 = element1.tagName();
60 tag1.replace( QRegularExpression(
".*:" ), QString() );
61 QString tag2 = element2.tagName();
62 tag2.replace( QRegularExpression(
".*:" ), QString() );
65 qDebug(
"Different tag names: %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data() );
69 if ( element1.hasAttributes() != element2.hasAttributes() )
71 qDebug(
"Different hasAttributes: %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data() );
75 if ( element1.hasAttributes() )
77 const QDomNamedNodeMap attrs1 = element1.attributes();
78 const QDomNamedNodeMap attrs2 = element2.attributes();
80 if ( attrs1.size() != attrs2.size() )
82 qDebug(
"Different attributes size: %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data() );
86 for (
int i = 0; i < attrs1.size(); ++i )
88 const QDomNode node1 = attrs1.item( i );
89 const QDomAttr attr1 = node1.toAttr();
91 if ( !element2.hasAttribute( attr1.name() ) )
93 qDebug(
"Element2 has not attribute: %s, %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data(), attr1.name().toLatin1().data() );
97 if ( element2.attribute( attr1.name() ) != attr1.value() )
99 qDebug(
"Element2 attribute has not the same value: %s, %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data(), attr1.name().toLatin1().data() );
105 if ( element1.hasChildNodes() != element2.hasChildNodes() )
107 qDebug(
"Different childNodes: %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data() );
111 if ( element1.hasChildNodes() )
113 const QDomNodeList nodes1 = element1.childNodes();
114 const QDomNodeList nodes2 = element2.childNodes();
116 if ( nodes1.size() != nodes2.size() )
118 qDebug(
"Different childNodes size: %s, %s", tag1.toLatin1().data(), tag2.toLatin1().data() );
122 for (
int i = 0; i < nodes1.size(); ++i )
124 const QDomNode node1 = nodes1.at( i );
125 const QDomNode node2 = nodes2.at( i );
126 if ( node1.isElement() && node2.isElement() )
128 QDomElement elt1 = node1.toElement();
129 QDomElement elt2 = node2.toElement();
131 if ( !compareDomElements( elt1, elt2 ) )
134 else if ( node1.isText() && node2.isText() )
136 const QDomText txt1 = node1.toText();
137 const QDomText txt2 = node2.toText();
139 if ( txt1.data() != txt2.data() )
141 qDebug(
"Different text data: %s %s", tag1.toLatin1().data(), txt1.data().toLatin1().data() );
142 qDebug(
"Different text data: %s %s", tag2.toLatin1().data(), txt2.data().toLatin1().data() );
149 if ( element1.text() != element2.text() )
151 qDebug(
"Different text: %s %s", tag1.toLatin1().data(), element1.text().toLatin1().data() );
152 qDebug(
"Different text: %s %s", tag2.toLatin1().data(), element2.text().toLatin1().data() );
159QString QgsTestUtils::sanitizeFakeHttpEndpoint(
const QString &urlString )
161 QString modifiedUrlString = urlString;
164 const int afterEndpointStartPos =
static_cast<int>( modifiedUrlString.indexOf(
"fake_qgis_http_endpoint" ) + strlen(
"fake_qgis_http_endpoint" ) );
165 QString afterEndpointStart = modifiedUrlString.mid( afterEndpointStartPos );
166 afterEndpointStart.replace(
"/"_L1,
"_"_L1 );
167 modifiedUrlString = modifiedUrlString.mid( 0, afterEndpointStartPos ) + afterEndpointStart;
169 const qsizetype posQuotationMark = modifiedUrlString.indexOf(
'?' );
170 QString args = modifiedUrlString.mid( posQuotationMark );
171 if ( modifiedUrlString.size() > 256 )
173 args.replace(
'/',
'_' );
174 args = QCryptographicHash::hash( args.toUtf8(), QCryptographicHash::Md5 ).toHex();
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(
'/',
'_' );
187 args.replace(
'\n',
'_' );
189 return modifiedUrlString.mid( 0, posQuotationMark ) + args;
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...
Base class for vector data providers.
virtual QgsAbstractFeatureSource * featureSource() const =0
Returns feature source object that can be used for querying provider's data.