1 /***************************************************************************
2 testqgsapplayoutvaliditychecks.cpp
3 --------------------------------------
4 Date : January 2019
5 Copyright : (C) 2019 Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
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 #include "qgstest.h"
16
17 #include <QObject>
18 #include <QString>
19 #include <QStringList>
20
21 //qgis includes...
22 #include "qgsdataitem.h"
23 #include "qgsapplication.h"
24 #include "qgslogger.h"
25 #include "qgsproject.h"
26 #include "qgslayout.h"
27 #include "qgslayoutitemscalebar.h"
28 #include "qgslayoutitemmap.h"
29 #include "qgslayoutitempicture.h"
30 #include "qgsabstractvaliditycheck.h"
31 #include "qgsvaliditycheckcontext.h"
32 #include "layout/qgslayoutvaliditychecks.h"
33 #include "qgsfeedback.h"
34
35 class TestQgsLayoutValidityChecks : public QObject
36 {
37 Q_OBJECT
38
39 public:
40 TestQgsLayoutValidityChecks();
41
42 private slots:
43 void initTestCase();// will be called before the first testfunction is executed.
44 void cleanupTestCase();// will be called after the last testfunction was executed.
init()45 void init() {} // will be called before each testfunction is executed.
cleanup()46 void cleanup() {} // will be called after every testfunction.
47
48 void testScaleBarValidity();
49 void testNorthArrowValidity();
50 void testOverviewValidity();
51 void testPictureValidity();
52
53 private:
54 QString mTestDataDir;
55 };
56
57 TestQgsLayoutValidityChecks::TestQgsLayoutValidityChecks() = default;
58
initTestCase()59 void TestQgsLayoutValidityChecks::initTestCase()
60 {
61 //
62 // Runs once before any tests are run
63 //
64 // init QGIS's paths - true means that all path will be inited from prefix
65 QgsApplication::init();
66 QgsApplication::initQgis();
67 QgsApplication::showSettings();
68
69 const QString dataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
70 mTestDataDir = dataDir + '/';
71 }
72
cleanupTestCase()73 void TestQgsLayoutValidityChecks::cleanupTestCase()
74 {
75 QgsApplication::exitQgis();
76 }
77
testScaleBarValidity()78 void TestQgsLayoutValidityChecks::testScaleBarValidity()
79 {
80 QgsProject p;
81 QgsLayout l( &p );
82
83 QgsLayoutItemScaleBar *scale = new QgsLayoutItemScaleBar( &l );
84 l.addItem( scale );
85
86 QgsLayoutValidityCheckContext context( &l );
87 QgsFeedback f;
88
89 // scalebar not linked to map
90 QgsLayoutScaleBarValidityCheck check;
91 QVERIFY( check.prepareCheck( &context, &f ) );
92 QList< QgsValidityCheckResult > res = check.runCheck( &context, &f );
93 QCOMPARE( res.size(), 1 );
94 QCOMPARE( res.at( 0 ).type, QgsValidityCheckResult::Warning );
95
96 // now link a map
97 QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
98 l.addItem( map );
99 scale->setLinkedMap( map );
100
101 QgsLayoutScaleBarValidityCheck check2;
102 QVERIFY( check2.prepareCheck( &context, &f ) );
103 res = check2.runCheck( &context, &f );
104 QCOMPARE( res.size(), 0 );
105 }
106
testNorthArrowValidity()107 void TestQgsLayoutValidityChecks::testNorthArrowValidity()
108 {
109 QgsProject p;
110 QgsLayout l( &p );
111
112 QgsLayoutItemPicture *picture = new QgsLayoutItemPicture( &l );
113 // we identify this as a north arrow based on the default picture path pointing to the default north arrow
114 picture->setPicturePath( QStringLiteral( ":/images/north_arrows/layout_default_north_arrow.svg" ) );
115
116 l.addItem( picture );
117
118 QgsLayoutValidityCheckContext context( &l );
119 QgsFeedback f;
120
121 // scalebar not linked to map
122 QgsLayoutNorthArrowValidityCheck check;
123 QVERIFY( check.prepareCheck( &context, &f ) );
124 QList< QgsValidityCheckResult > res = check.runCheck( &context, &f );
125 QCOMPARE( res.size(), 1 );
126 QCOMPARE( res.at( 0 ).type, QgsValidityCheckResult::Warning );
127
128 // now link a map
129 QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
130 l.addItem( map );
131 picture->setLinkedMap( map );
132
133 QgsLayoutNorthArrowValidityCheck check2;
134 QVERIFY( check2.prepareCheck( &context, &f ) );
135 res = check2.runCheck( &context, &f );
136 QCOMPARE( res.size(), 0 );
137
138 // test with ID check
139 picture->setPicturePath( QStringLiteral( "a" ) );
140 picture->setId( QStringLiteral( "north arrow 2" ) );
141 picture->setLinkedMap( nullptr );
142
143 QgsLayoutNorthArrowValidityCheck check3;
144 QVERIFY( check3.prepareCheck( &context, &f ) );
145 res = check3.runCheck( &context, &f );
146 QCOMPARE( res.size(), 1 );
147 QCOMPARE( res.at( 0 ).type, QgsValidityCheckResult::Warning );
148
149 // no longer looks like a north arrow
150 picture->setId( QStringLiteral( "a" ) );
151 QgsLayoutNorthArrowValidityCheck check4;
152 QVERIFY( check4.prepareCheck( &context, &f ) );
153 res = check4.runCheck( &context, &f );
154 QCOMPARE( res.size(), 0 );
155 }
156
testOverviewValidity()157 void TestQgsLayoutValidityChecks::testOverviewValidity()
158 {
159 QgsProject p;
160 QgsLayout l( &p );
161
162 QgsLayoutItemMap *map1 = new QgsLayoutItemMap( &l );
163 l.addItem( map1 );
164
165 QgsLayoutValidityCheckContext context( &l );
166 QgsFeedback f;
167
168 // no overviews
169 QgsLayoutOverviewValidityCheck check;
170 QVERIFY( check.prepareCheck( &context, &f ) );
171 QList< QgsValidityCheckResult > res = check.runCheck( &context, &f );
172 QCOMPARE( res.size(), 0 );
173
174 // overview not linked to map
175 map1->overviews()->addOverview( new QgsLayoutItemMapOverview( QStringLiteral( "blah" ), map1 ) );
176 QgsLayoutOverviewValidityCheck check2;
177 QVERIFY( check2.prepareCheck( &context, &f ) );
178 res = check2.runCheck( &context, &f );
179 QCOMPARE( res.size(), 1 );
180 QCOMPARE( res.at( 0 ).type, QgsValidityCheckResult::Warning );
181 map1->overview()->setEnabled( false );
182 QgsLayoutOverviewValidityCheck check3;
183 QVERIFY( check3.prepareCheck( &context, &f ) );
184 res = check3.runCheck( &context, &f );
185 QCOMPARE( res.size(), 0 );
186
187 // now link a map
188 QgsLayoutItemMap *map2 = new QgsLayoutItemMap( &l );
189 l.addItem( map2 );
190 map1->overview()->setLinkedMap( map2 );
191 map1->overview()->setEnabled( true );
192
193 QgsLayoutOverviewValidityCheck check4;
194 QVERIFY( check4.prepareCheck( &context, &f ) );
195 res = check4.runCheck( &context, &f );
196 QCOMPARE( res.size(), 0 );
197
198 map1->overviews()->addOverview( new QgsLayoutItemMapOverview( QStringLiteral( "blah2" ), map1 ) );
199 QgsLayoutOverviewValidityCheck check5;
200 QVERIFY( check5.prepareCheck( &context, &f ) );
201 res = check5.runCheck( &context, &f );
202 QCOMPARE( res.size(), 1 );
203 QCOMPARE( res.at( 0 ).type, QgsValidityCheckResult::Warning );
204
205 map1->overviews()->addOverview( new QgsLayoutItemMapOverview( QStringLiteral( "blah3" ), map1 ) );
206 QgsLayoutOverviewValidityCheck check6;
207 QVERIFY( check6.prepareCheck( &context, &f ) );
208 res = check6.runCheck( &context, &f );
209 QCOMPARE( res.size(), 2 );
210 QCOMPARE( res.at( 0 ).type, QgsValidityCheckResult::Warning );
211 QCOMPARE( res.at( 1 ).type, QgsValidityCheckResult::Warning );
212 }
213
testPictureValidity()214 void TestQgsLayoutValidityChecks::testPictureValidity()
215 {
216 QgsProject p;
217 QgsLayout l( &p );
218
219 QgsLayoutItemPicture *picture = new QgsLayoutItemPicture( &l );
220 l.addItem( picture );
221
222 QgsLayoutValidityCheckContext context( &l );
223 QgsFeedback f;
224
225 // invalid picture source
226 picture->setPicturePath( QStringLiteral( "blaaaaaaaaaaaaaaaaah" ) );
227 QgsLayoutPictureSourceValidityCheck check;
228 QVERIFY( check.prepareCheck( &context, &f ) );
229 QList< QgsValidityCheckResult > res = check.runCheck( &context, &f );
230 QCOMPARE( res.size(), 1 );
231 QCOMPARE( res.at( 0 ).type, QgsValidityCheckResult::Warning );
232
233 QgsLayoutPictureSourceValidityCheck check2;
234 picture->setPicturePath( QString() );
235 QVERIFY( check2.prepareCheck( &context, &f ) );
236 res = check2.runCheck( &context, &f );
237 QCOMPARE( res.size(), 0 );
238
239 QgsLayoutPictureSourceValidityCheck check3;
240 picture->setPicturePath( QStringLiteral( TEST_DATA_DIR ) + "/sample_svg.svg" );
241 QVERIFY( check3.prepareCheck( &context, &f ) );
242 res = check3.runCheck( &context, &f );
243 QCOMPARE( res.size(), 0 );
244
245 QgsLayoutItemPicture *picture2 = new QgsLayoutItemPicture( &l );
246 l.addItem( picture2 );
247 picture2->dataDefinedProperties().setProperty( QgsLayoutObject::PictureSource, QgsProperty::fromExpression( QStringLiteral( "'d:/bad' || 'robot'" ) ) );
248 l.refresh();
249
250 QgsLayoutPictureSourceValidityCheck check4;
251 QVERIFY( check4.prepareCheck( &context, &f ) );
252 res = check4.runCheck( &context, &f );
253 QCOMPARE( res.size(), 1 );
254 QCOMPARE( res.at( 0 ).type, QgsValidityCheckResult::Warning );
255
256 picture2->dataDefinedProperties().setProperty( QgsLayoutObject::PictureSource, QgsProperty::fromExpression( QStringLiteral( "''" ) ) );
257 l.refresh();
258 QgsLayoutPictureSourceValidityCheck check5;
259 QVERIFY( check5.prepareCheck( &context, &f ) );
260 res = check5.runCheck( &context, &f );
261 QCOMPARE( res.size(), 0 );
262
263 picture2->dataDefinedProperties().setProperty( QgsLayoutObject::PictureSource, QgsProperty::fromExpression( QStringLiteral( "'%1'" ).arg( QStringLiteral( TEST_DATA_DIR ) + "/sam' || 'ple_svg.svg" ) ) );
264 l.refresh();
265 QgsLayoutPictureSourceValidityCheck check6;
266 QVERIFY( check6.prepareCheck( &context, &f ) );
267 res = check6.runCheck( &context, &f );
268 QCOMPARE( res.size(), 0 );
269 }
270
271
272
273 QGSTEST_MAIN( TestQgsLayoutValidityChecks )
274 #include "testqgsapplayoutvaliditychecks.moc"
275