1 /************************************************************************
2 **
3 ** @file abstracttest.cpp
4 ** @author Roman Telezhynskyi <dismine(at)gmail.com>
5 ** @date 7 5, 2015
6 **
7 ** @brief
8 ** @copyright
9 ** This source code is part of the Valentina project, a pattern making
10 ** program, whose allow create and modeling patterns of clothing.
11 ** Copyright (C) 2015 Valentina project
12 ** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
13 **
14 ** Valentina is free software: you can redistribute it and/or modify
15 ** it under the terms of the GNU General Public License as published by
16 ** the Free Software Foundation, either version 3 of the License, or
17 ** (at your option) any later version.
18 **
19 ** Valentina is distributed in the hope that it will be useful,
20 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ** GNU General Public License for more details.
23 **
24 ** You should have received a copy of the GNU General Public License
25 ** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
26 **
27 *************************************************************************/
28
29 #include "abstracttest.h"
30
31 #include <qtestcase.h>
32 #include <QApplication>
33 #include <QByteArray>
34 #include <QDir>
35 #include <QFile>
36 #include <QFileInfo>
37 #include <QFlags>
38 #include <QIODevice>
39 #include <QPointF>
40 #include <QProcess>
41 #include <QScopedPointer>
42 #include <QStaticStringData>
43 #include <QStringData>
44 #include <QStringDataPtr>
45 #include <QStringList>
46 #include <QVector>
47 #include <QtGlobal>
48 #include <QLineF>
49 #include <QJsonDocument>
50 #include <QJsonObject>
51 #include <QJsonArray>
52
53 #include "vsysexits.h"
54 #include "../vgeometry/vgobject.h"
55 #include "../vgeometry/vpointf.h"
56 #include "../vgeometry/vspline.h"
57 #include "../vgeometry/vsplinepath.h"
58 #include "../vlayout/vabstractpiece.h"
59 #include "../vlayout/vrawsapoint.h"
60 #include "../vpatterndb/vcontainer.h"
61 #include "../vpatterndb/vpiece.h"
62 #include "../vpatterndb/vpiecenode.h"
63 #include "../vpatterndb/vpassmark.h"
64
65 //---------------------------------------------------------------------------------------------------------------------
AbstractTest(QObject * parent)66 AbstractTest::AbstractTest(QObject *parent) :
67 QObject(parent)
68 {
69 }
70
71 //---------------------------------------------------------------------------------------------------------------------
VectorFromJson(const QString & json,QVector<QPointF> & vector) const72 void AbstractTest::VectorFromJson(const QString &json, QVector<QPointF>& vector) const
73 {
74 QByteArray saveData;
75 PrepareDocument(json, saveData);
76 QJsonDocument loadDoc(QJsonDocument::fromJson(saveData));
77
78 const QString vectorKey = QStringLiteral("vector");
79 const QString typeKey = QStringLiteral("type");
80
81 QJsonObject vectorObject = loadDoc.object();
82 TestRoot(vectorObject, vectorKey, json);
83
84 QJsonArray vectorArray = vectorObject[vectorKey].toArray();
85 for (int i = 0; i < vectorArray.size(); ++i)
86 {
87 QJsonObject pointObject = vectorArray[i].toObject();
88
89 QString type;
90 AbstractTest::ReadStringValue(pointObject, typeKey, type);
91
92 if (type != QLatin1String("QPointF"))
93 {
94 const QString error = QStringLiteral("Invalid json file '%1'. Unexpected class '%2'.")
95 .arg(json, pointObject[typeKey].toString());
96 QFAIL(qUtf8Printable(error));
97 }
98
99 QPointF point;
100 QPointFromJson(pointObject, point);
101 vector.append(point);
102 }
103 }
104
105 //---------------------------------------------------------------------------------------------------------------------
VectorFromJson(const QString & json,QVector<VSAPoint> & vector) const106 void AbstractTest::VectorFromJson(const QString &json, QVector<VSAPoint> &vector) const
107 {
108 QByteArray saveData;
109 PrepareDocument(json, saveData);
110 QJsonDocument loadDoc(QJsonDocument::fromJson(saveData));
111
112 const QString vectorKey = QStringLiteral("vector");
113
114 QJsonObject vectorObject = loadDoc.object();
115 TestRoot(vectorObject, vectorKey, json);
116
117 QJsonArray vectorArray = vectorObject[vectorKey].toArray();
118 for (int i = 0; i < vectorArray.size(); ++i)
119 {
120 QJsonObject pointObject = vectorArray[i].toObject();
121
122 QString type;
123 AbstractTest::ReadStringValue(pointObject, QStringLiteral("type"), type);
124
125 if (type != QLatin1String("VSAPoint"))
126 {
127 const QString error = QStringLiteral("Invalid json file '%1'. Unexpected class '%2'.").arg(json, type);
128 QFAIL(qUtf8Printable(error));
129 }
130
131 VSAPoint point;
132 SAPointFromJson(pointObject, point);
133 vector.append(point);
134 }
135 }
136
137 //---------------------------------------------------------------------------------------------------------------------
VectorFromJson(const QString & json,QVector<VRawSAPoint> & vector) const138 void AbstractTest::VectorFromJson(const QString &json, QVector<VRawSAPoint> &vector) const
139 {
140 QByteArray saveData;
141 PrepareDocument(json, saveData);
142 QJsonDocument loadDoc(QJsonDocument::fromJson(saveData));
143
144 const QString vectorKey = QStringLiteral("vector");
145
146 QJsonObject vectorObject = loadDoc.object();
147 TestRoot(vectorObject, vectorKey, json);
148
149 QJsonArray vectorArray = vectorObject[vectorKey].toArray();
150 for (int i = 0; i < vectorArray.size(); ++i)
151 {
152 QJsonObject pointObject = vectorArray[i].toObject();
153
154 QString type;
155 AbstractTest::ReadStringValue(pointObject, QStringLiteral("type"), type);
156
157 if (type != QLatin1String("VRawSAPoint"))
158 {
159 const QString error = QStringLiteral("Invalid json file '%1'. Unexpected class '%2'.").arg(json, type);
160 QFAIL(qUtf8Printable(error));
161 }
162
163 VRawSAPoint point;
164 RawSAPointFromJson(pointObject, point);
165 vector.append(point);
166 }
167 }
168
169 //---------------------------------------------------------------------------------------------------------------------
PieceFromJson(const QString & json,VPiece & piece,QSharedPointer<VContainer> & data)170 void AbstractTest::PieceFromJson(const QString &json, VPiece &piece, QSharedPointer<VContainer> &data)
171 {
172 QByteArray saveData;
173 PrepareDocument(json, saveData);
174 QJsonDocument loadDoc(QJsonDocument::fromJson(saveData));
175
176 const QString testCaseKey = QStringLiteral("testCase");
177 const QString bdKey = QStringLiteral("bd");
178 const QString pieceKey = QStringLiteral("piece");
179
180 QJsonObject testCaseObject = loadDoc.object();
181 TestRoot(testCaseObject, testCaseKey, json);
182
183 QJsonObject testCase = testCaseObject[testCaseKey].toObject();
184
185 if (testCase.contains(bdKey))
186 {
187 DBFromJson(testCase[bdKey].toObject(), data);
188 }
189 else
190 {
191 const QString error = QStringLiteral("Test case json object does not contain db data.");
192 QFAIL(qUtf8Printable(error));
193 }
194
195 if (testCase.contains(pieceKey))
196 {
197 MainPathFromJson(testCase[pieceKey].toObject(), piece);
198 }
199 else
200 {
201 const QString error = QStringLiteral("Test case json object does not contain piece data.");
202 QFAIL(qUtf8Printable(error));
203 }
204 }
205
206 //---------------------------------------------------------------------------------------------------------------------
PassmarkDataFromJson(const QString & json,VPiecePassmarkData & data)207 void AbstractTest::PassmarkDataFromJson(const QString &json, VPiecePassmarkData &data)
208 {
209 QByteArray saveData;
210 PrepareDocument(json, saveData);
211 QJsonDocument loadDoc(QJsonDocument::fromJson(saveData));
212
213 const QString dataKey = QStringLiteral("data");
214
215 QJsonObject dataObject = loadDoc.object();
216 TestRoot(dataObject, dataKey, json);
217
218 QJsonObject passmarkData = dataObject[dataKey].toObject();
219
220 VSAPoint previousSAPoint;
221 SAPointFromJson(passmarkData[QStringLiteral("previousSAPoint")].toObject(), previousSAPoint);
222 data.previousSAPoint = previousSAPoint;
223
224 VSAPoint passmarkSAPoint;
225 SAPointFromJson(passmarkData[QStringLiteral("passmarkSAPoint")].toObject(), passmarkSAPoint);
226 data.passmarkSAPoint = passmarkSAPoint;
227
228 VSAPoint nextSAPoint;
229 SAPointFromJson(passmarkData[QStringLiteral("nextSAPoint")].toObject(), nextSAPoint);
230 data.nextSAPoint = nextSAPoint;
231
232 qreal saWidth = 0;
233 AbstractTest::ReadDoubleValue(passmarkData, QStringLiteral("saWidth"), saWidth);
234 data.saWidth = saWidth;
235
236 QString nodeName;
237 AbstractTest::ReadStringValue(passmarkData, QStringLiteral("nodeName"), nodeName);
238 data.nodeName = nodeName;
239
240 QString pieceName;
241 AbstractTest::ReadStringValue(passmarkData, QStringLiteral("pieceName"), pieceName);
242 data.pieceName = pieceName;
243
244 PassmarkLineType passmarkLineType = PassmarkLineType::OneLine;
245 AbstractTest::ReadDoubleValue(passmarkData, QStringLiteral("passmarkLineType"), passmarkLineType,
246 QString::number(static_cast<int>(PassmarkLineType::OneLine)));
247 data.passmarkLineType = passmarkLineType;
248
249 PassmarkAngleType passmarkAngleType = PassmarkAngleType::Straightforward;
250 AbstractTest::ReadDoubleValue(passmarkData, QStringLiteral("passmarkAngleType"), passmarkAngleType,
251 QString::number(static_cast<int>(PassmarkAngleType::Straightforward)));
252 data.passmarkAngleType = passmarkAngleType;
253
254 bool isMainPathNode = true;
255 AbstractTest::ReadBooleanValue(passmarkData, QStringLiteral("isMainPathNode"), isMainPathNode);
256 data.isMainPathNode = isMainPathNode;
257
258 bool isShowSecondPassmark = true;
259 AbstractTest::ReadBooleanValue(passmarkData, QStringLiteral("isShowSecondPassmark"), isShowSecondPassmark);
260 data.isShowSecondPassmark = isShowSecondPassmark;
261
262 int passmarkIndex = -1;
263 AbstractTest::ReadDoubleValue(passmarkData, QStringLiteral("passmarkIndex"), passmarkIndex, QStringLiteral("-1"));
264 data.passmarkIndex = passmarkIndex;
265
266 vidtype id = NULL_ID;
267 AbstractTest::ReadDoubleValue(passmarkData, QStringLiteral("id"), id, QString::number(NULL_ID));
268 data.id = id;
269
270 qreal globalPassmarkLength;
271 AbstractTest::ReadDoubleValue(passmarkData, QStringLiteral("globalPassmarkLength"), globalPassmarkLength,
272 QString::number(NULL_ID));
273 data.globalPassmarkLength = globalPassmarkLength;
274 }
275
276 //---------------------------------------------------------------------------------------------------------------------
PassmarkShapeFromJson(const QString & json,QVector<QLineF> & shape)277 void AbstractTest::PassmarkShapeFromJson(const QString &json, QVector<QLineF> &shape)
278 {
279 QByteArray saveData;
280 PrepareDocument(json, saveData);
281 QJsonDocument loadDoc(QJsonDocument::fromJson(saveData));
282
283 const QString shapeKey = QStringLiteral("shape");
284 const QString typeKey = QStringLiteral("type");
285
286 QJsonObject shapeObject = loadDoc.object();
287 TestRoot(shapeObject, shapeKey, json);
288
289 QJsonArray vectorArray = shapeObject[shapeKey].toArray();
290 for (int i = 0; i < vectorArray.size(); ++i)
291 {
292 QJsonObject lineObject = vectorArray[i].toObject();
293
294 QString type;
295 AbstractTest::ReadStringValue(lineObject, typeKey, type);
296
297 if (type != QLatin1String("QLineF"))
298 {
299 const QString error = QStringLiteral("Invalid json file '%1'. Unexpected class '%2'.")
300 .arg(json, lineObject[typeKey].toString());
301 QFAIL(qUtf8Printable(error));
302 }
303
304 QLineF line;
305 QLineFromJson(lineObject, line);
306 shape.append(line);
307 }
308 }
309
310 //---------------------------------------------------------------------------------------------------------------------
Comparison(const QVector<QPointF> & ekv,const QVector<QPointF> & ekvOrig) const311 void AbstractTest::Comparison(const QVector<QPointF> &ekv, const QVector<QPointF> &ekvOrig) const
312 {
313 // Begin comparison
314 QCOMPARE(ekv.size(), ekvOrig.size());// First check if sizes equal
315 const qreal testAccuracy = (1.0/*mm*/ / 25.4) * PrintDPI;
316
317 for (int i=0; i < ekv.size(); i++)
318 {
319 Comparison(ekv.at(i), ekvOrig.at(i), testAccuracy);
320 }
321 }
322
323 //---------------------------------------------------------------------------------------------------------------------
Comparison(const QPointF & result,const QPointF & expected,qreal testAccuracy) const324 void AbstractTest::Comparison(const QPointF &result, const QPointF &expected, qreal testAccuracy) const
325 {
326 const QString msg = QStringLiteral("Actual '%2;%3', Expected '%4;%5'. Distance between points %6 mm.")
327 .arg(result.x()).arg(result.y()).arg(expected.x()).arg(expected.y())
328 .arg(UnitConvertor(QLineF(result, expected).length(), Unit::Px, Unit::Mm));
329 // Check each point. Don't use comparison float values
330 QVERIFY2(VFuzzyComparePoints(result, expected, testAccuracy), qUtf8Printable(msg));
331 }
332
333
334 //---------------------------------------------------------------------------------------------------------------------
Comparison(const QVector<QLineF> & result,const QVector<QLineF> & expected) const335 void AbstractTest::Comparison(const QVector<QLineF> &result, const QVector<QLineF> &expected) const
336 {
337 // Begin comparison
338 QCOMPARE(result.size(), expected.size());// First check if sizes equal
339
340 for (int i=0; i < result.size(); i++)
341 {
342 const QLineF &line1 = result.at(i);
343 const QLineF &line2 = expected.at(i);
344 // Check each point. Don't use comparison float values
345 QVERIFY2(VFuzzyComparePoints(line1.p1(), line2.p1()) && VFuzzyComparePoints(line1.p2(), line2.p2()),
346 qUtf8Printable(
347 QStringLiteral("Index: %1. Got line '(%2;%3):(%4;%5)', Expected line '(%6;%7):(%8;%9)'.")
348 .arg(i)
349 .arg(line1.p1().x())
350 .arg(line1.p1().y())
351 .arg(line1.p2().x())
352 .arg(line1.p2().y())
353 .arg(line2.p1().x())
354 .arg(line2.p1().y())
355 .arg(line2.p2().x())
356 .arg(line2.p2().y())
357 )
358 );
359 }
360 }
361
362 //---------------------------------------------------------------------------------------------------------------------
ValentinaPath() const363 QString AbstractTest::ValentinaPath() const
364 {
365 const QString path = QStringLiteral("/../../../app/valentina/bin/valentina");
366 #ifdef Q_OS_WIN
367 return QCoreApplication::applicationDirPath() + path + QLatin1String(".exe");
368 #else
369 return QCoreApplication::applicationDirPath() + path;
370 #endif
371 }
372
373 //---------------------------------------------------------------------------------------------------------------------
TapePath() const374 QString AbstractTest::TapePath() const
375 {
376 const QString path = QStringLiteral("/../../../app/tape/bin/tape");
377 #ifdef Q_OS_WIN
378 return QCoreApplication::applicationDirPath() + path + QLatin1String(".exe");
379 #else
380 return QCoreApplication::applicationDirPath() + path;
381 #endif
382 }
383
384 //---------------------------------------------------------------------------------------------------------------------
TranslationsPath() const385 QString AbstractTest::TranslationsPath() const
386 {
387 return QCoreApplication::applicationDirPath() + QStringLiteral("/../../../app/valentina/bin/translations");
388 }
389
390 //---------------------------------------------------------------------------------------------------------------------
RunTimeout(int defMsecs)391 int AbstractTest::RunTimeout(int defMsecs)
392 {
393 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
394 QString timeout = QString::fromLocal8Bit(qgetenv("VTEST_RUN_TIMEOUT"));
395 if (timeout.isEmpty())
396 {
397 return defMsecs;
398 }
399 #else
400 QString timeout = qEnvironmentVariable("VTEST_RUN_TIMEOUT", QString::number(defMsecs));
401 #endif
402
403 bool ok = false;
404 int msecs = timeout.toInt(&ok);
405 return ok ? msecs : defMsecs;
406 }
407
408 //---------------------------------------------------------------------------------------------------------------------
Run(int exit,const QString & program,const QStringList & arguments,QString & error,int msecs)409 int AbstractTest::Run(int exit, const QString &program, const QStringList &arguments, QString &error, int msecs)
410 {
411 msecs = AbstractTest::RunTimeout(msecs);
412
413 const QString parameters = QStringLiteral("Program: %1 \nArguments: %2.")
414 .arg(program, arguments.join(QStringLiteral(", ")));
415
416 QFileInfo info(program);
417 if (not info.exists())
418 {
419 error = QStringLiteral("Can't find binary.\n%1").arg(parameters);
420 return TST_EX_BIN;
421 }
422
423 QScopedPointer<QProcess> process(new QProcess());
424 process->setWorkingDirectory(info.absoluteDir().absolutePath());
425 process->start(program, arguments);
426
427 if (not process->waitForStarted(msecs))
428 {
429 error = QStringLiteral("The start operation timed out or an error occurred.\n%1\n%2")
430 .arg(parameters, QString(process->readAllStandardError()));
431 process->kill();
432 return TST_EX_START_TIME_OUT;
433 }
434
435 if (not process->waitForFinished(msecs))
436 {
437 error = QStringLiteral("The finish operation timed out or an error occurred.\n%1\n%2")
438 .arg(parameters, QString(process->readAllStandardError()));
439 process->kill();
440 return TST_EX_FINISH_TIME_OUT;
441 }
442
443 if (process->exitStatus() == QProcess::CrashExit)
444 {
445 error = QStringLiteral("Program crashed.\n%1\n%2").arg(parameters, QString(process->readAllStandardError()));
446 return TST_EX_CRASH;
447 }
448
449 if (process->exitCode() != exit)
450 {
451 error = QStringLiteral("Unexpected finish. Exit code: %1\n%2").arg(process->exitCode())
452 .arg(QString(process->readAllStandardError()));
453 return process->exitCode();
454 }
455
456 return process->exitCode();
457 }
458
459 //---------------------------------------------------------------------------------------------------------------------
CopyRecursively(const QString & srcFilePath,const QString & tgtFilePath) const460 bool AbstractTest::CopyRecursively(const QString &srcFilePath, const QString &tgtFilePath) const
461 {
462 QFileInfo srcFileInfo(srcFilePath);
463 if (srcFileInfo.isDir())
464 {
465 QDir targetDir(tgtFilePath);
466 targetDir.cdUp();
467 const QString dirName = QFileInfo(tgtFilePath).fileName();
468 if (not targetDir.mkdir(dirName))
469 {
470 const QString msg = QStringLiteral("Can't create dir '%1'.").arg(dirName);
471 QWARN(qUtf8Printable(msg));
472 return false;
473 }
474 QDir sourceDir(srcFilePath);
475 const QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot |
476 QDir::Hidden | QDir::System);
477 for (auto &fileName : fileNames)
478 {
479 const QString newSrcFilePath = srcFilePath + QDir::separator() + fileName;
480 const QString newTgtFilePath = tgtFilePath + QDir::separator() + fileName;
481 if (not CopyRecursively(newSrcFilePath, newTgtFilePath))
482 {
483 return false;
484 }
485 }
486 }
487 else
488 {
489 if (QFileInfo::exists(tgtFilePath))
490 {
491 const QString msg = QStringLiteral("File '%1' exists.").arg(srcFilePath);
492 QWARN(qUtf8Printable(msg));
493
494 if (QFile::remove(tgtFilePath))
495 {
496 QWARN("File successfully removed.");
497 }
498 else
499 {
500 QWARN("Can't remove file.");
501 return false;
502 }
503 }
504
505 // Check error: Cannot open %file for input
506 QFile srcFile(srcFilePath);
507 if (not srcFile.open(QFile::ReadOnly))
508 {
509 const QString msg = QStringLiteral("Can't copy file '%1'. Error: %2")
510 .arg(srcFilePath, srcFile.errorString());
511 QWARN(qUtf8Printable(msg));
512 return false;
513 }
514 srcFile.close();
515
516 if (not srcFile.copy(tgtFilePath))
517 {
518 const QString msg = QStringLiteral("Can't copy file '%1' to '%2'. Error: %3")
519 .arg(srcFilePath, tgtFilePath, srcFile.errorString());
520 QWARN(qUtf8Printable(msg));
521 return false;
522 }
523 }
524 return true;
525 }
526
527 //---------------------------------------------------------------------------------------------------------------------
PrepareDocument(const QString & json,QByteArray & data) const528 void AbstractTest::PrepareDocument(const QString &json, QByteArray &data) const
529 {
530 QFile loadFile(json);
531 if (not loadFile.open(QIODevice::ReadOnly))
532 {
533 const QString error = QStringLiteral("Couldn't open json file. %1").arg(loadFile.errorString());
534 QFAIL(qUtf8Printable(error));
535 }
536
537 data = loadFile.readAll();
538 }
539
540 //---------------------------------------------------------------------------------------------------------------------
TestRoot(const QJsonObject & root,const QString & attribute,const QString & file) const541 void AbstractTest::TestRoot(const QJsonObject &root, const QString &attribute, const QString &file) const
542 {
543 if (not root.contains(attribute))
544 {
545 const QString error = QStringLiteral("Invalid json file '%1'. File doesn't contain root object.").arg(file);
546 QFAIL(qUtf8Printable(error));
547 }
548 }
549
550 //---------------------------------------------------------------------------------------------------------------------
ReadStringValue(const QJsonObject & itemObject,const QString & attribute,QString & value,const QString & defaultValue) const551 void AbstractTest::ReadStringValue(const QJsonObject &itemObject, const QString &attribute, QString &value,
552 const QString &defaultValue) const
553 {
554 if (itemObject.contains(attribute))
555 {
556 QJsonValue attributeValue = itemObject[attribute];
557 if (attributeValue.isString())
558 {
559 value = attributeValue.toString();
560 }
561 else
562 {
563 const QString error = QStringLiteral("%1 is not string '%2'.").arg(attribute, attributeValue.toString());
564 QFAIL(qUtf8Printable(error));
565 }
566 }
567 else
568 {
569 if (not defaultValue.isEmpty())
570 {
571 value = defaultValue;
572 }
573 else
574 {
575 const QString error = QStringLiteral("Json object does not contain attribute '%1'.").arg(attribute);
576 QFAIL(qUtf8Printable(error));
577 }
578 }
579 }
580
581 //---------------------------------------------------------------------------------------------------------------------
ReadBooleanValue(const QJsonObject & itemObject,const QString & attribute,bool & value,const QString & defaultValue) const582 void AbstractTest::ReadBooleanValue(const QJsonObject &itemObject, const QString &attribute, bool &value,
583 const QString &defaultValue) const
584 {
585 if (itemObject.contains(attribute))
586 {
587 QJsonValue attributeValue = itemObject[attribute];
588 if (attributeValue.isBool())
589 {
590 value = attributeValue.toBool();
591 }
592 else
593 {
594 const QString error = QStringLiteral("%1 is not boolean value '%2'.").arg(attribute,
595 attributeValue.toString());
596 QFAIL(qUtf8Printable(error));
597 }
598 }
599 else
600 {
601 if (not defaultValue.isEmpty())
602 {
603 bool ok = false;
604 int defVal = defaultValue.toInt(&ok);
605
606 if (not ok)
607 {
608 const QString error = QStringLiteral("Cannot convert default value '%1' to int.").arg(defaultValue);
609 QFAIL(qUtf8Printable(error));
610 }
611
612 value = static_cast<bool>(defVal);
613 }
614 else
615 {
616 const QString error = QStringLiteral("Json object does not contain attribute '%1'.").arg(attribute);
617 QFAIL(qUtf8Printable(error));
618 }
619 }
620 }
621
622 //---------------------------------------------------------------------------------------------------------------------
ReadPointValue(const QJsonObject & itemObject,const QString & attribute,VPointF & value)623 void AbstractTest::ReadPointValue(const QJsonObject &itemObject, const QString &attribute, VPointF &value)
624 {
625 if (itemObject.contains(attribute))
626 {
627 QJsonObject p1Object = itemObject[attribute].toObject();
628 VPointFromJson(p1Object, value);
629 }
630 else
631 {
632 const QString error = QStringLiteral("Json object does not contain attribute '%1'.").arg(attribute);
633 QFAIL(qUtf8Printable(error));
634 }
635 }
636
637 //---------------------------------------------------------------------------------------------------------------------
ReadSplinePointValues(const QJsonObject & itemObject,const QString & attribute,QVector<VSplinePoint> & points)638 void AbstractTest::ReadSplinePointValues(const QJsonObject &itemObject, const QString &attribute,
639 QVector<VSplinePoint> &points)
640 {
641 points.clear();
642 if (itemObject.contains(attribute))
643 {
644 QJsonArray nodes = itemObject[attribute].toArray();
645 for (int i = 0; i < nodes.size(); ++i)
646 {
647 QJsonObject item = nodes[i].toObject();
648 VSplinePoint point;
649 ReadSplinePointValue(item, point);
650 points.append(point);
651 }
652 }
653 else
654 {
655 const QString error = QStringLiteral("Json object does not contain attribute '%1'.").arg(attribute);
656 QFAIL(qUtf8Printable(error));
657 }
658 }
659
660 //---------------------------------------------------------------------------------------------------------------------
ReadSplinePointValue(const QJsonObject & itemObject,VSplinePoint & point)661 void AbstractTest::ReadSplinePointValue(const QJsonObject &itemObject, VSplinePoint &point)
662 {
663 qreal angle1 = 0;
664 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("angle1"), angle1);
665
666 QString angle1Formula;
667 AbstractTest::ReadStringValue(itemObject, QStringLiteral("angle1Formula"), angle1Formula);
668
669 qreal angle2 = 0;
670 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("angle2"), angle2);
671
672 QString angle2Formula;
673 AbstractTest::ReadStringValue(itemObject, QStringLiteral("angle2Formula"), angle2Formula);
674
675 qreal length1 = 0;
676 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("length1"), length1);
677
678 QString length1Formula;
679 AbstractTest::ReadStringValue(itemObject, QStringLiteral("length1Formula"), length1Formula);
680
681 qreal length2 = 0;
682 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("length2"), length2);
683
684 QString length2Formula;
685 AbstractTest::ReadStringValue(itemObject, QStringLiteral("length2Formula"), length2Formula);
686
687 VPointF pSpline;
688 ReadPointValue(itemObject, QStringLiteral("point"), pSpline);
689
690 point = VSplinePoint(pSpline, angle1, angle1Formula, angle2, angle2Formula, length1, length1Formula, length2,
691 length2Formula);
692 }
693
694 //---------------------------------------------------------------------------------------------------------------------
ReadPieceNodeValue(const QJsonObject & itemObject,VPieceNode & node)695 void AbstractTest::ReadPieceNodeValue(const QJsonObject &itemObject, VPieceNode &node)
696 {
697 vidtype id = NULL_ID;
698 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("id"), id);
699
700 Tool typeTool = Tool::LAST_ONE_DO_NOT_USE;
701 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("type"), typeTool);
702
703 bool reverse = false;
704 AbstractTest::ReadBooleanValue(itemObject, QStringLiteral("reverse"), reverse, QChar('0'));
705
706 node = VPieceNode(id, typeTool, reverse);
707 }
708
709 //---------------------------------------------------------------------------------------------------------------------
QPointFromJson(const QJsonObject & itemObject,QPointF & point) const710 void AbstractTest::QPointFromJson(const QJsonObject &itemObject, QPointF &point) const
711 {
712 qreal x = 0;
713 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("x"), x);
714 point.setX(x);
715
716 qreal y = 0;
717 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("y"), y);
718 point.setY(y);
719 }
720
721 //---------------------------------------------------------------------------------------------------------------------
722 template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type*>
ReadDoubleValue(const QJsonObject & itemObject,const QString & attribute,T & value,const QString & defaultValue) const723 void AbstractTest::ReadDoubleValue(const QJsonObject &itemObject, const QString &attribute, T &value,
724 const QString &defaultValue) const
725 {
726 if (itemObject.contains(attribute))
727 {
728 QJsonValue attributeValue = itemObject[attribute];
729 if (attributeValue.isDouble())
730 {
731 value = static_cast<T>(attributeValue.toDouble());
732 }
733 else
734 {
735 const QString error = QStringLiteral("%1 is not double '%2'.").arg(attribute, attributeValue.toString());
736 QFAIL(qUtf8Printable(error));
737 }
738 }
739 else
740 {
741 if (not defaultValue.isEmpty())
742 {
743 bool ok = false;
744 value = static_cast<T>(defaultValue.toDouble(&ok));
745
746 if (not ok)
747 {
748 const QString error = QStringLiteral("Cannot convert default value '%1' to double.").arg(defaultValue);
749 QFAIL(qUtf8Printable(error));
750 }
751 }
752 else
753 {
754 const QString error = QStringLiteral("Json object does not contain attribute '%1'.").arg(attribute);
755 QFAIL(qUtf8Printable(error));
756 }
757 }
758 }
759
760 //---------------------------------------------------------------------------------------------------------------------
761 template<typename T, typename std::enable_if<std::is_enum<T>::value>::type*>
ReadDoubleValue(const QJsonObject & itemObject,const QString & attribute,T & value,const QString & defaultValue) const762 void AbstractTest::ReadDoubleValue(const QJsonObject &itemObject, const QString &attribute, T &value,
763 const QString &defaultValue) const
764 {
765 if (itemObject.contains(attribute))
766 {
767 QJsonValue attributeValue = itemObject[attribute];
768 if (attributeValue.isDouble())
769 {
770 value = static_cast<T>(static_cast<int>(attributeValue.toDouble()));
771 }
772 else
773 {
774 const QString error = QStringLiteral("%1 is not double '%2'.").arg(attribute, attributeValue.toString());
775 QFAIL(qUtf8Printable(error));
776 }
777 }
778 else
779 {
780 if (not defaultValue.isEmpty())
781 {
782 bool ok = false;
783 value = static_cast<T>(defaultValue.toInt(&ok));
784
785 if (not ok)
786 {
787 const QString error = QStringLiteral("Cannot convert default value '%1' to int.").arg(defaultValue);
788 QFAIL(qUtf8Printable(error));
789 }
790 }
791 else
792 {
793 const QString error = QStringLiteral("Json object does not contain attribute '%1'.").arg(attribute);
794 QFAIL(qUtf8Printable(error));
795 }
796 }
797 }
798
799 //---------------------------------------------------------------------------------------------------------------------
800 template<typename T, typename std::enable_if<std::is_integral<T>::value>::type*>
ReadDoubleValue(const QJsonObject & itemObject,const QString & attribute,T & value,const QString & defaultValue) const801 void AbstractTest::ReadDoubleValue(const QJsonObject &itemObject, const QString &attribute, T &value,
802 const QString &defaultValue) const
803 {
804 if (itemObject.contains(attribute))
805 {
806 QJsonValue attributeValue = itemObject[attribute];
807 if (attributeValue.isDouble())
808 {
809 value = static_cast<T>(attributeValue.toDouble());
810 }
811 else
812 {
813 const QString error = QStringLiteral("%1 is not double '%2'.").arg(attribute, attributeValue.toString());
814 QFAIL(qUtf8Printable(error));
815 }
816 }
817 else
818 {
819 if (not defaultValue.isEmpty())
820 {
821 bool ok = false;
822 value = static_cast<T>(defaultValue.toInt(&ok));
823
824 if (not ok)
825 {
826 const QString error = QStringLiteral("Cannot convert default value '%1' to int.").arg(defaultValue);
827 QFAIL(qUtf8Printable(error));
828 }
829 }
830 else
831 {
832 const QString error = QStringLiteral("Json object does not contain attribute '%1'.").arg(attribute);
833 QFAIL(qUtf8Printable(error));
834 }
835 }
836 }
837
838 //---------------------------------------------------------------------------------------------------------------------
VPointFromJson(const QJsonObject & itemObject,VPointF & point)839 void AbstractTest::VPointFromJson(const QJsonObject &itemObject, VPointF &point)
840 {
841 vidtype id = NULL_ID;
842 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("id"), id);
843
844 qreal mx = 0;
845 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("mx"), mx);
846
847 qreal my = 0;
848 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("my"), my);
849
850 QString name;
851 AbstractTest::ReadStringValue(itemObject, QStringLiteral("name"), name);
852
853 qreal x = 0;
854 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("x"), x);
855
856 qreal y = 0;
857 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("y"), y);
858
859 point = VPointF(x, y, name, mx, my);
860 point.setId(id);
861 }
862
863 //---------------------------------------------------------------------------------------------------------------------
QLineFromJson(const QJsonObject & itemObject,QLineF & line)864 void AbstractTest::QLineFromJson(const QJsonObject &itemObject, QLineF &line)
865 {
866 QPointF p1;
867 QPointFromJson(itemObject[QStringLiteral("p1")].toObject(), p1);
868
869 QPointF p2;
870 QPointFromJson(itemObject[QStringLiteral("p2")].toObject(), p2);
871
872 line = QLineF(p1, p2);
873 }
874
875 //---------------------------------------------------------------------------------------------------------------------
SAPointFromJson(const QJsonObject & itemObject,VSAPoint & point) const876 void AbstractTest::SAPointFromJson(const QJsonObject &itemObject, VSAPoint &point) const
877 {
878 qreal x = 0;
879 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("x"), x);
880 point.setX(x);
881
882 qreal y = 0;
883 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("y"), y);
884 point.setY(y);
885
886 qreal saBefore;
887 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("saBefore"), saBefore, QStringLiteral("-1"));
888 point.SetSABefore(saBefore);
889
890 qreal saAfter;
891 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("saAfter"), saAfter, QStringLiteral("-1"));
892 point.SetSAAfter(saAfter);
893
894 PieceNodeAngle angleType = PieceNodeAngle::ByLength;
895 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("angle"), angleType,
896 QString::number(static_cast<int>(PieceNodeAngle::ByLength)));
897 point.SetAngleType(angleType);
898 }
899
900 //---------------------------------------------------------------------------------------------------------------------
RawSAPointFromJson(const QJsonObject & itemObject,VRawSAPoint & point) const901 void AbstractTest::RawSAPointFromJson(const QJsonObject &itemObject, VRawSAPoint &point) const
902 {
903 qreal x = 0;
904 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("x"), x);
905 point.setX(x);
906
907 qreal y = 0;
908 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("y"), y);
909 point.setY(y);
910
911 bool loopPoint;
912 AbstractTest::ReadBooleanValue(itemObject, QStringLiteral("loopPoint"), loopPoint, QStringLiteral("0"));
913 point.SetLoopPoint(loopPoint);
914 }
915
916 //---------------------------------------------------------------------------------------------------------------------
SplineFromJson(const QJsonObject & itemObject,QSharedPointer<VContainer> & data)917 void AbstractTest::SplineFromJson(const QJsonObject &itemObject, QSharedPointer<VContainer> &data)
918 {
919 vidtype id = NULL_ID;
920 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("id"), id);
921
922 qreal aScale = 0;
923 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("aScale"), aScale);
924
925 qreal angle1 = 0;
926 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("angle1"), angle1);
927
928 QString angle1Formula;
929 AbstractTest::ReadStringValue(itemObject, QStringLiteral("angle1Formula"), angle1Formula);
930
931 qreal angle2 = 0;
932 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("angle2"), angle2);
933
934 QString angle2Formula;
935 AbstractTest::ReadStringValue(itemObject, QStringLiteral("angle2Formula"), angle2Formula);
936
937 qreal c1Length = 0;
938 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("c1Length"), c1Length);
939
940 QString c1LengthFormula;
941 AbstractTest::ReadStringValue(itemObject, QStringLiteral("c1LengthFormula"), c1LengthFormula);
942
943 qreal c2Length = 0;
944 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("c2Length"), c2Length);
945
946 QString c2LengthFormula;
947 AbstractTest::ReadStringValue(itemObject, QStringLiteral("c2LengthFormula"), c2LengthFormula);
948
949 VPointF p1;
950 ReadPointValue(itemObject, QStringLiteral("p1"), p1);
951 data->UpdateGObject(p1.id(), new VPointF(p1));
952
953 VPointF p4;
954 ReadPointValue(itemObject, QStringLiteral("p4"), p4);
955 data->UpdateGObject(p4.id(), new VPointF(p4));
956
957 VSpline *spl = new VSpline(p1, p4, angle1, angle1Formula, angle2, angle2Formula, c1Length, c1LengthFormula,
958 c2Length, c2LengthFormula);
959 spl->SetApproximationScale(aScale);
960 data->UpdateGObject(id, spl);
961 }
962
963 //---------------------------------------------------------------------------------------------------------------------
SplinePathFromJson(const QJsonObject & itemObject,QSharedPointer<VContainer> & data)964 void AbstractTest::SplinePathFromJson(const QJsonObject &itemObject, QSharedPointer<VContainer> &data)
965 {
966 vidtype id = NULL_ID;
967 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("id"), id);
968
969 qreal aScale = 0;
970 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("aScale"), aScale);
971
972 QVector<VSplinePoint> points;
973 AbstractTest::ReadSplinePointValues(itemObject, QStringLiteral("nodes"), points);
974 for (auto &point : points)
975 {
976 data->UpdateGObject(point.P().id(), new VPointF(point.P()));
977 }
978
979 VSplinePath *path = new VSplinePath(points);
980 path->SetApproximationScale(aScale);
981 data->UpdateGObject(id, path);
982 }
983
984 //---------------------------------------------------------------------------------------------------------------------
DBFromJson(const QJsonObject & dbObject,QSharedPointer<VContainer> & data)985 void AbstractTest::DBFromJson(const QJsonObject &dbObject, QSharedPointer<VContainer> &data)
986 {
987 const QString itemsKey = QStringLiteral("items");
988
989 if (dbObject.contains(itemsKey))
990 {
991 QJsonArray items = dbObject[itemsKey].toArray();
992 for (int i = 0; i < items.size(); ++i)
993 {
994 QJsonObject itemObject = items[i].toObject();
995 GOType objectType;
996 AbstractTest::ReadDoubleValue(itemObject, QStringLiteral("type"), objectType);
997
998 switch(objectType)
999 {
1000 case GOType::Point:
1001 {
1002 VPointF point;
1003 VPointFromJson(itemObject, point);
1004 data->UpdateGObject(point.id(), new VPointF(point));
1005 break;
1006 }
1007 case GOType::Spline:
1008 SplineFromJson(itemObject, data);
1009 break;
1010 case GOType::SplinePath:
1011 SplinePathFromJson(itemObject, data);
1012 break;
1013 default:
1014 {
1015 const QString error = QStringLiteral("Not supported item type '%1'.")
1016 .arg(static_cast<int>(objectType));
1017 QFAIL(qUtf8Printable(error));
1018 }
1019 }
1020 }
1021 }
1022 else
1023 {
1024 const QString error = QStringLiteral("DB json object does not contain items.");
1025 QFAIL(qUtf8Printable(error));
1026 }
1027 }
1028
1029 //---------------------------------------------------------------------------------------------------------------------
MainPathFromJson(const QJsonObject & pieceObject,VPiece & piece)1030 void AbstractTest::MainPathFromJson(const QJsonObject &pieceObject, VPiece &piece)
1031 {
1032 qreal saWidth = 0;
1033 AbstractTest::ReadDoubleValue(pieceObject, QStringLiteral("saWidth"), saWidth);
1034
1035 bool seamAllowance = false;
1036 AbstractTest::ReadBooleanValue(pieceObject, QStringLiteral("seamAllowance"), seamAllowance);
1037
1038 piece.SetSeamAllowance(seamAllowance);
1039 piece.SetSAWidth(saWidth);
1040
1041 piece.GetPath().Clear();
1042
1043 const QString nodesKey = QStringLiteral("nodes");
1044
1045 if (pieceObject.contains(nodesKey))
1046 {
1047 QJsonArray nodes = pieceObject[nodesKey].toArray();
1048 for (int i = 0; i < nodes.size(); ++i)
1049 {
1050 QJsonObject itemObject = nodes[i].toObject();
1051
1052 VPieceNode node;
1053 ReadPieceNodeValue(itemObject, node);
1054 piece.GetPath().Append(node);
1055 }
1056 }
1057 else
1058 {
1059 const QString error = QStringLiteral("Piece json object does not contain nodes.");
1060 QFAIL(qUtf8Printable(error));
1061 }
1062 }
1063