UnitTestDockWidget.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <QCompleter>
  9. #include <QEvent>
  10. #include <QGraphicsScene>
  11. #include <QGraphicsView>
  12. #include <QAction>
  13. #include <QMenu>
  14. #include <QMessageBox>
  15. #include <QScopedValueRollback>
  16. #include <QLineEdit>
  17. #include <QTimer>
  18. #include <QPushButton>
  19. #include <QHeaderView>
  20. #include <AzCore/Component/ComponentApplication.h>
  21. #include <AzCore/RTTI/BehaviorContext.h>
  22. #include <AzCore/UserSettings/UserSettings.h>
  23. #include <AzCore/Serialization/SerializeContext.h>
  24. #include <AzCore/Serialization/EditContext.h>
  25. #include <AzCore/IO/FileIO.h>
  26. #include <AzCore/Asset/AssetManager.h>
  27. #include <Editor/Assets/ScriptCanvasAssetHelpers.h>
  28. #include <AzFramework/StringFunc/StringFunc.h>
  29. #include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
  30. #include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
  31. #include <Editor/QtMetaTypes.h>
  32. #include <Editor/Settings.h>
  33. #include <Editor/GraphCanvas/GraphCanvasEditorNotificationBusId.h>
  34. #include <Editor/Include/ScriptCanvas/GraphCanvas/NodeDescriptorBus.h>
  35. #include <Editor/Model/UnitTestBrowserFilterModel.h>
  36. #include <Editor/Translation/TranslationHelper.h>
  37. #include <Editor/View/Widgets/PropertyGridBus.h>
  38. #include <Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.h>
  39. #include <Editor/View/Widgets/UnitTestPanel/ui_UnitTestDockWidget.h>
  40. #include <Editor/View/Widgets/UnitTestPanel/moc_UnitTestDockWidget.cpp>
  41. #include <Data/Data.h>
  42. #include <ScriptCanvas/Bus/ScriptCanvasExecutionBus.h>
  43. #include <ScriptCanvas/Bus/UnitTestVerificationBus.h>
  44. #include <ScriptCanvas/Data/DataRegistry.h>
  45. #include <ScriptCanvas/GraphCanvas/NodeDescriptorBus.h>
  46. #include <ScriptCanvas/Components/EditorUtils.h>
  47. #include <LyViewPaneNames.h>
  48. namespace ScriptCanvasEditor
  49. {
  50. /////////////////////////
  51. // ItemButtonsDelegate
  52. /////////////////////////
  53. ItemButtonsDelegate::ItemButtonsDelegate(QObject* parent)
  54. : QStyledItemDelegate(parent)
  55. , m_editIcon(QIcon(":/ScriptCanvasEditorResources/Resources/edit_icon.png").pixmap(QSize(14, 14)))
  56. {
  57. }
  58. QPoint ItemButtonsDelegate::GetEditPosition(const QStyleOptionViewItem& option) const
  59. {
  60. return QPoint(option.rect.right() - m_editIcon.width(), option.rect.center().y() - m_editIcon.height() / 2);
  61. }
  62. QPoint ItemButtonsDelegate::GetResultsPosition(const QStyleOptionViewItem& option) const
  63. {
  64. return QPoint(option.rect.left() + m_editIcon.width() + m_leftIconPadding, option.rect.center().y() - m_editIcon.height() / 2);
  65. }
  66. void ItemButtonsDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
  67. {
  68. QStyledItemDelegate::paint(painter, option, index);
  69. if (!index.model()->index(0, 0, index).isValid() && (option.state & QStyle::State_MouseOver))
  70. {
  71. painter->drawPixmap(GetEditPosition(option), m_editIcon);
  72. }
  73. }
  74. bool ItemButtonsDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index)
  75. {
  76. if (!index.model()->index(0, 0, index).isValid() && event->type() == QEvent::MouseButtonRelease)
  77. {
  78. QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
  79. QRect editButtonRect = m_editIcon.rect().translated(GetEditPosition(option));
  80. QRect resultsButtonRect = m_editIcon.rect().translated(GetResultsPosition(option));
  81. if (editButtonRect.contains(mouseEvent->pos()))
  82. {
  83. Q_EMIT EditButtonClicked(index);
  84. }
  85. else if (resultsButtonRect.contains(mouseEvent->pos()))
  86. {
  87. Q_EMIT ResultsButtonClicked(index);
  88. }
  89. }
  90. return QStyledItemDelegate::editorEvent(event, model, option, index);
  91. }
  92. ///////////////////////
  93. // UnitTestComponent
  94. ///////////////////////
  95. void UnitTestComponent::Reflect(AZ::ReflectContext* context)
  96. {
  97. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  98. if (serializeContext)
  99. {
  100. serializeContext->Class<UnitTestComponent, GraphCanvas::GraphCanvasPropertyComponent>()
  101. ->Version(0)
  102. ;
  103. AZ::EditContext* editContext = serializeContext->GetEditContext();
  104. if (editContext)
  105. {
  106. editContext->Class<UnitTestComponent>("Unit Test", "")
  107. ->ClassElement(AZ::Edit::ClassElements::EditorData, "Properties")
  108. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  109. ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &UnitTestComponent::GetTitle)
  110. ;
  111. }
  112. }
  113. }
  114. AZ::Entity* UnitTestComponent::CreateUnitTestEntity()
  115. {
  116. AZ::Entity* entity = aznew AZ::Entity("UnitTestHelper");
  117. entity->CreateComponent<UnitTestComponent>();
  118. return entity;
  119. }
  120. UnitTestComponent::UnitTestComponent()
  121. : m_componentTitle("UnitTest")
  122. {
  123. }
  124. AZStd::string_view UnitTestComponent::GetTitle()
  125. {
  126. return m_componentTitle;
  127. }
  128. /////////////////////////
  129. // UnitTestContextMenu
  130. /////////////////////////
  131. UnitTestContextMenu::UnitTestContextMenu(UnitTestDockWidget* dockWidget, AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* sourceEntry)
  132. : QMenu()
  133. {
  134. AZ::Uuid sourceUuid = sourceEntry->GetSourceUuid();
  135. AZStd::string sourceDisplayName = sourceEntry->GetDisplayName().toUtf8().data();
  136. if (dockWidget->widgetActive)
  137. {
  138. QAction* runAction = new QAction(QObject::tr("Run this test"), this);
  139. runAction->setToolTip(QObject::tr("Run this Test only."));
  140. runAction->setStatusTip(QObject::tr("Run this Test only."));
  141. QObject::connect(runAction,
  142. &QAction::triggered,
  143. [dockWidget, sourceUuid]()
  144. {
  145. AZStd::vector<AZ::Uuid> scriptUuids;
  146. scriptUuids.push_back(sourceUuid);
  147. dockWidget->RunTests(scriptUuids);
  148. }
  149. );
  150. addAction(runAction);
  151. if (dockWidget->m_filter->HasTestResults(sourceUuid))
  152. {
  153. QAction* consoleAction = new QAction(QObject::tr("View test results"), this);
  154. consoleAction->setToolTip(QObject::tr("Read Console Results for this Test."));
  155. consoleAction->setStatusTip(QObject::tr("Read Console Results for this Test."));
  156. QObject::connect(consoleAction,
  157. &QAction::triggered,
  158. [dockWidget, sourceUuid, sourceDisplayName]()
  159. {
  160. dockWidget->OpenTestResults(sourceUuid, sourceDisplayName);
  161. }
  162. );
  163. addAction(consoleAction);
  164. }
  165. }
  166. QAction* openAction = new QAction(QObject::tr("Edit script"), this);
  167. openAction->setToolTip(QObject::tr("Open this Test in the Script Canvas Editor."));
  168. openAction->setStatusTip(QObject::tr("Open this Test in the Script Canvas Editor."));
  169. QObject::connect(openAction,
  170. &QAction::triggered,
  171. [dockWidget, sourceUuid]()
  172. {
  173. dockWidget->OpenScriptInEditor(sourceUuid);
  174. }
  175. );
  176. addAction(openAction);
  177. }
  178. ////////////////////////
  179. // UnitTestDockWidget
  180. ////////////////////////
  181. UnitTestDockWidget::UnitTestDockWidget(QWidget* parent /*= nullptr*/)
  182. : AzQtComponents::StyledDockWidget(parent)
  183. , m_ui(new Ui::UnitTestDockWidget())
  184. , widgetActive(true)
  185. , m_itemButtonsDelegate(new ItemButtonsDelegate(this))
  186. {
  187. m_ui->setupUi(this);
  188. UnitTestWidgetNotificationBus::Handler::BusConnect();
  189. m_ui->searchFilter->setClearButtonEnabled(true);
  190. QObject::connect(m_ui->searchFilter, &QLineEdit::textChanged, this, &UnitTestDockWidget::OnQuickFilterChanged);
  191. QObject::connect(m_ui->searchFilter, &QLineEdit::returnPressed, this, &UnitTestDockWidget::OnReturnPressed);
  192. m_filterTimer.setInterval(250);
  193. m_filterTimer.setSingleShot(true);
  194. m_filterTimer.stop();
  195. QObject::connect(&m_filterTimer, &QTimer::timeout, this, &UnitTestDockWidget::UpdateSearchFilter);
  196. m_ui->testsTree->setContextMenuPolicy(Qt::CustomContextMenu);
  197. connect(m_ui->testsTree, &QWidget::customContextMenuRequested, this, &UnitTestDockWidget::OnContextMenuRequested);
  198. connect(m_ui->closeResults, &QPushButton::clicked, this, &UnitTestDockWidget::OnCloseResultsButton);
  199. m_filter = m_ui->testsTree->m_filter;
  200. m_ui->testsTree->setItemDelegateForColumn(0, m_itemButtonsDelegate);
  201. QObject::connect(m_itemButtonsDelegate, &ItemButtonsDelegate::EditButtonClicked, this, &UnitTestDockWidget::OnEditButtonClicked);
  202. QObject::connect(m_itemButtonsDelegate, &ItemButtonsDelegate::ResultsButtonClicked, this, &UnitTestDockWidget::OnResultsButtonClicked);
  203. if (UnitTestVerificationBus::GetTotalNumOfEventHandlers() == 0)
  204. {
  205. m_ui->testResultsOutput->setPlainText(QString("WARNING: Functionality of this Widget has been limited - Script Canvas Testing Gem is not loaded!"));
  206. m_ui->runButton->setDisabled(true);
  207. widgetActive = false;
  208. }
  209. else
  210. {
  211. m_ui->consoleOutput->hide();
  212. connect(m_ui->runButton, &QPushButton::clicked, this, &UnitTestDockWidget::OnStartTestsButton);
  213. connect(m_ui->testsTree, &QAbstractItemView::doubleClicked, this, &UnitTestDockWidget::OnRowDoubleClicked);
  214. }
  215. }
  216. UnitTestDockWidget::~UnitTestDockWidget()
  217. {
  218. GraphCanvas::AssetEditorNotificationBus::Handler::BusDisconnect();
  219. AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
  220. UnitTestWidgetNotificationBus::Handler::BusDisconnect();
  221. delete m_itemButtonsDelegate;
  222. }
  223. void UnitTestDockWidget::OnCheckStateCountChange(const int count)
  224. {
  225. m_ui->label->setText(QString("Selected %1 test(s).").arg(count));
  226. }
  227. void UnitTestDockWidget::OnContextMenuRequested(const QPoint& pos)
  228. {
  229. QModelIndex index = m_ui->testsTree->indexAt(pos);
  230. QModelIndex sourceIndex = m_filter->mapToSource(index);
  231. if (sourceIndex.isValid())
  232. {
  233. AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry = static_cast<AzToolsFramework::AssetBrowser::AssetBrowserEntry*>(sourceIndex.internalPointer());
  234. if (entry->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Source)
  235. {
  236. UnitTestContextMenu menu(this, static_cast<AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry*>(entry));
  237. menu.exec(m_ui->testsTree->viewport()->mapToGlobal(pos));
  238. }
  239. }
  240. }
  241. void UnitTestDockWidget::OnRowDoubleClicked(QModelIndex index)
  242. {
  243. QModelIndex sourceIndex = m_filter->mapToSource(index);
  244. if (sourceIndex.isValid())
  245. {
  246. AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry = static_cast<AzToolsFramework::AssetBrowser::AssetBrowserEntry*>(sourceIndex.internalPointer());
  247. if (entry->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Source)
  248. {
  249. AZStd::vector<AZ::Uuid> scriptUuids;
  250. scriptUuids.emplace_back(static_cast<AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry*>(entry)->GetSourceUuid());
  251. RunTests(scriptUuids);
  252. }
  253. }
  254. }
  255. void UnitTestDockWidget::OnEditButtonClicked(QModelIndex index)
  256. {
  257. QModelIndex sourceIndex = m_filter->mapToSource(index);
  258. if (sourceIndex.isValid())
  259. {
  260. AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry = static_cast<AzToolsFramework::AssetBrowser::AssetBrowserEntry*>(sourceIndex.internalPointer());
  261. if (entry->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Source)
  262. {
  263. AZ::Uuid sourceUuid = static_cast<AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry*>(entry)->GetSourceUuid();
  264. OpenScriptInEditor(sourceUuid);
  265. }
  266. }
  267. }
  268. void UnitTestDockWidget::OnResultsButtonClicked(QModelIndex index)
  269. {
  270. QModelIndex sourceIndex = m_filter->mapToSource(index);
  271. if (sourceIndex.isValid())
  272. {
  273. AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry = static_cast<AzToolsFramework::AssetBrowser::AssetBrowserEntry*>(sourceIndex.internalPointer());
  274. if (entry->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Source)
  275. {
  276. AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* sourceEntry = static_cast<AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry*>(entry);
  277. AZ::Uuid sourceUuid = sourceEntry->GetSourceUuid();
  278. AZStd::string sourceDisplayName = sourceEntry->GetDisplayName().toUtf8().data();
  279. OpenTestResults(sourceUuid, sourceDisplayName);
  280. }
  281. }
  282. }
  283. QCheckBox* UnitTestDockWidget::GetEnabledCheckBox(ScriptCanvas::ExecutionMode mode)
  284. {
  285. switch (mode)
  286. {
  287. case ScriptCanvas::ExecutionMode::Interpreted:
  288. return m_ui->executionInterpretedEnabled;
  289. case ScriptCanvas::ExecutionMode::Native:
  290. return m_ui->executionNativeEnabled;
  291. default:
  292. AZ_Assert(false, "Unsupported type");
  293. return nullptr;
  294. }
  295. }
  296. QLabel* UnitTestDockWidget::GetStatusLabel(ScriptCanvas::ExecutionMode mode)
  297. {
  298. switch (mode)
  299. {
  300. case ScriptCanvas::ExecutionMode::Interpreted:
  301. return m_ui->labelInterpretedStatus;
  302. case ScriptCanvas::ExecutionMode::Native:
  303. return m_ui->labelNativeStatus;
  304. default:
  305. AZ_Assert(false, "Unsupported type");
  306. return nullptr;
  307. }
  308. }
  309. void UnitTestDockWidget::ClearSearchFilter()
  310. {
  311. {
  312. QSignalBlocker blocker(m_ui->searchFilter);
  313. m_ui->searchFilter->setText("");
  314. }
  315. UpdateSearchFilter();
  316. }
  317. void UnitTestDockWidget::UpdateSearchFilter()
  318. {
  319. m_ui->testsTree->SetSearchFilter(m_ui->searchFilter->userInputText());
  320. }
  321. void UnitTestDockWidget::OnReturnPressed()
  322. {
  323. UpdateSearchFilter();
  324. }
  325. void UnitTestDockWidget::OnQuickFilterChanged(const QString& text)
  326. {
  327. if(text.isEmpty())
  328. {
  329. //If filter was cleared, update immediately
  330. UpdateSearchFilter();
  331. return;
  332. }
  333. m_filterTimer.stop();
  334. m_filterTimer.start();
  335. }
  336. void UnitTestDockWidget::OnStartTestsButton()
  337. {
  338. AZStd::vector<AZ::Uuid> scriptUuids;
  339. m_filter->GetCheckedScriptsUuidsList(scriptUuids);
  340. ClearSearchFilter();
  341. RunTests(scriptUuids);
  342. }
  343. void UnitTestDockWidget::OnCloseResultsButton()
  344. {
  345. m_ui->consoleOutput->hide();
  346. }
  347. void UnitTestDockWidget::OpenScriptInEditor(AZ::Uuid sourceUuid)
  348. {
  349. AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas);
  350. AZ::Data::AssetId sourceAssetId(sourceUuid, 0);
  351. AZ::Outcome<int, AZStd::string> openOutcome = AZ::Failure(AZStd::string());
  352. GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAssetId
  353. , SourceHandle(nullptr, sourceUuid)
  354. , Tracker::ScriptCanvasFileState::UNMODIFIED);
  355. if (!openOutcome)
  356. {
  357. AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data());
  358. }
  359. }
  360. void UnitTestDockWidget::OpenTestResults(AZ::Uuid sourceUuid, AZStd::string_view sourceDisplayName)
  361. {
  362. if (m_filter->HasTestResults(sourceUuid))
  363. {
  364. m_ui->testResultsLabel->setText(QString("Test Results | %1").arg(sourceDisplayName.data()));
  365. m_ui->testResultsOutput->setPlainText(QString(m_filter->GetTestResult(sourceUuid)->m_consoleOutput.c_str()));
  366. m_ui->consoleOutput->show();
  367. }
  368. }
  369. QString ModeToString(ScriptCanvas::ExecutionMode mode)
  370. {
  371. using namespace ScriptCanvas;
  372. switch (mode)
  373. {
  374. case ExecutionMode::Interpreted:
  375. return QString("Interpreted");
  376. case ExecutionMode::Native:
  377. return QString("Native");
  378. default:
  379. return QString("<invalid>");
  380. }
  381. }
  382. bool UnitTestDockWidget::IsModeEnabled(ScriptCanvas::ExecutionMode mode)
  383. {
  384. return GetEnabledCheckBox(mode)->checkState() == Qt::Checked;
  385. }
  386. void UnitTestDockWidget::RunTests(const AZStd::vector<AZ::Uuid>& scriptUuids)
  387. {
  388. AZStd::vector<ScriptCanvas::ExecutionMode> activeModes;
  389. auto executionModes = { ExecutionMode::Interpreted, ExecutionMode::Native };
  390. for (auto mode : executionModes)
  391. {
  392. if (IsModeEnabled(mode))
  393. {
  394. activeModes.push_back(mode);
  395. }
  396. else
  397. {
  398. GetStatusLabel(mode)->setText(ModeToString(mode) + QString(" not running"));
  399. }
  400. }
  401. if (activeModes.empty() || scriptUuids.empty())
  402. {
  403. m_ui->consoleOutput->hide();
  404. m_filter->FlushLatestTestRun();
  405. return;
  406. }
  407. else
  408. {
  409. AZ::SystemTickBus::Handler::BusConnect();
  410. m_ui->label->setText(QString("Starting %1 tests.").arg(scriptUuids.size()));
  411. m_filter->FlushLatestTestRun();
  412. m_filter->TestsStart();
  413. m_ui->consoleOutput->hide();
  414. for (size_t modeIndex = 0; modeIndex < activeModes.size(); ++modeIndex)
  415. {
  416. auto mode = activeModes[modeIndex];
  417. GetStatusLabel(mode)->setText(QString("Starting %1 tests.").arg(scriptUuids.size()));
  418. for (const AZ::Uuid& scriptUuid : scriptUuids)
  419. {
  420. const SourceAssetBrowserEntry* sourceBrowserEntry = SourceAssetBrowserEntry::GetSourceByUuid(scriptUuid);
  421. if (sourceBrowserEntry == nullptr)
  422. {
  423. AZ_Error("Script Canvas", false, "The source asset file with ID: %s was not found", scriptUuid.ToString<AZStd::string>().c_str());
  424. continue;
  425. }
  426. SourceHandle source(nullptr, scriptUuid);
  427. ScriptCanvasEditor::CompleteDescriptionInPlace(source);
  428. RunTestGraph(source, mode);
  429. }
  430. }
  431. }
  432. }
  433. void UnitTestDockWidget::OnTestsComplete()
  434. {
  435. AZ::SystemTickBus::Handler::BusDisconnect();
  436. QString testCompletionString;
  437. const int nativeMode = static_cast<int>(ExecutionMode::Native);
  438. if (m_testMetrics[nativeMode].m_graphsTested > 0)
  439. {
  440. testCompletionString = ModeToString(ExecutionMode::Native);
  441. testCompletionString += QString(": ");
  442. testCompletionString += QString("Attempted %1 test(s) - %2 Succeeded, %3 Failed, %4 Failed to Compile")
  443. .arg(m_testMetrics[nativeMode].m_graphsTested)
  444. .arg(m_testMetrics[nativeMode].m_success)
  445. .arg(m_testMetrics[nativeMode].m_failures)
  446. .arg(m_testMetrics[nativeMode].m_compilationFailures);
  447. GetStatusLabel(ExecutionMode::Native)->setText(testCompletionString);
  448. }
  449. const int interpretedMode = static_cast<int>(ExecutionMode::Interpreted);
  450. if (m_testMetrics[interpretedMode].m_graphsTested > 0)
  451. {
  452. testCompletionString = ModeToString(ExecutionMode::Interpreted);
  453. testCompletionString += QString(": ");
  454. testCompletionString += QString("Attempted %1 test(s) - %2 Succeeded, %3 Failed, %4 Failed to Compile")
  455. .arg(m_testMetrics[interpretedMode].m_graphsTested)
  456. .arg(m_testMetrics[interpretedMode].m_success)
  457. .arg(m_testMetrics[interpretedMode].m_failures)
  458. .arg(m_testMetrics[interpretedMode].m_compilationFailures);
  459. GetStatusLabel(ExecutionMode::Interpreted)->setText(testCompletionString);
  460. }
  461. m_filter->TestsEnd();
  462. m_ui->label->setText(QString("Finished"));
  463. m_testMetrics[nativeMode].Clear();
  464. m_testMetrics[interpretedMode].Clear();
  465. }
  466. void UnitTestDockWidget::RunTestGraph(SourceHandle asset, ScriptCanvas::ExecutionMode mode)
  467. {
  468. Reporter reporter;
  469. UnitTestWidgetNotificationBus::Broadcast(&UnitTestWidgetNotifications::OnTestStart, asset.Id());
  470. ScriptCanvasExecutionBus::BroadcastResult(reporter, &ScriptCanvasExecutionRequests::RunAssetGraph, asset, mode);
  471. UnitTestResult testResult;
  472. UnitTestVerificationBus::BroadcastResult(testResult, &UnitTestVerificationRequests::Verify, reporter);
  473. UnitTestWidgetNotificationBus::Broadcast(&UnitTestWidgetNotifications::OnTestResult, asset.Id(), testResult);
  474. m_pendingTests.Add(asset, mode);
  475. ++m_testMetrics[static_cast<int>(mode)].m_graphsTested;
  476. if (testResult.m_compiled)
  477. {
  478. if (testResult.m_completed)
  479. {
  480. ++m_testMetrics[static_cast<int>(mode)].m_success;
  481. }
  482. else
  483. {
  484. ++m_testMetrics[static_cast<int>(mode)].m_failures;
  485. }
  486. }
  487. else
  488. {
  489. ++m_testMetrics[static_cast<int>(mode)].m_compilationFailures;
  490. }
  491. m_pendingTests.Complete(asset, mode);
  492. }
  493. void UnitTestDockWidget::OnSystemTick()
  494. {
  495. if (m_pendingTests.IsFinished())
  496. {
  497. OnTestsComplete();
  498. }
  499. }
  500. void UnitTestDockWidget::PendingTests::Add(SourceHandle assetId, ExecutionMode mode)
  501. {
  502. m_pendingTests.push_back(AZStd::make_pair(assetId, mode));
  503. }
  504. void UnitTestDockWidget::PendingTests::Complete(SourceHandle assetId, ExecutionMode mode)
  505. {
  506. AZStd::erase_if(m_pendingTests, [assetId, mode](const AZStd::pair<SourceHandle, ExecutionMode>& pending)
  507. {
  508. return (assetId == pending.first && mode == pending.second);
  509. });
  510. }
  511. bool UnitTestDockWidget::PendingTests::IsFinished() const
  512. {
  513. return m_pendingTests.empty();
  514. }
  515. }