1 /**********************************************************************************************
2 Copyright (C) 2015-2016 Christian Eichler code@christian-eichler.de
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 **********************************************************************************************/
18
19 #include <QDebug>
20 #include <QTemporaryFile>
21
22 #include "TestHelper.h"
23 #include "test_QMapShack.h"
24
25 #include "gis/gpx/CGpxProject.h"
26 #include "gis/ovl/CGisItemOvlArea.h"
27 #include "gis/prj/IGisProject.h"
28 #include "gis/fit/CFitProject.h"
29 #include "gis/qms/CQmsProject.h"
30 #include "gis/rte/CGisItemRte.h"
31 #include "gis/slf/CSlfProject.h"
32 #include "gis/slf/CSlfReader.h"
33 #include "gis/trk/CGisItemTrk.h"
34 #include "gis/trk/CKnownExtension.h"
35 #include "gis/wpt/CGisItemWpt.h"
36 #include "helpers/CSettings.h"
37 #include "setup/IAppSetup.h"
38
39 QString testInput;
40
initTestCase()41 void test_QMapShack::initTestCase()
42 {
43 IAppSetup* env = IAppSetup::getPlatformInstance();
44 env->processArguments();
45 env->initLogHandler();
46 env->initQMapShack();
47
48 SETTINGS;
49 IUnit::self().setUnitType((IUnit::type_e)cfg.value("MainWindow/units",IUnit::eTypeMetric).toInt(), nullptr);
50 CKnownExtension::init(IUnit::self());
51
52 testInput = QCoreApplication::applicationDirPath() + "/input/";
53
54 inputFiles =
55 {
56 "qtt_gpx_file0.gpx"
57 , "gpx_ext_GarminTPX1_gpxtpx.gpx"
58 , "gpx_ext_GarminTPX1_tp1.gpx"
59 , "V1.6.0_file1.qms"
60 , "V1.6.0_file2.qms"
61 };
62 }
63
verify(expectedGisProject exp,const IGisProject & proj)64 void test_QMapShack::verify(expectedGisProject exp, const IGisProject &proj)
65 {
66 VERIFY_EQUAL(true, proj.isValid());
67 VERIFY_EQUAL(exp.changed, proj.isChanged());
68
69 VERIFY_EQUAL(exp.name, proj.getName());
70 VERIFY_EQUAL(exp.desc, proj.getDescription());
71
72 VERIFY_EQUAL(exp.wpts.count(), proj.getItemCountByType(IGisItem::eTypeWpt));
73 VERIFY_EQUAL(exp.trks.count(), proj.getItemCountByType(IGisItem::eTypeTrk));
74 VERIFY_EQUAL(exp.rtes.count(), proj.getItemCountByType(IGisItem::eTypeRte));
75 VERIFY_EQUAL(exp.ovls.count(), proj.getItemCountByType(IGisItem::eTypeOvl));
76
77 for(int i = 0; i < proj.childCount(); i++)
78 {
79 IGisItem *item = dynamic_cast<IGisItem*>(proj.child(i));
80
81 CGisItemWpt *wpt = dynamic_cast<CGisItemWpt*>(item);
82 if(nullptr != wpt)
83 {
84 VERIFY_EQUAL(true, exp.wpts.contains(wpt->getName()));
85 exp.wpts.remove(wpt->getName());
86
87 SUBVERIFY(wpt->getPosition() != QPointF(0., 0.), "Waypoint has position 0/0");
88 }
89
90 CGisItemTrk *itemTrk = dynamic_cast<CGisItemTrk*>(item);
91 if(nullptr != itemTrk)
92 {
93 const CTrackData &trk = itemTrk->getTrackData();
94
95 SUBVERIFY(exp.trks.contains(itemTrk->getName()), QString("Found track `%1`, there shouldn't be any track with that name").arg(itemTrk->getName()));
96
97 const expectedTrack &expTrk = exp.trks.take(itemTrk->getName());
98
99 int trkptCount = 0;
100 for(const trkseg_t &seg : trk.segs)
101 {
102 trkptCount += seg.pts.count();
103
104 for(const trkpt_t &trkpt : seg.pts)
105 {
106 SUBVERIFY((0. != trkpt.lat) || (0. != trkpt.lon), "Trackpoint has position 0/0");
107
108 for(const QString &key : expTrk.extensions.keys())
109 {
110 VERIFY_EQUAL(expTrk.extensions[key].known, CKnownExtension::isKnown(key));
111 if(expTrk.extensions[key].everyPoint)
112 {
113 SUBVERIFY(trkpt.extensions.contains(key), QString("Missing extension `%1`on trackpoint").arg(key));
114 }
115 }
116 }
117 }
118
119 VERIFY_EQUAL(expTrk.segCount, trk.segs.count());
120 VERIFY_EQUAL(expTrk.ptCount, trkptCount);
121 VERIFY_EQUAL(expTrk.colorIdx, itemTrk->getColorIdx());
122
123 QStringList existingSources = itemTrk->getExistingDataSources();
124 for(const QString &ext : expTrk.extensions.keys())
125 {
126 SUBVERIFY(existingSources.contains(ext), QString("Missing extension `%1`").arg(ext));
127 existingSources.removeOne(ext);
128 }
129
130 auto accuFunc = [](const QString &accu, const QString &b) { return accu.isEmpty() ? b : QString("%1, %2").arg(accu).arg(b); };
131 QString remainingExts = std::accumulate(existingSources.cbegin(), existingSources.cend(), QString(), accuFunc);
132
133 SUBVERIFY(existingSources.isEmpty(), QString("existingSources still contains: ") + remainingExts);
134 }
135
136 CGisItemRte *itemRte = dynamic_cast<CGisItemRte*>(item);
137 if(nullptr != itemRte)
138 {
139 SUBVERIFY(exp.rtes.contains(itemRte->getName()), QString("Found route `%1`, there shouldn't be any route with that name").arg(itemRte->getName()));
140 const CGisItemRte::rte_t &rte = itemRte->getRoute();
141
142 const expectedRoute &expRte = exp.rtes.take(itemRte->getName());
143
144 VERIFY_EQUAL(expRte.ptCount, rte.pts.size());
145 }
146
147 CGisItemOvlArea *itemOvl = dynamic_cast<CGisItemOvlArea*>(item);
148 if(nullptr != itemOvl)
149 {
150 SUBVERIFY(exp.ovls.contains(itemOvl->getName()), QString("Found area `%1`, there shouldn't be any area with that name").arg(itemOvl->getName()));
151
152 const expectedArea &expOvl = exp.ovls.take(itemOvl->getName());
153 VERIFY_EQUAL(expOvl.colorIdx, itemOvl->getColorIdx());
154
155 const CGisItemOvlArea::area_t &area = itemOvl->getAreaData();
156 VERIFY_EQUAL(expOvl.ptCount, area.pts.size());
157 }
158 }
159
160 // ensure all expected waypoints/tracks actually exist
161 SUBVERIFY(exp.wpts.isEmpty(), "Not all expected waypoints found");
162 SUBVERIFY(exp.trks.isEmpty(), "Not all expected tracks found");
163 SUBVERIFY(exp.rtes.isEmpty(), "Not all expected routes found");
164 SUBVERIFY(exp.ovls.isEmpty(), "Not all expected areas found");
165 }
166
verify(const QString & projFile,const IGisProject & proj)167 void test_QMapShack::verify(const QString &projFile, const IGisProject &proj)
168 {
169 expectedGisProject exp = TestHelper::readExpProj(fileToPath(projFile) + ".xml");
170 verify(exp, proj);
171 }
172
verify(const QString & projFile)173 void test_QMapShack::verify(const QString &projFile)
174 {
175 IGisProject *proj = readProjFile(projFile);
176 expectedGisProject exp = TestHelper::readExpProj(fileToPath(projFile) + ".xml");
177
178 verify(exp, *proj);
179 delete proj;
180 }
181
fileToPath(const QString & file)182 QString test_QMapShack::fileToPath(const QString &file)
183 {
184 if(!QFileInfo(file).exists())
185 {
186 return testInput + "/" + file.right(3) + "/" + file;
187 }
188 return file;
189 }
190
readProjFile(const QString & file,bool valid,bool forceVerify)191 IGisProject* test_QMapShack::readProjFile(const QString &file, bool valid, bool forceVerify)
192 {
193 IGisProject *proj = nullptr;
194
195 try
196 {
197 if(file.endsWith(".gpx"))
198 {
199 CGpxProject *gpxProj = new CGpxProject("a very random string to prevent loading via constructor", (CGisListWks*) nullptr);
200 gpxProj->blockUpdateItems(true);
201 CGpxProject::loadGpx(fileToPath(file), gpxProj);
202 gpxProj->blockUpdateItems(false);
203 proj = gpxProj;
204 SUBVERIFY(IGisProject::eTypeGpx == proj->getType(), "Project has invalid type");
205 }
206 else if(file.endsWith(".qms"))
207 {
208 proj = new CQmsProject(fileToPath(file), (CGisListWks*) nullptr);
209 SUBVERIFY(IGisProject::eTypeQms == proj->getType(), "Project has invalid type");
210 }
211 else if(file.endsWith(".slf"))
212 {
213 CSlfProject *slfProj = new CSlfProject("a very random string to prevent loading via constructor", false);
214 proj = slfProj;
215 CSlfReader::readFile(fileToPath(file), slfProj);
216 SUBVERIFY(IGisProject::eTypeSlf == proj->getType(), "Project has invalid type");
217 }
218 else if(file.endsWith(".fit"))
219 {
220 proj = new CFitProject(fileToPath(file), (CGisListWks*) nullptr);
221 SUBVERIFY(IGisProject::eTypeFit == proj->getType(), "Project has invalid type");
222 }
223 else
224 {
225 SUBVERIFY(false, "Internal error: Can't read project file `" + file + "`");
226 }
227 }
228 catch(QString &errormsg)
229 {
230 SUBVERIFY(!valid, "Expected `" + file + "` to be valid, error while reading: " + errormsg);
231 delete proj;
232 proj = nullptr;
233 }
234
235 SUBVERIFY(valid || nullptr == proj, "File is neither valid, nor an exception was thrown");
236
237 if(nullptr != proj)
238 {
239 const QString &projPath = fileToPath(file);
240 SUBVERIFY(QFile(projPath + ".xml").exists() || !forceVerify, "Can't verify file `" + file + "`, .xml does not exist");
241
242 if(QFile(projPath + ".xml").exists())
243 {
244 verify(file, *proj);
245 }
246 }
247
248 return proj;
249 }
250
251 QTEST_MAIN(test_QMapShack)
252