From c1555b1d7eca11a68548042c2272ca64af6ff3a6 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 5 May 2017 13:01:06 +0200 Subject: [PATCH] AutoTest: Provide way to access the original test output When running tests the original output is processed and not presented to the user at all. For crashing tests this could mean that output was not able to get processed completely (e.g. when having XML as output and relying on well-formed code) Unhandled output could also lead to incorrect results. This patch adds another view to the results pane which contains the complete output of the last test run. Change-Id: I923496e9c440de4ea68bee55415777ea5c2379c2 Reviewed-by: David Schulz --- src/plugins/autotest/autotest.qrc | 4 ++ src/plugins/autotest/autotesticons.h | 2 + .../autotest/gtest/gtestoutputreader.cpp | 15 +----- .../autotest/gtest/gtestoutputreader.h | 1 - src/plugins/autotest/images/text.png | Bin 0 -> 148 bytes src/plugins/autotest/images/text@2x.png | Bin 0 -> 274 bytes src/plugins/autotest/images/visual.png | Bin 0 -> 213 bytes src/plugins/autotest/images/visual@2x.png | Bin 0 -> 297 bytes src/plugins/autotest/testoutputreader.cpp | 16 ++++-- src/plugins/autotest/testoutputreader.h | 2 + src/plugins/autotest/testresultspane.cpp | 51 +++++++++++++++--- src/plugins/autotest/testresultspane.h | 8 ++- src/plugins/autotest/testrunner.cpp | 5 +- 13 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 src/plugins/autotest/images/text.png create mode 100644 src/plugins/autotest/images/text@2x.png create mode 100644 src/plugins/autotest/images/visual.png create mode 100644 src/plugins/autotest/images/visual@2x.png diff --git a/src/plugins/autotest/autotest.qrc b/src/plugins/autotest/autotest.qrc index 6bd7eac6d79..a62ab49d8fb 100644 --- a/src/plugins/autotest/autotest.qrc +++ b/src/plugins/autotest/autotest.qrc @@ -11,5 +11,9 @@ images/runselected_tickmarks.png images/runselected_tickmarks@2x.png images/data.png + images/text.png + images/text@2x.png + images/visual.png + images/visual@2x.png diff --git a/src/plugins/autotest/autotesticons.h b/src/plugins/autotest/autotesticons.h index cb557b5390e..b278509dbbc 100644 --- a/src/plugins/autotest/autotesticons.h +++ b/src/plugins/autotest/autotesticons.h @@ -71,6 +71,8 @@ const Utils::Icon RESULT_MESSAGEWARN({ const Utils::Icon RESULT_MESSAGEFATAL({ {":/utils/images/filledcircle.png", Utils::Theme::OutputPanes_TestFatalTextColor}}, Utils::Icon::Tint); +const Utils::Icon VISUAL_DISPLAY({{":/images/visual.png", Utils::Theme::IconsBaseColor}}); +const Utils::Icon TEXT_DISPLAY({{":/images/text.png", Utils::Theme::IconsBaseColor}}); } // namespace Icons } // namespace Autotest diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp index 2eba52e7537..96382f5f896 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.cpp +++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp @@ -56,20 +56,7 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine) static QRegExp errorLocation("^(.*)\\((\\d+)\\): error:.*$"); static QRegExp iterations("^Repeating all tests \\(iteration (\\d+)\\) \\. \\. \\.$"); - QByteArray read = outputLine; - if (!m_unprocessed.isEmpty()) { - read = m_unprocessed + read; - m_unprocessed.clear(); - } - if (!read.endsWith('\n')) { - m_unprocessed = read; - return; - } - read.chop(1); // remove the newline from the output - if (read.endsWith('\r')) - read.chop(1); - - const QString line = QString::fromLatin1(read); + const QString line = QString::fromLatin1(outputLine); if (line.trimmed().isEmpty()) return; diff --git a/src/plugins/autotest/gtest/gtestoutputreader.h b/src/plugins/autotest/gtest/gtestoutputreader.h index 42031cd4d67..0ed2bf878cb 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.h +++ b/src/plugins/autotest/gtest/gtestoutputreader.h @@ -50,7 +50,6 @@ private: QString m_currentTestName; QString m_currentTestSet; QString m_description; - QByteArray m_unprocessed; int m_iteration = 1; }; diff --git a/src/plugins/autotest/images/text.png b/src/plugins/autotest/images/text.png new file mode 100644 index 0000000000000000000000000000000000000000..b43b92e09a1e94203d8c2944442905bf5559e4de GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4h9AW2CEqh_A)RqM0>h8hDcma{?X4SVZgG^ z>x_$Nh35Gi?W>+H)N;05C8=LB(bb`CpK0oeKix^Et&7{TL>l?Sc&46UdVeNh>z)hF zrXqKvRvbQ8y{p0Dh4+lh*Ebq8G+Z!cYud-k5E*q{(`w#FdysXWu6{1-oD!M9Y+?XWn+A7aSe-!!?&f%S5s zw#5nVDc^rK1|PJOTd?Op|D3)%XBemS|LVOwTRWoh)64oowkt^i4$uB5TW_*zxWwbT zWASdbDKg8Pe$E#==fY(D&@<1@r&*hsD}u*&i}nMxuEkm!tt!9Ia%ey2RQ5EMytCN< bnlb~!w%l0zzvXUSAkTWb`njxgN@xNAMNVp; literal 0 HcmV?d00001 diff --git a/src/plugins/autotest/images/visual.png b/src/plugins/autotest/images/visual.png new file mode 100644 index 0000000000000000000000000000000000000000..092367618c08b7ca4651c35c9cc59cdf80db4dcf GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4h9AW2CEqh_A)Rq%<*(_43P*={_%hRwk=z> zy!cnIk?`Yx{9Hy3GeyoHCvNSwn&T$)L;gp`-&a>xU$1HBuGreaV7l?Xi%`Jiz|i1* z?H4}%s6WuW+u?(Rr$XQK`Sast6$@&W)WyZ8YdJmm&p%n!o>-pEFp#=aaD0ga7{Ok@fh!&JONPoZZZg7ZPLkMVu&**>B#+6*s@J@pgo0j^9)9 zMyAL$ToODF7wYx99-Mm4&wdYAgF^Fcd9IWV+7+9m+0IRpiHyIKyYRq2D>GKv;)fHD z_L{C}3~bQXi<7h15GFF8N#Vzeg=&YFE?{HPTE0>1fP7>D>+w~I31VTarNbZm xGK=@^XlRHwPP2Fv%D}QzX+zJNu2@Dk1_o)HM>Xvm`rAQa;OXk;vd$@?2>`cgY{LKm literal 0 HcmV?d00001 diff --git a/src/plugins/autotest/testoutputreader.cpp b/src/plugins/autotest/testoutputreader.cpp index b7cf59f1d58..fea9237717d 100644 --- a/src/plugins/autotest/testoutputreader.cpp +++ b/src/plugins/autotest/testoutputreader.cpp @@ -25,6 +25,7 @@ #include "testoutputreader.h" #include "testresult.h" +#include "testresultspane.h" #include #include @@ -41,12 +42,21 @@ TestOutputReader::TestOutputReader(const QFutureInterface &future if (m_testApplication) { connect(m_testApplication, &QProcess::readyRead, this, [this] () { - while (m_testApplication->canReadLine()) - processOutput(m_testApplication->readLine()); + while (m_testApplication->canReadLine()) { + QByteArray output = m_testApplication->readLine(); + output.chop(1); // remove the newline from the output + if (output.endsWith('\r')) + output.chop(1); + + emit newOutputAvailable(output); + processOutput(output); + } }); connect(m_testApplication, &QProcess::readyReadStandardError, this, [this] () { - processStdError(m_testApplication->readAllStandardError()); + const QByteArray output = m_testApplication->readAllStandardError(); + emit newOutputAvailable(output); + processStdError(output); }); } } diff --git a/src/plugins/autotest/testoutputreader.h b/src/plugins/autotest/testoutputreader.h index 237f23c6aca..ff04d8f4ce6 100644 --- a/src/plugins/autotest/testoutputreader.h +++ b/src/plugins/autotest/testoutputreader.h @@ -45,6 +45,8 @@ public: virtual void processOutput(const QByteArray &outputLine) = 0; virtual void processStdError(const QByteArray &output); +signals: + void newOutputAvailable(const QByteArray &output); protected: QFutureInterface m_futureInterface; QProcess *m_testApplication; // not owned diff --git a/src/plugins/autotest/testresultspane.cpp b/src/plugins/autotest/testresultspane.cpp index 48402bbb05a..b4fbab97859 100644 --- a/src/plugins/autotest/testresultspane.cpp +++ b/src/plugins/autotest/testresultspane.cpp @@ -33,16 +33,15 @@ #include "testtreemodel.h" #include "testcodeparser.h" +#include #include #include +#include #include #include #include - #include - #include - #include #include @@ -54,6 +53,7 @@ #include #include #include +#include #include #include @@ -79,11 +79,13 @@ TestResultsPane::TestResultsPane(QObject *parent) : Core::IOutputPane(parent), m_context(new Core::IContext(this)) { - m_outputWidget = new QWidget; + m_outputWidget = new QStackedWidget; + QWidget *visualOutputWidget = new QWidget; + m_outputWidget->addWidget(visualOutputWidget); QVBoxLayout *outputLayout = new QVBoxLayout; outputLayout->setMargin(0); outputLayout->setSpacing(0); - m_outputWidget->setLayout(outputLayout); + visualOutputWidget->setLayout(outputLayout); QPalette pal; pal.setColor(QPalette::Window, @@ -103,7 +105,7 @@ TestResultsPane::TestResultsPane(QObject *parent) : outputLayout->addWidget(m_summaryWidget); - m_treeView = new ResultsTreeView(m_outputWidget); + m_treeView = new ResultsTreeView(visualOutputWidget); m_treeView->setHeaderHidden(true); m_treeView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); @@ -119,6 +121,19 @@ TestResultsPane::TestResultsPane(QObject *parent) : outputLayout->addWidget(Core::ItemViewFind::createSearchableWrapper(m_treeView)); + m_textOutput = new QPlainTextEdit; + m_textOutput->setPalette(pal); + QFont font("monospace"); + font.setStyleHint(QFont::TypeWriter); + m_textOutput->setFont(font); + m_textOutput->setWordWrapMode(QTextOption::WordWrap); + m_textOutput->setReadOnly(true); + m_outputWidget->addWidget(m_textOutput); + + auto agg = new Aggregation::Aggregate; + agg->add(m_textOutput); + agg->add(new Core::BaseTextFind(m_textOutput)); + createToolButtons(); connect(m_treeView, &Utils::TreeView::activated, this, &TestResultsPane::onItemActivated); @@ -188,6 +203,11 @@ void TestResultsPane::createToolButtons() initializeFilterMenu(); connect(m_filterMenu, &QMenu::triggered, this, &TestResultsPane::filterMenuTriggered); m_filterButton->setMenu(m_filterMenu); + m_outputToggleButton = new QToolButton(m_treeView); + m_outputToggleButton->setIcon(Icons::TEXT_DISPLAY.icon()); + m_outputToggleButton->setToolTip(tr("Switch Between Visual and Text Display")); + m_outputToggleButton->setEnabled(true); + connect(m_outputToggleButton, &QToolButton::clicked, this, &TestResultsPane::toggleOutputStyle); } static TestResultsPane *s_instance = nullptr; @@ -202,6 +222,8 @@ TestResultsPane *TestResultsPane::instance() TestResultsPane::~TestResultsPane() { delete m_treeView; + if (!m_outputWidget->parent()) + delete m_outputWidget; s_instance = nullptr; } @@ -217,6 +239,11 @@ void TestResultsPane::addTestResult(const TestResultPtr &result) navigateStateChanged(); } +void TestResultsPane::addOutput(const QByteArray &output) +{ + m_textOutput->appendPlainText(QString::fromLatin1(output)); +} + QWidget *TestResultsPane::outputWidget(QWidget *parent) { if (m_outputWidget) { @@ -229,7 +256,8 @@ QWidget *TestResultsPane::outputWidget(QWidget *parent) QList TestResultsPane::toolBarWidgets() const { - return {m_expandCollapse, m_runAll, m_runSelected, m_stopTestRun, m_filterButton}; + return {m_expandCollapse, m_runAll, m_runSelected, m_stopTestRun, m_outputToggleButton, + m_filterButton}; } QString TestResultsPane::displayName() const @@ -251,6 +279,7 @@ void TestResultsPane::clearContents() m_autoScroll = AutotestPlugin::instance()->settings()->autoScroll; connect(m_treeView->verticalScrollBar(), &QScrollBar::rangeChanged, this, &TestResultsPane::onScrollBarRangeChanged, Qt::UniqueConnection); + m_textOutput->clear(); } void TestResultsPane::visibilityChanged(bool visible) @@ -574,6 +603,14 @@ void TestResultsPane::onSaveWholeTriggered() } } +void TestResultsPane::toggleOutputStyle() +{ + const bool displayText = m_outputWidget->currentIndex() == 0; + m_outputWidget->setCurrentIndex(displayText ? 1 : 0); + m_outputToggleButton->setIcon(displayText ? Icons::VISUAL_DISPLAY.icon() + : Icons::TEXT_DISPLAY.icon()); +} + // helper for onCopyWholeTriggered() and onSaveWholeTriggered() QString TestResultsPane::getWholeOutput(const QModelIndex &parent) { diff --git a/src/plugins/autotest/testresultspane.h b/src/plugins/autotest/testresultspane.h index 9c5af8f50cf..6b837055672 100644 --- a/src/plugins/autotest/testresultspane.h +++ b/src/plugins/autotest/testresultspane.h @@ -38,6 +38,8 @@ class QKeyEvent; class QLabel; class QModelIndex; class QMenu; +class QPlainTextEdit; +class QStackedWidget; class QToolButton; QT_END_NAMESPACE @@ -88,6 +90,7 @@ public: void goToPrev() override; void addTestResult(const TestResultPtr &result); + void addOutput(const QByteArray &output); private: explicit TestResultsPane(QObject *parent = 0); @@ -109,9 +112,10 @@ private: void onCopyItemTriggered(const QModelIndex &idx); void onCopyWholeTriggered(); void onSaveWholeTriggered(); + void toggleOutputStyle(); QString getWholeOutput(const QModelIndex &parent = QModelIndex()); - QWidget *m_outputWidget; + QStackedWidget *m_outputWidget; QFrame *m_summaryWidget; QLabel *m_summaryLabel; ResultsTreeView *m_treeView; @@ -123,6 +127,8 @@ private: QToolButton *m_runSelected; QToolButton *m_stopTestRun; QToolButton *m_filterButton; + QToolButton *m_outputToggleButton; + QPlainTextEdit *m_textOutput; QMenu *m_filterMenu; bool m_wasVisibleBefore = false; bool m_autoScroll = false; diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index ea83e1728c1..846a3f81220 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -157,6 +157,8 @@ static void performTestRun(QFutureInterface &futureInterface, QScopedPointer outputReader; outputReader.reset(testConfiguration->outputReader(futureInterface, &testProcess)); QTC_ASSERT(outputReader, continue); + TestRunner::connect(outputReader.data(), &TestOutputReader::newOutputAvailable, + TestResultsPane::instance(), &TestResultsPane::addOutput); if (futureInterface.isCanceled()) break; @@ -364,7 +366,8 @@ void TestRunner::debugTests() if (useOutputProcessor) { TestOutputReader *outputreader = config->outputReader(*futureInterface, 0); - + connect(outputreader, &TestOutputReader::newOutputAvailable, + TestResultsPane::instance(), &TestResultsPane::addOutput); connect(runControl, &ProjectExplorer::RunControl::appendMessageRequested, this, [this, outputreader] (ProjectExplorer::RunControl *, const QString &msg, Utils::OutputFormat format) {