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