ctkEventTranslatorPlayerWidget.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0.txt
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // QT includes
  15. #include <QDebug>
  16. #include <QFileDialog>
  17. #include <QFile>
  18. #include <QMetaEnum>
  19. #include <QTextStream>
  20. #include <QVBoxLayout>
  21. // CTKTesting includes
  22. #include "ctkCallback.h"
  23. #include "ctkEventTranslatorPlayerWidget.h"
  24. #include "ctkQtTestingUtility.h"
  25. #include "ctkXMLEventObserver.h"
  26. #include "ctkXMLEventSource.h"
  27. #include "ui_ctkEventTranslatorPlayerWidget.h"
  28. // Standard include
  29. #include <cmath>
  30. //-----------------------------------------------------------------------------
  31. class ctkEventTranslatorPlayerWidgetPrivate
  32. : public Ui_ctkEventTranslatorPlayerWidget
  33. {
  34. public:
  35. ~ctkEventTranslatorPlayerWidgetPrivate();
  36. QList<ctkEventTranslatorPlayerWidget::InfoTestCase*> TestCase;
  37. pqTestUtility* TestUtility;
  38. };
  39. ctkEventTranslatorPlayerWidgetPrivate::~ctkEventTranslatorPlayerWidgetPrivate()
  40. {
  41. delete this->TestUtility;
  42. this->TestUtility = 0;
  43. }
  44. //-----------------------------------------------------------------------------
  45. ctkEventTranslatorPlayerWidget::ctkEventTranslatorPlayerWidget()
  46. : Superclass()
  47. , d_ptr(new ctkEventTranslatorPlayerWidgetPrivate)
  48. {
  49. Q_D(ctkEventTranslatorPlayerWidget);
  50. d->setupUi(this);
  51. QObject::connect(d->TranslatorButton, SIGNAL(clicked(bool)),
  52. this, SLOT(onClickedRecord(bool)));
  53. QObject::connect(d->PlayerButton, SIGNAL(clicked(bool)),
  54. this, SLOT(onClickedPlayback(bool)));
  55. QObject::connect(d->TestCaseComboBox, SIGNAL(currentIndexChanged(int)),
  56. this, SLOT(switchTestCase(int)));
  57. d->TestUtility = 0;
  58. }
  59. //-----------------------------------------------------------------------------
  60. ctkEventTranslatorPlayerWidget::~ctkEventTranslatorPlayerWidget()
  61. {
  62. Q_D(ctkEventTranslatorPlayerWidget);
  63. d->TestUtility = 0;
  64. }
  65. //-----------------------------------------------------------------------------
  66. void ctkEventTranslatorPlayerWidget::addTestCase(QWidget *widget,
  67. QString fileName,
  68. void (*newCallback)(void * data))
  69. {
  70. Q_D(ctkEventTranslatorPlayerWidget);
  71. InfoTestCase* infoTestCase = new InfoTestCase;
  72. infoTestCase->Widget = widget;
  73. infoTestCase->FileName = fileName;
  74. infoTestCase->Callback = new ctkCallback(newCallback);
  75. infoTestCase->Callback->setCallbackData(widget);
  76. infoTestCase->Dialog = false;
  77. d->TestCase.push_back(infoTestCase);
  78. d->stackedWidget->addWidget(widget);
  79. d->TestCaseComboBox->addItem(QString::number(d->TestCase.count()),
  80. QVariant(d->TestCase.count()));
  81. }
  82. //-----------------------------------------------------------------------------
  83. void ctkEventTranslatorPlayerWidget::addTestCase(QDialog *dialog,
  84. QString fileName,
  85. void (*newCallback)(void * data))
  86. {
  87. Q_D(ctkEventTranslatorPlayerWidget);
  88. InfoTestCase* infoTestCase = new InfoTestCase;
  89. infoTestCase->Widget = dialog;
  90. infoTestCase->FileName = fileName;
  91. infoTestCase->Callback = new ctkCallback(newCallback);
  92. infoTestCase->Callback->setCallbackData(dialog);
  93. infoTestCase->Dialog = false;
  94. d->TestCase.push_back(infoTestCase);
  95. // QVBoxLayout* layout = new QVBoxLayout();
  96. QPushButton* button = new QPushButton("Open the Dialog");
  97. connect(button, SIGNAL(clicked(bool)), this, SLOT(popupDialog()));
  98. d->stackedWidget->addWidget(button);
  99. d->TestCaseComboBox->addItem(QString::number(d->TestCase.count()),
  100. QVariant(d->TestCase.count()));
  101. }
  102. //-----------------------------------------------------------------------------
  103. void ctkEventTranslatorPlayerWidget::setTestUtility(pqTestUtility* newTestUtility)
  104. {
  105. Q_D(ctkEventTranslatorPlayerWidget);
  106. d->TestUtility = newTestUtility;
  107. d->TestUtility->addEventObserver("xml", new ctkXMLEventObserver(d->TestUtility));
  108. ctkXMLEventSource* eventSource = new ctkXMLEventSource(d->TestUtility);
  109. eventSource->setRestoreSettingsAuto(true);
  110. d->TestUtility->addEventSource("xml", eventSource);
  111. }
  112. //-----------------------------------------------------------------------------
  113. pqTestUtility* ctkEventTranslatorPlayerWidget::testUtility() const
  114. {
  115. Q_D(const ctkEventTranslatorPlayerWidget);
  116. return d->TestUtility;
  117. }
  118. //-----------------------------------------------------------------------------
  119. void ctkEventTranslatorPlayerWidget::addWidgetEventPlayer(
  120. pqWidgetEventPlayer* player)
  121. {
  122. Q_D(ctkEventTranslatorPlayerWidget);
  123. d->TestUtility->eventPlayer()->addWidgetEventPlayer(player);
  124. }
  125. //-----------------------------------------------------------------------------
  126. void ctkEventTranslatorPlayerWidget::addWidgetEventTranslator(
  127. pqWidgetEventTranslator* translator)
  128. {
  129. Q_D(ctkEventTranslatorPlayerWidget);
  130. d->TestUtility->eventTranslator()->addWidgetEventTranslator(translator);
  131. }
  132. //-----------------------------------------------------------------------------
  133. void ctkEventTranslatorPlayerWidget::record(int currentTestCase)
  134. {
  135. Q_D(ctkEventTranslatorPlayerWidget);
  136. if(d->TestCase.count() == 0 ||
  137. currentTestCase > d->TestCase.count() - 1)
  138. {
  139. qWarning() << "Problem with the test case. Please verify that you added a test case.";
  140. return;
  141. }
  142. // We load the xml and check if it is different form the other test case
  143. QFile* filexml = new QFile(d->TestCase[currentTestCase]->FileName);
  144. if (!filexml->open(QIODevice::ReadWrite))
  145. {
  146. qWarning() << "The file .xml was not created";
  147. return;
  148. }
  149. for(int i = 0 ; i < currentTestCase && i != currentTestCase; i++)
  150. {
  151. if (d->TestCase[i]->FileName ==
  152. d->TestCase[currentTestCase]->FileName)
  153. {
  154. qWarning() << "This xml file should already recorded\n";
  155. return;
  156. }
  157. }
  158. d->TestUtility->recordTests(filexml->fileName());
  159. }
  160. //-----------------------------------------------------------------------------
  161. bool ctkEventTranslatorPlayerWidget::play(int currentTestCase)
  162. {
  163. Q_D(ctkEventTranslatorPlayerWidget);
  164. if(d->TestCase.count() == 0)
  165. {
  166. qWarning() << "No test case had been added. Please add a test case.";
  167. return false;
  168. }
  169. // Connect the slot player done to the the good callback
  170. QObject::connect(this, SIGNAL(playerDone(QWidget*)),
  171. d->TestCase[currentTestCase]->Callback, SLOT(invoke()));
  172. if (!QFile::exists(d->TestCase[currentTestCase]->FileName))
  173. {
  174. qWarning() << "No .xml file for this test case";
  175. return false;
  176. }
  177. if (!d->TestUtility->playTests(QStringList(d->TestCase[currentTestCase]->FileName)))
  178. {
  179. qWarning() << "The Test case " << currentTestCase
  180. << " playback has failed !";
  181. return false;
  182. }
  183. emit this->playerDone(d->TestCase[currentTestCase]->Widget);
  184. QObject::disconnect(d->TestCase[currentTestCase]->Callback);
  185. return true;
  186. }
  187. //-----------------------------------------------------------------------------
  188. void ctkEventTranslatorPlayerWidget::play()
  189. {
  190. Q_D(ctkEventTranslatorPlayerWidget);
  191. bool success = true;
  192. for(int i = 0 ; i < d->TestCase.count() ; i++ )
  193. {
  194. d->TestCaseComboBox->setCurrentIndex(i);
  195. success &= this->play(i);
  196. }
  197. QApplication::exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
  198. }
  199. //-----------------------------------------------------------------------------
  200. void ctkEventTranslatorPlayerWidget::popupDialog()
  201. {
  202. Q_D(ctkEventTranslatorPlayerWidget);
  203. QDialog* widget = qobject_cast<QDialog*>(d->TestCase[d->TestCaseComboBox->currentIndex()]->Widget);
  204. widget->exec();
  205. }
  206. //-----------------------------------------------------------------------------
  207. void ctkEventTranslatorPlayerWidget::onClickedPlayback(bool)
  208. {
  209. Q_D(ctkEventTranslatorPlayerWidget);
  210. this->play(d->TestCaseComboBox->currentIndex());
  211. }
  212. //-----------------------------------------------------------------------------
  213. void ctkEventTranslatorPlayerWidget::onClickedRecord(bool)
  214. {
  215. Q_D(ctkEventTranslatorPlayerWidget);
  216. this->record(d->TestCaseComboBox->currentIndex());
  217. }
  218. //-----------------------------------------------------------------------------
  219. void ctkEventTranslatorPlayerWidget::switchTestCase(int index)
  220. {
  221. Q_D(ctkEventTranslatorPlayerWidget);
  222. d->stackedWidget->setCurrentIndex(index);
  223. }
  224. //-----------------------------------------------------------------------------
  225. const char* enumValueToKey(QObject* object, const char* enumName, int value)
  226. {
  227. const QMetaObject * metaObject = object->metaObject();
  228. QMetaEnum theEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
  229. return theEnum.valueToKey(value);
  230. }
  231. //-----------------------------------------------------------------------------
  232. bool ctkEventTranslatorPlayerWidget::compare(const double &actual,
  233. const double& expected,
  234. const char* actualName,
  235. const char* expectedName,
  236. const char * function, int line)
  237. {
  238. if (actual != expected)
  239. {
  240. QTextStream(stderr, QIODevice::WriteOnly)
  241. << "Line " << line << " - Problem with function " << function << "\n"
  242. << "\tActual value : '" << actualName << "' = " << actual << " \n"
  243. << "\tExpected value : '" << expectedName << "' = " << expected << endl;
  244. QApplication::exit(EXIT_FAILURE);
  245. return false;
  246. }
  247. return true;
  248. }
  249. //-----------------------------------------------------------------------------
  250. bool ctkEventTranslatorPlayerWidget::compare(const int &actual,
  251. const int& expected,
  252. const char* actualName,
  253. const char* expectedName,
  254. const char * function, int line)
  255. {
  256. if (actual != expected)
  257. {
  258. QTextStream(stderr, QIODevice::WriteOnly)
  259. << "Line " << line << " - Problem with function " << function << "\n"
  260. << "\tActual value : '" << actualName << "' = " << actual << " \n"
  261. << "\tExpected value : '" << expectedName << "' = " << expected << endl;
  262. QApplication::exit(EXIT_FAILURE);
  263. return false;
  264. }
  265. // enumValueToKey(widget, "Axis", currentCurrentAxis)
  266. return true;
  267. }
  268. //-----------------------------------------------------------------------------
  269. bool ctkEventTranslatorPlayerWidget::compare(const QString& actual,
  270. const QString& expected,
  271. const char* actualName,
  272. const char* expectedName,
  273. const char * function, int line)
  274. {
  275. if (actual != expected)
  276. {
  277. QTextStream(stderr, QIODevice::WriteOnly)
  278. << "Line " << line << " - Problem with function " << function << "\n"
  279. << "\tActual value : '" << actualName << "' = " << actual << " \n"
  280. << "\tExpected value : '" << expectedName << "' = " << expected << endl;
  281. QApplication::exit(EXIT_FAILURE);
  282. return false;
  283. }
  284. // enumValueToKey(widget, "Axis", currentCurrentAxis)
  285. return true;
  286. }
  287. //-----------------------------------------------------------------------------
  288. bool ctkEventTranslatorPlayerWidget::compare(const QStringList& actual,
  289. const QStringList& expected,
  290. const char* actualName,
  291. const char* expectedName,
  292. const char * function, int line)
  293. {
  294. if (actual != expected)
  295. {
  296. QTextStream(stderr, QIODevice::WriteOnly)
  297. << "Line " << line << " - Problem with function " << function << "\n"
  298. << "\tActual value : '" << actualName << "' = " << actual.join(" ") << " \n"
  299. << "\tExpected value : '" << expectedName << "' = " << expected.join(" ") << endl;
  300. QApplication::exit(EXIT_FAILURE);
  301. return false;
  302. }
  303. // enumValueToKey(widget, "Axis", currentCurrentAxis)
  304. return true;
  305. }
  306. //-----------------------------------------------------------------------------
  307. bool ctkEventTranslatorPlayerWidget::compare(const QDateTime& actual,
  308. const QDateTime& expected,
  309. const char* actualName,
  310. const char* expectedName,
  311. const char * function, int line)
  312. {
  313. if (actual != expected)
  314. {
  315. QTextStream(stderr, QIODevice::WriteOnly)
  316. << "Line " << line << " - Problem with function " << function << "\n"
  317. << "\tActual value : '" << actualName << "' = " << actual.date().toString() << " \n"
  318. << "\tExpected value : '" << expectedName << "' = " << expected.date().toString() << endl;
  319. QApplication::exit(EXIT_FAILURE);
  320. return false;
  321. }
  322. // enumValueToKey(widget, "Axis", currentCurrentAxis)
  323. return true;
  324. }
  325. //-----------------------------------------------------------------------------
  326. bool ctkEventTranslatorPlayerWidget::compare(const QColor& actual,
  327. const QColor& expected,
  328. const char* actualName,
  329. const char* expectedName,
  330. const char * function, int line)
  331. {
  332. if (actual != expected)
  333. {
  334. QTextStream(stderr, QIODevice::WriteOnly)
  335. << "Line " << line << " - Problem with function " << function << "\n"
  336. << "\tActual value : '" << actualName << "' = R:" << actual.red() << " G:"<< actual.green() << " B:" << actual.blue() << "\n"
  337. << "\tExpected value : '" << expectedName << "' = R:" << expected.red() << " G:"<< expected.green() << " B:" << expected.blue()<< endl;
  338. QApplication::exit(EXIT_FAILURE);
  339. return false;
  340. }
  341. // enumValueToKey(widget, "Axis", currentCurrentAxis)
  342. return true;
  343. }
  344. //-----------------------------------------------------------------------------
  345. bool ctkEventTranslatorPlayerWidget::compare(const QImage& actual,
  346. const QImage& expected,
  347. const char* actualName,
  348. const char* expectedName,
  349. const char * function, int line)
  350. {
  351. double totaldiff = 0.0 ; //holds the number of different pixels
  352. // images are considered the same if both contain a null image
  353. if (actual.isNull() && expected.isNull())
  354. {
  355. return true;
  356. }
  357. // images are not the same if one images contains a null image
  358. if (actual.isNull() || expected.isNull())
  359. {
  360. QTextStream(stderr, QIODevice::WriteOnly)
  361. << "Line " << line << " - 1 image is Null " << function << "\n" << endl;
  362. QApplication::exit(EXIT_FAILURE);
  363. return false;
  364. }
  365. // images do not have the same size
  366. if (actual.size() != expected.size())
  367. {
  368. QTextStream(stderr, QIODevice::WriteOnly)
  369. << "Line " << line << " - The 2 Images don't have the same size " << function << "\n"
  370. << "\tActual value : '" << actualName << "' = W:" << actual.width() << " H:"<< actual.height() << "\n"
  371. << "\tExpected value : '" << expectedName << "' = W:" << expected.width() << " H:"<< expected.height() << endl;
  372. QApplication::exit(EXIT_FAILURE);
  373. return false;
  374. }
  375. QImage a = actual.convertToFormat(QImage::Format_ARGB32);
  376. QImage e = expected.convertToFormat(QImage::Format_ARGB32);
  377. for ( int y=0; y<a.height(); y++ )
  378. {
  379. for ( int x=0; x<a.width(); x++ )
  380. {
  381. QRgb actPix = a.pixel(x, y);
  382. QRgb expPix = e.pixel(x, y);
  383. if (qAlpha(actPix) == 0 && qAlpha(expPix) == 0)
  384. {
  385. continue;
  386. }
  387. if (actPix != expPix)
  388. {
  389. totaldiff ++;
  390. }
  391. }
  392. }
  393. totaldiff = (totaldiff * 100) / (a.width() * a.height());
  394. if (totaldiff >= 0.01)
  395. {
  396. QTextStream(stderr, QIODevice::WriteOnly)
  397. << "Line " << line << " - The 2 Images have "
  398. << totaldiff << "% differencies \n" << endl;
  399. QApplication::exit(EXIT_FAILURE);
  400. return false;
  401. }
  402. return true;
  403. }