From b81f69d97a7aabaf2f6dc50e573dad7cb065fd45 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 23 Feb 2018 18:40:16 -0800 Subject: [PATCH 01/24] WIP - recursive tests. --- tools/auto-tester/src/Test.cpp | 13 +++++++------ tools/auto-tester/src/Test.h | 1 + tools/auto-tester/src/ui/AutoTester.cpp | 4 ++++ tools/auto-tester/src/ui/AutoTester.h | 1 + tools/auto-tester/src/ui/AutoTester.ui | 21 +++++++++++++++++---- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 816eac7fbd..931a940760 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -319,11 +319,12 @@ void Test::createRecursiveScript() { return; } - QFile allTestsFilename(topLevelDirectory + "/" + "allTests.js"); + const QString recursiveTestsFilename("testRecursive.js"); + QFile allTestsFilename(topLevelDirectory + "/" + recursiveTestsFilename); if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { messageBox.critical(0, "Internal Error", - "Failed to create \"allTests.js\" in directory \"" + topLevelDirectory + "\"" + "Failed to create \"" + recursiveTestsFilename + "\" in directory \"" + topLevelDirectory + "\"" ); exit(-1); @@ -335,9 +336,6 @@ void Test::createRecursiveScript() { textStream << "var autoTester = Script.require(\"https://github.com/highfidelity/hifi_tests/blob/master/tests/utils/autoTester.js?raw=true\");" << endl; textStream << "autoTester.enableRecursive();" << endl << endl; - // The main will call each test after the previous test is completed - // This is implemented with an interval timer that periodically tests if a - // running test has increment a testNumber variable that it received as an input. QVector testPathnames; // First test if top-level folder has a test.js file @@ -371,7 +369,7 @@ void Test::createRecursiveScript() { } if (testPathnames.length() <= 0) { - messageBox.information(0, "Failure", "No \"test.js\" files found"); + messageBox.information(0, "Failure", "No \"" + TEST_FILENAME + "\" files found"); allTestsFilename.close(); return; } @@ -383,6 +381,9 @@ void Test::createRecursiveScript() { messageBox.information(0, "Success", "Script has been created"); } +void Test::createRecursiveScriptsRecursively() { +} + void Test::createTest() { // Rename files sequentially, as ExpectedResult_1.jpeg, ExpectedResult_2.jpg and so on // Any existing expected result images will be deleted diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 3177df4d47..3da5badb6d 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -26,6 +26,7 @@ public: void evaluateTests(bool interactiveMode, QProgressBar* progressBar); void evaluateTestsRecursively(bool interactiveMode, QProgressBar* progressBar); void createRecursiveScript(); + void createRecursiveScriptsRecursively(); void createTest(); void deleteOldSnapshots(); diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 2834ff81e0..18eef13e6e 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -30,6 +30,10 @@ void AutoTester::on_createRecursiveScriptButton_clicked() { test.createRecursiveScript(); } +void AutoTester::on_createRecursiveScriptsRecursivelyButton_clicked() { + test.createRecursiveScriptsRecursively(); +} + void AutoTester::on_createTestButton_clicked() { test.createTest(); } diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index 35f609a89d..d25969589b 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -24,6 +24,7 @@ private slots: void on_evaluateTestsButton_clicked(); void on_evaluateTestsRecursivelyButton_clicked(); void on_createRecursiveScriptButton_clicked(); + void on_createRecursiveScriptsRecursivelyButton_clicked(); void on_createTestButton_clicked(); void on_deleteOldSnapshotsButton_clicked(); void on_closeButton_clicked(); diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index d06255acf6..0d142ec43e 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -17,7 +17,7 @@ - 190 + 20 300 220 40 @@ -31,7 +31,7 @@ 360 - 130 + 210 220 40 @@ -112,7 +112,7 @@ 360 - 240 + 270 220 40 @@ -121,6 +121,19 @@ Delete Old Snapshots + + + + 360 + 140 + 220 + 40 + + + + Create Recursive Scripts Recursively + + @@ -145,4 +158,4 @@ - \ No newline at end of file + From 2a1c22e7a5eb53548d0f901cfb3e9143e1c6c7ef Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Mar 2018 11:10:45 -0800 Subject: [PATCH 02/24] "Create Test" copies (and renames) images from snapshot folder to the corresponding test folder. --- tools/auto-tester/src/Test.cpp | 68 ++++++++++++++++++++++------------ tools/auto-tester/src/Test.h | 4 +- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 931a940760..357fc7b296 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -17,8 +17,6 @@ #include Test::Test() { - snapshotFilenameFormat = QRegularExpression("hifi-snap-by-.*-on-\\d\\d\\d\\d-\\d\\d-\\d\\d_\\d\\d-\\d\\d-\\d\\d.jpg"); - expectedImageFilenameFormat = QRegularExpression("ExpectedImage_\\d+.jpg"); mismatchWindow.setModal(true); @@ -387,16 +385,16 @@ void Test::createRecursiveScriptsRecursively() { void Test::createTest() { // Rename files sequentially, as ExpectedResult_1.jpeg, ExpectedResult_2.jpg and so on // Any existing expected result images will be deleted - QString pathToImageDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); - if (pathToImageDirectory == "") { + QString imageSourceDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); + if (imageSourceDirectory == "") { return; } - QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(pathToImageDirectory); + QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(imageSourceDirectory); int i = 1; foreach (QString currentFilename, sortedImageFilenames) { - QString fullCurrentFilename = pathToImageDirectory + "/" + currentFilename; + QString fullCurrentFilename = imageSourceDirectory + "/" + currentFilename; if (isInExpectedImageFilenameFormat(currentFilename)) { if (!QFile::remove(fullCurrentFilename)) { messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); @@ -408,22 +406,15 @@ void Test::createTest() { messageBox.critical(0, "Error", "More than 100,000 images not supported"); exit(-1); } - QString newFilename = "ExpectedImage_" + QString::number(i-1).rightJustified(5, '0') + ".jpg"; - QString fullNewFileName = pathToImageDirectory + "/" + newFilename; + QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".jpg"; + QString imageDestinationDirectory = getImageDestinationDirectory(currentFilename); + QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; - if (!imageDirectory.rename(fullCurrentFilename, newFilename)) { - if (!QFile::exists(fullCurrentFilename)) { - messageBox.critical(0, "Error", "Could not rename file: " + fullCurrentFilename + " to: " + newFilename + "\n" - + fullCurrentFilename + " not found" - + "\nTest creation aborted" - ); - exit(-1); - } else { - messageBox.critical(0, "Error", "Could not rename file: " + fullCurrentFilename + " to: " + newFilename + "\n" - + "unknown error" + "\nTest creation aborted" - ); - exit(-1); - } + try { + QFile::copy(fullCurrentFilename, fullNewFileName); + } catch (...) { + messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); + exit(-1); } ++i; } @@ -475,9 +466,40 @@ QStringList Test::createListOfAllJPEGimagesInDirectory(QString pathToImageDirect return imageDirectory.entryList(nameFilters, QDir::Files, QDir::Name); } -// Use regular expressions to check if files are in specific format +// Snapshots are files in the following format: +// Filename contains no periods (excluding period before exception +// Filename (i.e. without extension) contains _tests_ (this is based on all test scripts being within the tests folder +// Last 5 characters in filename are digits +// Extension is jpg bool Test::isInSnapshotFilenameFormat(QString filename) { - return (snapshotFilenameFormat.match(filename).hasMatch()); + QStringList filenameParts = filename.split("."); + + bool filnameHasNoPeriods = (filenameParts.size() == 2); + bool contains_tests = filenameParts[0].contains("_tests_"); + + bool last5CharactersAreDigits; + filenameParts[0].right(5).toInt(&last5CharactersAreDigits, 10); + + bool extensionIsJPG = filenameParts[1] == "jpg"; + + return (filnameHasNoPeriods && contains_tests && last5CharactersAreDigits && extensionIsJPG); +} + +// For a file named "D_GitHub_hifi-tests_tests_content_entity_zone_create_0.jpg", the test directory is +// D:/GitHub/hifi-tests/tests/content/entity/zone/create +// This method assumes the filename is in the correct format +// The final part of the filename is the image number. This is checked for sanity +QString Test::getImageDestinationDirectory(QString filename) { + QString filenameWithoutExtension = filename.split(".")[0]; + QStringList filenameParts = filenameWithoutExtension.split("_"); + + QString result = filenameParts[0] + ":"; + + for (int i = 1; i < filenameParts.length() - 1; ++i) { + result += "/" + filenameParts[i]; + } + + return result; } bool Test::isInExpectedImageFilenameFormat(QString filename) { diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 3da5badb6d..55fb7229d1 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -46,6 +46,8 @@ public: bool isAValidDirectory(QString pathname); + QString getImageDestinationDirectory(QString filename); + private: const QString TEST_FILENAME { "test.js" }; const QString TEST_RESULTS_FOLDER { "TestResults" }; @@ -55,14 +57,12 @@ private: QDir imageDirectory; - QRegularExpression snapshotFilenameFormat; QRegularExpression expectedImageFilenameFormat; MismatchWindow mismatchWindow; ImageComparer imageComparer; - QString testResultsFolderPath { "" }; int index { 1 }; }; From 5bb4023fb5d62869923a2a0f9a1b47383d05c3df Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 1 Mar 2018 19:23:17 -0800 Subject: [PATCH 03/24] First version - can download fixed URL to fixed location. --- tools/auto-tester/CMakeLists.txt | 2 +- tools/auto-tester/src/Test.cpp | 63 +++++++++++++------------ tools/auto-tester/src/Test.h | 7 ++- tools/auto-tester/src/main.cpp | 6 ++- tools/auto-tester/src/ui/AutoTester.cpp | 35 ++++++++++---- tools/auto-tester/src/ui/AutoTester.h | 8 +++- 6 files changed, 76 insertions(+), 45 deletions(-) diff --git a/tools/auto-tester/CMakeLists.txt b/tools/auto-tester/CMakeLists.txt index a875f5676a..a2589bb760 100644 --- a/tools/auto-tester/CMakeLists.txt +++ b/tools/auto-tester/CMakeLists.txt @@ -5,7 +5,7 @@ project(${TARGET_NAME}) SET (CMAKE_AUTOUIC ON) SET (CMAKE_AUTOMOC ON) -setup_hifi_project (Core Widgets) +setup_hifi_project (Core Widgets Network) link_hifi_libraries () # FIX: Qt was built with -reduce-relocations diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 357fc7b296..458ce0838b 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -16,8 +16,13 @@ #include #include +#include "ui/AutoTester.h" +extern AutoTester* autoTester; + Test::Test() { - expectedImageFilenameFormat = QRegularExpression("ExpectedImage_\\d+.jpg"); + QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + EXPECTED_IMAGE_TYPE); + + expectedImageFilenameFormat = QRegularExpression(regex); mismatchWindow.setModal(true); } @@ -178,49 +183,45 @@ void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure te void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { // Get list of JPEG images in folder, sorted by name - QString pathToImageDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); - if (pathToImageDirectory == "") { + QString pathToTestResultsDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); + if (pathToTestResultsDirectory == "") { return; } // Leave if test results folder could not be created - if (!createTestResultsFolderPathIfNeeded(pathToImageDirectory)) { + if (!createTestResultsFolderPathIfNeeded(pathToTestResultsDirectory)) { return; } - QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(pathToImageDirectory); - - // Separate images into two lists. The first is the expected images, the second is the test results + // Create two lists. The first is the test results, the second is the expected images // Images that are in the wrong format are ignored. + + QStringList sortedTestResultsFilenames = createListOfAllJPEGimagesInDirectory(pathToTestResultsDirectory); QStringList expectedImages; QStringList resultImages; - foreach(QString currentFilename, sortedImageFilenames) { - QString fullCurrentFilename = pathToImageDirectory + "/" + currentFilename; - if (isInExpectedImageFilenameFormat(currentFilename)) { - expectedImages << fullCurrentFilename; - } else if (isInSnapshotFilenameFormat(currentFilename)) { + foreach(QString currentFilename, sortedTestResultsFilenames) { + QString fullCurrentFilename = pathToTestResultsDirectory + "/" + currentFilename; + if (isInSnapshotFilenameFormat(currentFilename)) { resultImages << fullCurrentFilename; + + QString expectedImageDirectory = getExpectedImageDestinationDirectory(currentFilename); + + // extract the digits at the end of the filename (exluding the file extension) + QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); + + QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + EXPECTED_IMAGE_TYPE; + expectedImages << (expectedImageDirectory + "/" + expectedImageFilename); } } - // The number of images in each list should be identical - if (expectedImages.length() != resultImages.length()) { - messageBox.critical(0, - "Test failed", - "Found " + QString::number(resultImages.length()) + " images in directory" + - "\nExpected to find " + QString::number(expectedImages.length()) + " images" - ); + autoTester->downloadImage(QUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png")); + ////bool success = compareImageLists(expectedImages, resultImages, pathToImageDirectory, interactiveMode, progressBar); - exit(-1); - } - - bool success = compareImageLists(expectedImages, resultImages, pathToImageDirectory, interactiveMode, progressBar); - - if (success) { - messageBox.information(0, "Success", "All images are as expected"); - } else { - messageBox.information(0, "Failure", "One or more images are not as expected"); - } + ////if (success) { + //// messageBox.information(0, "Success", "All images are as expected"); + ////} else { + //// messageBox.information(0, "Failure", "One or more images are not as expected"); + ////} zipAndDeleteTestResultsFolder(); } @@ -407,7 +408,7 @@ void Test::createTest() { exit(-1); } QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".jpg"; - QString imageDestinationDirectory = getImageDestinationDirectory(currentFilename); + QString imageDestinationDirectory = getExpectedImageDestinationDirectory(currentFilename); QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; try { @@ -489,7 +490,7 @@ bool Test::isInSnapshotFilenameFormat(QString filename) { // D:/GitHub/hifi-tests/tests/content/entity/zone/create // This method assumes the filename is in the correct format // The final part of the filename is the image number. This is checked for sanity -QString Test::getImageDestinationDirectory(QString filename) { +QString Test::getExpectedImageDestinationDirectory(QString filename) { QString filenameWithoutExtension = filename.split(".")[0]; QStringList filenameParts = filenameWithoutExtension.split("_"); diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 55fb7229d1..7168a8ef69 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -46,7 +46,7 @@ public: bool isAValidDirectory(QString pathname); - QString getImageDestinationDirectory(QString filename); + QString getExpectedImageDestinationDirectory(QString filename); private: const QString TEST_FILENAME { "test.js" }; @@ -65,6 +65,11 @@ private: QString testResultsFolderPath { "" }; int index { 1 }; + + // Expected images are in the format ExpectedImage_dddd.jpg (d == decimal digit) + const int NUM_DIGITS { 5 }; + const QString EXPECTED_IMAGE_PREFIX { "ExpectedImage_" }; + const QString EXPECTED_IMAGE_TYPE { ".jpg" }; }; #endif // hifi_test_h \ No newline at end of file diff --git a/tools/auto-tester/src/main.cpp b/tools/auto-tester/src/main.cpp index 6e5e06b732..cd0ce22b13 100644 --- a/tools/auto-tester/src/main.cpp +++ b/tools/auto-tester/src/main.cpp @@ -10,11 +10,13 @@ #include #include "ui/AutoTester.h" +AutoTester* autoTester; + int main(int argc, char *argv[]) { QApplication application(argc, argv); - AutoTester autoTester; - autoTester.show(); + autoTester = new AutoTester(); + autoTester->show(); return application.exec(); } diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 18eef13e6e..8d0b0dc6a5 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -12,36 +12,53 @@ AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); - ui.checkBoxInteractiveMode->setChecked(true); - ui.progressBar->setVisible(false); + + test = new Test(); } void AutoTester::on_evaluateTestsButton_clicked() { - test.evaluateTests(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); + ////QUrl imageUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png"); + ////downloader = new Downloader(imageUrl, this); + ////connect(downloader, SIGNAL (downloaded()), this, SLOT (saveImage())); + test->evaluateTests(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); } void AutoTester::on_evaluateTestsRecursivelyButton_clicked() { - test.evaluateTestsRecursively(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); + test->evaluateTestsRecursively(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); } void AutoTester::on_createRecursiveScriptButton_clicked() { - test.createRecursiveScript(); + test->createRecursiveScript(); } void AutoTester::on_createRecursiveScriptsRecursivelyButton_clicked() { - test.createRecursiveScriptsRecursively(); + test->createRecursiveScriptsRecursively(); } void AutoTester::on_createTestButton_clicked() { - test.createTest(); + test->createTest(); } void AutoTester::on_deleteOldSnapshotsButton_clicked() { - test.deleteOldSnapshots(); + test->deleteOldSnapshots(); } void AutoTester::on_closeButton_clicked() { exit(0); -} \ No newline at end of file +} + +void AutoTester::downloadImage(QUrl url) { + downloader = new Downloader(url, this); + + connect(downloader, SIGNAL (downloaded()), this, SLOT (saveImage())); +} + +void AutoTester::saveImage() { + QPixmap image; + image.loadFromData(downloader->downloadedData()); + int er = image.width(); + int df = image.height(); + image.save("D:/Dicom/lll.png"); +} diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index d25969589b..2f6a9bca1e 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -12,6 +12,8 @@ #include #include "ui_AutoTester.h" + +#include "../Downloader.h" #include "../Test.h" class AutoTester : public QMainWindow { @@ -19,6 +21,7 @@ class AutoTester : public QMainWindow { public: AutoTester(QWidget *parent = Q_NULLPTR); + void downloadImage(QUrl url); private slots: void on_evaluateTestsButton_clicked(); @@ -29,10 +32,13 @@ private slots: void on_deleteOldSnapshotsButton_clicked(); void on_closeButton_clicked(); + void saveImage(); + private: Ui::AutoTesterClass ui; - Test test; + Test* test; + Downloader* downloader; }; #endif // hifi_AutoTester_h \ No newline at end of file From 07267f9fe6bd8618b4cf1e6d20b98677693a1946 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Mar 2018 09:13:07 -0800 Subject: [PATCH 04/24] WIP. --- tools/auto-tester/src/Downloader.cpp | 32 +++++++++++++++++ tools/auto-tester/src/Downloader.h | 48 +++++++++++++++++++++++++ tools/auto-tester/src/Test.cpp | 4 ++- tools/auto-tester/src/ui/AutoTester.cpp | 2 +- 4 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 tools/auto-tester/src/Downloader.cpp create mode 100644 tools/auto-tester/src/Downloader.h diff --git a/tools/auto-tester/src/Downloader.cpp b/tools/auto-tester/src/Downloader.cpp new file mode 100644 index 0000000000..030aa95a19 --- /dev/null +++ b/tools/auto-tester/src/Downloader.cpp @@ -0,0 +1,32 @@ +// +// Downloader.cpp +// +// Created by Nissim Hadar on 1 Mar 2018. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "Downloader.h" + +Downloader::Downloader(QUrl imageUrl, QObject *parent) : QObject(parent) { + connect( + &_networkAccessManager, SIGNAL (finished(QNetworkReply*)), + this, SLOT (fileDownloaded(QNetworkReply*)) + ); + + QNetworkRequest request(imageUrl); + _networkAccessManager.get(request); +} + +void Downloader::fileDownloaded(QNetworkReply* reply) { + _downloadedData = reply->readAll(); + + //emit a signal + reply->deleteLater(); + emit downloaded(); +} + +QByteArray Downloader::downloadedData() const { + return _downloadedData; +} \ No newline at end of file diff --git a/tools/auto-tester/src/Downloader.h b/tools/auto-tester/src/Downloader.h new file mode 100644 index 0000000000..b0ad58fac5 --- /dev/null +++ b/tools/auto-tester/src/Downloader.h @@ -0,0 +1,48 @@ +// +// Downloader.h +// +// Created by Nissim Hadar on 1 Mar 2018. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_downloader_h +#define hifi_downloader_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +class Downloader : public QObject { +Q_OBJECT +public: + explicit Downloader(QUrl imageUrl, QObject *parent = 0); + + QByteArray downloadedData() const; + +signals: + void downloaded(); + + private slots: + void fileDownloaded(QNetworkReply* pReply); + +private: + QNetworkAccessManager _networkAccessManager; + QByteArray _downloadedData; +}; + +#endif // hifi_downloader_h \ No newline at end of file diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 458ce0838b..ee792c0ea4 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -214,7 +214,9 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { } } - autoTester->downloadImage(QUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png")); + ////autoTester->downloadImage(QUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png")); + ////autoTester->downloadImage(QUrl("https://github.com/NissimHadar/hifi_tests/blob/addRecursionToAutotester/tests/content/entity/zone/ambientLightInheritance/ExpectedImage_00000.jpg?raw=true")); + autoTester->downloadImage(QUrl("https://hifi-content.s3.amazonaws.com/nissim/autoTester/resources/ColourBox.jpg")); ////bool success = compareImageLists(expectedImages, resultImages, pathToImageDirectory, interactiveMode, progressBar); ////if (success) { diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 8d0b0dc6a5..5a666aa5eb 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -60,5 +60,5 @@ void AutoTester::saveImage() { image.loadFromData(downloader->downloadedData()); int er = image.width(); int df = image.height(); - image.save("D:/Dicom/lll.png"); + image.save("D:/Dicom/lll.jpg"); } From d29adcd000dd5dffc33849c9763008a1f62e78d1 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Mar 2018 16:08:14 -0800 Subject: [PATCH 05/24] Can download multiple images from GitHub. --- tools/auto-tester/src/Test.cpp | 54 +++++++++++++++++++------ tools/auto-tester/src/Test.h | 1 + tools/auto-tester/src/ui/AutoTester.cpp | 36 +++++++++++++---- tools/auto-tester/src/ui/AutoTester.h | 12 +++++- 4 files changed, 81 insertions(+), 22 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index ee792c0ea4..ac10d1ab33 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -188,36 +188,43 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { return; } - // Leave if test results folder could not be created + // Quit if test results folder could not be created if (!createTestResultsFolderPathIfNeeded(pathToTestResultsDirectory)) { return; } // Create two lists. The first is the test results, the second is the expected images + // The expected images are represented as a URL to enabel download from GitHub // Images that are in the wrong format are ignored. QStringList sortedTestResultsFilenames = createListOfAllJPEGimagesInDirectory(pathToTestResultsDirectory); QStringList expectedImages; QStringList resultImages; + + const QString URLPrefix("https://raw.githubusercontent.com"); + const QString githubUser("NissimHadar"); + const QString testsRepo("hifi_tests"); + const QString branch("addRecursionToAutotester"); + foreach(QString currentFilename, sortedTestResultsFilenames) { QString fullCurrentFilename = pathToTestResultsDirectory + "/" + currentFilename; if (isInSnapshotFilenameFormat(currentFilename)) { resultImages << fullCurrentFilename; - QString expectedImageDirectory = getExpectedImageDestinationDirectory(currentFilename); + QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); // extract the digits at the end of the filename (exluding the file extension) QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); - QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + EXPECTED_IMAGE_TYPE; - expectedImages << (expectedImageDirectory + "/" + expectedImageFilename); + + QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + expectedImagePartialSourceDirectory + "/" + expectedImageFilename); + expectedImages << imageURLString; } } - ////autoTester->downloadImage(QUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png")); - ////autoTester->downloadImage(QUrl("https://github.com/NissimHadar/hifi_tests/blob/addRecursionToAutotester/tests/content/entity/zone/ambientLightInheritance/ExpectedImage_00000.jpg?raw=true")); - autoTester->downloadImage(QUrl("https://hifi-content.s3.amazonaws.com/nissim/autoTester/resources/ColourBox.jpg")); - ////bool success = compareImageLists(expectedImages, resultImages, pathToImageDirectory, interactiveMode, progressBar); + //autoTester->downloadImage(QUrl("https://raw.githubusercontent.com/NissimHadar/hifi_tests/addRecursionToAutotester/tests/content/entity/zone/ambientLightInheritance/ExpectedImage_00000.jpg")); + + autoTester->downloadImages(expectedImages); ////if (success) { //// messageBox.information(0, "Success", "All images are as expected"); @@ -386,7 +393,7 @@ void Test::createRecursiveScriptsRecursively() { } void Test::createTest() { - // Rename files sequentially, as ExpectedResult_1.jpeg, ExpectedResult_2.jpg and so on + // Rename files sequentially, as ExpectedResult_00000.jpeg, ExpectedResult_00001.jpg and so on // Any existing expected result images will be deleted QString imageSourceDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); if (imageSourceDirectory == "") { @@ -404,9 +411,9 @@ void Test::createTest() { exit(-1); } } else if (isInSnapshotFilenameFormat(currentFilename)) { - const int MAX_IMAGES = 100000; - if (i >= MAX_IMAGES) { - messageBox.critical(0, "Error", "More than 100,000 images not supported"); + const int maxImages = pow(10, NUM_DIGITS); + if (i >= maxImages) { + messageBox.critical(0, "Error", "More than " + QString::number(maxImages) + " images not supported"); exit(-1); } QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".jpg"; @@ -491,7 +498,6 @@ bool Test::isInSnapshotFilenameFormat(QString filename) { // For a file named "D_GitHub_hifi-tests_tests_content_entity_zone_create_0.jpg", the test directory is // D:/GitHub/hifi-tests/tests/content/entity/zone/create // This method assumes the filename is in the correct format -// The final part of the filename is the image number. This is checked for sanity QString Test::getExpectedImageDestinationDirectory(QString filename) { QString filenameWithoutExtension = filename.split(".")[0]; QStringList filenameParts = filenameWithoutExtension.split("_"); @@ -505,6 +511,28 @@ QString Test::getExpectedImageDestinationDirectory(QString filename) { return result; } +// For a file named "D_GitHub_hifi-tests_tests_content_entity_zone_create_0.jpg", the source directory on GitHub +// is ...tests/content/entity/zone/create +// This is used to create the full URL +// This method assumes the filename is in the correct format +QString Test::getExpectedImagePartialSourceDirectory(QString filename) { + QString filenameWithoutExtension = filename.split(".")[0]; + QStringList filenameParts = filenameWithoutExtension.split("_"); + + int i { 0 }; + while (filenameParts[i] != "tests") { + ++i; + } + + QString result = filenameParts[i]; + + for (int j = i + 1; j < filenameParts.length() - 1; ++j) { + result += "/" + filenameParts[j]; + } + + return result; +} + bool Test::isInExpectedImageFilenameFormat(QString filename) { return (expectedImageFilenameFormat.match(filename).hasMatch()); } \ No newline at end of file diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 7168a8ef69..026dbf25f6 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -47,6 +47,7 @@ public: bool isAValidDirectory(QString pathname); QString getExpectedImageDestinationDirectory(QString filename); + QString getExpectedImagePartialSourceDirectory(QString filename); private: const QString TEST_FILENAME { "test.js" }; diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 5a666aa5eb..c3ab88b7f4 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -16,6 +16,8 @@ AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) { ui.progressBar->setVisible(false); test = new Test(); + + signalMapper = new QSignalMapper(); } void AutoTester::on_evaluateTestsButton_clicked() { @@ -50,15 +52,35 @@ void AutoTester::on_closeButton_clicked() { } void AutoTester::downloadImage(QUrl url) { - downloader = new Downloader(url, this); + downloaders.emplace_back(new Downloader(url, this)); + connect(downloaders[_index], SIGNAL (downloaded()), signalMapper, SLOT (map())); - connect(downloader, SIGNAL (downloaded()), this, SLOT (saveImage())); + signalMapper->setMapping(downloaders[_index], _index); + + ++_index; } -void AutoTester::saveImage() { +void AutoTester::downloadImages(QStringList listOfURLs) { + _numberOfImagesToDownload = listOfURLs.size(); + _numberOfImagesDownloaded = 0; + _index = 0; + + for (int i = 0; i < _numberOfImagesToDownload; ++i) { + QUrl imageURL(listOfURLs[i]); + downloadImage(imageURL); + } + + connect(signalMapper, SIGNAL (mapped(int)), this, SLOT (saveImage(int))); +} + +void AutoTester::saveImage(int index) { QPixmap image; - image.loadFromData(downloader->downloadedData()); - int er = image.width(); - int df = image.height(); - image.save("D:/Dicom/lll.jpg"); + image.loadFromData(downloaders[index]->downloadedData()); + + int w = image.width(); + int h = image.height(); + + ++_numberOfImagesDownloaded; + + image.save("D:/Dicom/lll_" + QString::number(index) + ".jpg"); } diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index 2f6a9bca1e..5c1f217421 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -11,6 +11,7 @@ #define hifi_AutoTester_h #include +#include #include "ui_AutoTester.h" #include "../Downloader.h" @@ -22,6 +23,7 @@ class AutoTester : public QMainWindow { public: AutoTester(QWidget *parent = Q_NULLPTR); void downloadImage(QUrl url); + void downloadImages(QStringList listOfURLs); private slots: void on_evaluateTestsButton_clicked(); @@ -32,13 +34,19 @@ private slots: void on_deleteOldSnapshotsButton_clicked(); void on_closeButton_clicked(); - void saveImage(); + void saveImage(int index); private: Ui::AutoTesterClass ui; Test* test; - Downloader* downloader; + std::vector downloaders; + + QSignalMapper* signalMapper; + + int _numberOfImagesToDownload; + int _numberOfImagesDownloaded; + int _index; }; #endif // hifi_AutoTester_h \ No newline at end of file From 4b836a2ca9ef0194af2c6f1c03ff96ee7f409fe6 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Mar 2018 16:49:09 -0800 Subject: [PATCH 06/24] Stores downloaded images in correct folder and with correct filenames. --- tools/auto-tester/src/Test.cpp | 11 +++++++---- tools/auto-tester/src/ui/AutoTester.cpp | 17 +++++++++-------- tools/auto-tester/src/ui/AutoTester.h | 11 ++++++++--- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index ac10d1ab33..d30349b395 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -198,7 +198,8 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { // Images that are in the wrong format are ignored. QStringList sortedTestResultsFilenames = createListOfAllJPEGimagesInDirectory(pathToTestResultsDirectory); - QStringList expectedImages; + QStringList expectedImagesURLs; + QStringList expectedImagesFilenames; QStringList resultImages; const QString URLPrefix("https://raw.githubusercontent.com"); @@ -217,14 +218,16 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + EXPECTED_IMAGE_TYPE; + expectedImagesFilenames << expectedImageFilename; + QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + expectedImagePartialSourceDirectory + "/" + expectedImageFilename); - expectedImages << imageURLString; + expectedImagesURLs << imageURLString; } } - //autoTester->downloadImage(QUrl("https://raw.githubusercontent.com/NissimHadar/hifi_tests/addRecursionToAutotester/tests/content/entity/zone/ambientLightInheritance/ExpectedImage_00000.jpg")); + autoTester->downloadImages(expectedImagesURLs, pathToTestResultsDirectory, expectedImagesFilenames); - autoTester->downloadImages(expectedImages); + // Wait for do ////if (success) { //// messageBox.information(0, "Success", "All images are as expected"); diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index c3ab88b7f4..5fd726ad72 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -51,7 +51,7 @@ void AutoTester::on_closeButton_clicked() { exit(0); } -void AutoTester::downloadImage(QUrl url) { +void AutoTester::downloadImage(const QUrl& url) { downloaders.emplace_back(new Downloader(url, this)); connect(downloaders[_index], SIGNAL (downloaded()), signalMapper, SLOT (map())); @@ -60,13 +60,16 @@ void AutoTester::downloadImage(QUrl url) { ++_index; } -void AutoTester::downloadImages(QStringList listOfURLs) { - _numberOfImagesToDownload = listOfURLs.size(); +void AutoTester::downloadImages(const QStringList& URLs, const QString& directoryName, const QStringList& filenames) { + _directoryName = directoryName; + _filenames = filenames; + + _numberOfImagesToDownload = URLs.size(); _numberOfImagesDownloaded = 0; _index = 0; for (int i = 0; i < _numberOfImagesToDownload; ++i) { - QUrl imageURL(listOfURLs[i]); + QUrl imageURL(URLs[i]); downloadImage(imageURL); } @@ -77,10 +80,8 @@ void AutoTester::saveImage(int index) { QPixmap image; image.loadFromData(downloaders[index]->downloadedData()); - int w = image.width(); - int h = image.height(); + + image.save(_directoryName + "/" + _filenames[index]); ++_numberOfImagesDownloaded; - - image.save("D:/Dicom/lll_" + QString::number(index) + ".jpg"); } diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index 5c1f217421..d5bab6d8a4 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -22,8 +22,8 @@ class AutoTester : public QMainWindow { public: AutoTester(QWidget *parent = Q_NULLPTR); - void downloadImage(QUrl url); - void downloadImages(QStringList listOfURLs); + void downloadImage(const QUrl& url); + void downloadImages(const QStringList& URLs, const QString& directoryName, const QStringList& filenames); private slots: void on_evaluateTestsButton_clicked(); @@ -38,10 +38,15 @@ private slots: private: Ui::AutoTesterClass ui; - Test* test; + std::vector downloaders; + // local storage for parameters - folder to store downloaded files in, and a list of their names + QString _directoryName; + QStringList _filenames; + + // Used to enable passing a parameter to slots QSignalMapper* signalMapper; int _numberOfImagesToDownload; From 361b5331bafba0d7862c52c8527a3c3550a91dc8 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 2 Mar 2018 18:09:32 -0800 Subject: [PATCH 07/24] File sizes are wrong, and so is format. --- tools/auto-tester/src/Test.cpp | 101 ++++-------------------- tools/auto-tester/src/Test.h | 11 ++- tools/auto-tester/src/ui/AutoTester.cpp | 23 +++--- tools/auto-tester/src/ui/AutoTester.h | 1 - tools/auto-tester/src/ui/AutoTester.ui | 13 --- 5 files changed, 36 insertions(+), 113 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index d30349b395..8fed094b07 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -63,9 +63,9 @@ void Test::zipAndDeleteTestResultsFolder() { index = 1; } -bool Test::compareImageLists(QStringList expectedImages, QStringList resultImages, QString testDirectory, bool interactiveMode, QProgressBar* progressBar) { +bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) { progressBar->setMinimum(0); - progressBar->setMaximum(expectedImages.length() - 1); + progressBar->setMaximum(expectedImagesFilenames.length() - 1); progressBar->setValue(0); progressBar->setVisible(true); @@ -74,10 +74,10 @@ bool Test::compareImageLists(QStringList expectedImages, QStringList resultImage const double THRESHOLD { 0.999 }; bool success{ true }; bool keepOn{ true }; - for (int i = 0; keepOn && i < expectedImages.length(); ++i) { + for (int i = 0; keepOn && i < expectedImagesFilenames.length(); ++i) { // First check that images are the same size - QImage resultImage(resultImages[i]); - QImage expectedImage(expectedImages[i]); + QImage resultImage(resultImagesFilenames[i]); + QImage expectedImage(expectedImagesFilenames[i]); if (resultImage.width() != expectedImage.width() || resultImage.height() != expectedImage.height()) { messageBox.critical(0, "Internal error", "Images are not the same size"); exit(-1); @@ -94,14 +94,14 @@ bool Test::compareImageLists(QStringList expectedImages, QStringList resultImage if (similarityIndex < THRESHOLD) { TestFailure testFailure = TestFailure{ (float)similarityIndex, - expectedImages[i].left(expectedImages[i].lastIndexOf("/") + 1), // path to the test (including trailing /) - QFileInfo(expectedImages[i].toStdString().c_str()).fileName(), // filename of expected image - QFileInfo(resultImages[i].toStdString().c_str()).fileName() // filename of result image + expectedImagesFilenames[i].left(expectedImagesFilenames[i].lastIndexOf("/") + 1), // path to the test (including trailing /) + QFileInfo(expectedImagesFilenames[i].toStdString().c_str()).fileName(), // filename of expected image + QFileInfo(resultImagesFilenames[i].toStdString().c_str()).fileName() // filename of result image }; mismatchWindow.setTestFailure(testFailure); - if (!interactiveMode) { + if (!isInteractiveMode) { appendTestResultsToFile(testResultsFolderPath, testFailure, mismatchWindow.getComparisonImage()); success = false; } else { @@ -181,9 +181,9 @@ void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure te comparisonImage.save(failureFolderPath + "/" + "Difference Image.jpg"); } -void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { +void Test::startTestsEvaluation() { // Get list of JPEG images in folder, sorted by name - QString pathToTestResultsDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); + pathToTestResultsDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); if (pathToTestResultsDirectory == "") { return; } @@ -199,8 +199,6 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { QStringList sortedTestResultsFilenames = createListOfAllJPEGimagesInDirectory(pathToTestResultsDirectory); QStringList expectedImagesURLs; - QStringList expectedImagesFilenames; - QStringList resultImages; const QString URLPrefix("https://raw.githubusercontent.com"); const QString githubUser("NissimHadar"); @@ -210,7 +208,7 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { foreach(QString currentFilename, sortedTestResultsFilenames) { QString fullCurrentFilename = pathToTestResultsDirectory + "/" + currentFilename; if (isInSnapshotFilenameFormat(currentFilename)) { - resultImages << fullCurrentFilename; + resultImagesFilenames << fullCurrentFilename; QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); @@ -226,15 +224,10 @@ void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { } autoTester->downloadImages(expectedImagesURLs, pathToTestResultsDirectory, expectedImagesFilenames); +} - // Wait for do - - ////if (success) { - //// messageBox.information(0, "Success", "All images are as expected"); - ////} else { - //// messageBox.information(0, "Failure", "One or more images are not as expected"); - ////} - +void Test::finishTestsEvaluation(bool interactiveMode, QProgressBar* progressBar) { + bool success = compareImageLists(interactiveMode, progressBar); zipAndDeleteTestResultsFolder(); } @@ -253,70 +246,6 @@ bool Test::isAValidDirectory(QString pathname) { return true; } -// Two criteria are used to decide if a folder contains valid test results. -// 1) a 'test'js' file exists in the folder -// 2) the folder has the same number of actual and expected images -void Test::evaluateTestsRecursively(bool interactiveMode, QProgressBar* progressBar) { - // Select folder to start recursing from - QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder that will contain the top level test script", ".", QFileDialog::ShowDirsOnly); - if (topLevelDirectory == "") { - return; - } - - // Leave if test results folder could not be created - if (!createTestResultsFolderPathIfNeeded(topLevelDirectory)) { - return; - } - - bool success{ true }; - QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); - while (it.hasNext()) { - QString directory = it.next(); - - if (!isAValidDirectory(directory)) { - continue; - } - - const QString testPathname{ directory + "/" + TEST_FILENAME }; - QFileInfo fileInfo(testPathname); - if (!fileInfo.exists()) { - // Folder does not contain 'test.js' - continue; - } - - QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(directory); - - // Separate images into two lists. The first is the expected images, the second is the test results - // Images that are in the wrong format are ignored. - QStringList expectedImages; - QStringList resultImages; - foreach(QString currentFilename, sortedImageFilenames) { - QString fullCurrentFilename = directory + "/" + currentFilename; - if (isInExpectedImageFilenameFormat(currentFilename)) { - expectedImages << fullCurrentFilename; - } else if (isInSnapshotFilenameFormat(currentFilename)) { - resultImages << fullCurrentFilename; - } - } - - if (expectedImages.length() != resultImages.length()) { - // Number of images doesn't match - continue; - } - - // Set success to false if any test has failed - success &= compareImageLists(expectedImages, resultImages, directory, interactiveMode, progressBar); - } - - if (success) { - messageBox.information(0, "Success", "All images are as expected"); - } else { - messageBox.information(0, "Failure", "One or more images are not as expected"); - } - - zipAndDeleteTestResultsFolder(); -} - void Test::importTest(QTextStream& textStream, const QString& testPathname) { textStream << "Script.include(\"" << "file:///" << testPathname + "?raw=true\");" << endl; } diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 026dbf25f6..bb7831da5e 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -23,14 +23,15 @@ class Test { public: Test(); - void evaluateTests(bool interactiveMode, QProgressBar* progressBar); - void evaluateTestsRecursively(bool interactiveMode, QProgressBar* progressBar); + void startTestsEvaluation(); + void finishTestsEvaluation(bool interactiveMode, QProgressBar* progressBar); + void createRecursiveScript(); void createRecursiveScriptsRecursively(); void createTest(); void deleteOldSnapshots(); - bool compareImageLists(QStringList expectedImages, QStringList resultImages, QString testDirectory, bool interactiveMode, QProgressBar* progressBar); + bool compareImageLists(bool isInteractiveMode, QProgressBar* progressBar); QStringList createListOfAllJPEGimagesInDirectory(QString pathToImageDirectory); @@ -71,6 +72,10 @@ private: const int NUM_DIGITS { 5 }; const QString EXPECTED_IMAGE_PREFIX { "ExpectedImage_" }; const QString EXPECTED_IMAGE_TYPE { ".jpg" }; + + QString pathToTestResultsDirectory; + QStringList expectedImagesFilenames; + QStringList resultImagesFilenames; }; #endif // hifi_test_h \ No newline at end of file diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 5fd726ad72..52499cd448 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -21,14 +21,7 @@ AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) { } void AutoTester::on_evaluateTestsButton_clicked() { - ////QUrl imageUrl("http://ribafreixo.com/wp-content/uploads/2017/03/Order-Now-Button-300x113.png"); - ////downloader = new Downloader(imageUrl, this); - ////connect(downloader, SIGNAL (downloaded()), this, SLOT (saveImage())); - test->evaluateTests(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); -} - -void AutoTester::on_evaluateTestsRecursivelyButton_clicked() { - test->evaluateTestsRecursively(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); + test->startTestsEvaluation(); } void AutoTester::on_createRecursiveScriptButton_clicked() { @@ -68,6 +61,11 @@ void AutoTester::downloadImages(const QStringList& URLs, const QString& director _numberOfImagesDownloaded = 0; _index = 0; + ui.progressBar->setMinimum(0); + ui.progressBar->setMaximum(_numberOfImagesToDownload - 1); + ui.progressBar->setValue(0); + ui.progressBar->setVisible(true); + for (int i = 0; i < _numberOfImagesToDownload; ++i) { QUrl imageURL(URLs[i]); downloadImage(imageURL); @@ -80,8 +78,13 @@ void AutoTester::saveImage(int index) { QPixmap image; image.loadFromData(downloaders[index]->downloadedData()); - - image.save(_directoryName + "/" + _filenames[index]); + image.save(_directoryName + "/" + _filenames[index], 0, 100); ++_numberOfImagesDownloaded; + + if (_numberOfImagesDownloaded == _numberOfImagesToDownload) { + test->finishTestsEvaluation(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); + } else { + ui.progressBar->setValue(_numberOfImagesDownloaded); + } } diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index d5bab6d8a4..acf34c60a3 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -27,7 +27,6 @@ public: private slots: void on_evaluateTestsButton_clicked(); - void on_evaluateTestsRecursivelyButton_clicked(); void on_createRecursiveScriptButton_clicked(); void on_createRecursiveScriptsRecursivelyButton_clicked(); void on_createTestButton_clicked(); diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index 0d142ec43e..70060940d1 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -66,19 +66,6 @@ Create Recursive Script - - - - 20 - 130 - 220 - 40 - - - - Evaluate Tests Recursively - - From 0a2610a9e0b8335e89f6c725e117d24dacb2707e Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sat, 3 Mar 2018 09:58:30 -0800 Subject: [PATCH 08/24] Evaluation seems to work. --- tools/auto-tester/src/ImageComparer.cpp | 6 ++-- tools/auto-tester/src/Test.cpp | 47 ++++++++++++++----------- tools/auto-tester/src/Test.h | 7 ++-- tools/auto-tester/src/ui/AutoTester.cpp | 7 ++-- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/tools/auto-tester/src/ImageComparer.cpp b/tools/auto-tester/src/ImageComparer.cpp index 94b95a5ab6..99f7d22c5f 100644 --- a/tools/auto-tester/src/ImageComparer.cpp +++ b/tools/auto-tester/src/ImageComparer.cpp @@ -17,13 +17,13 @@ double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) const { // Make sure the image is 8 bits per colour QImage::Format format = expectedImage.format(); - if (format != QImage::Format::Format_RGB32) { + if (format != QImage::Format::Format_ARGB32) { throw -1; } const int L = 255; // (2^number of bits per pixel) - 1 - const double K1{ 0.01 }; - const double K2{ 0.03 }; + const double K1 { 0.01 }; + const double K2 { 0.03 }; const double c1 = pow((K1 * L), 2); const double c2 = pow((K2 * L), 2); diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 8fed094b07..48fa530384 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -20,7 +20,7 @@ extern AutoTester* autoTester; Test::Test() { - QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + EXPECTED_IMAGE_TYPE); + QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + IMAGE_FORMAT); expectedImageFilenameFormat = QRegularExpression(regex); @@ -65,7 +65,7 @@ void Test::zipAndDeleteTestResultsFolder() { bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) { progressBar->setMinimum(0); - progressBar->setMaximum(expectedImagesFilenames.length() - 1); + progressBar->setMaximum(expectedImagesFullFilenames.length() - 1); progressBar->setValue(0); progressBar->setVisible(true); @@ -74,10 +74,11 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) const double THRESHOLD { 0.999 }; bool success{ true }; bool keepOn{ true }; - for (int i = 0; keepOn && i < expectedImagesFilenames.length(); ++i) { + for (int i = 0; keepOn && i < expectedImagesFullFilenames.length(); ++i) { // First check that images are the same size - QImage resultImage(resultImagesFilenames[i]); - QImage expectedImage(expectedImagesFilenames[i]); + QImage resultImage(resultImagesFullFilenames[i]); + QImage expectedImage(expectedImagesFullFilenames[i]); + if (resultImage.width() != expectedImage.width() || resultImage.height() != expectedImage.height()) { messageBox.critical(0, "Internal error", "Images are not the same size"); exit(-1); @@ -94,9 +95,9 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) if (similarityIndex < THRESHOLD) { TestFailure testFailure = TestFailure{ (float)similarityIndex, - expectedImagesFilenames[i].left(expectedImagesFilenames[i].lastIndexOf("/") + 1), // path to the test (including trailing /) - QFileInfo(expectedImagesFilenames[i].toStdString().c_str()).fileName(), // filename of expected image - QFileInfo(resultImagesFilenames[i].toStdString().c_str()).fileName() // filename of result image + expectedImagesFullFilenames[i].left(expectedImagesFullFilenames[i].lastIndexOf("/") + 1), // path to the test (including trailing /) + QFileInfo(expectedImagesFullFilenames[i].toStdString().c_str()).fileName(), // filename of expected image + QFileInfo(resultImagesFullFilenames[i].toStdString().c_str()).fileName() // filename of result image }; mismatchWindow.setTestFailure(testFailure); @@ -197,7 +198,7 @@ void Test::startTestsEvaluation() { // The expected images are represented as a URL to enabel download from GitHub // Images that are in the wrong format are ignored. - QStringList sortedTestResultsFilenames = createListOfAllJPEGimagesInDirectory(pathToTestResultsDirectory); + QStringList sortedTestResultsFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(pathToTestResultsDirectory); QStringList expectedImagesURLs; const QString URLPrefix("https://raw.githubusercontent.com"); @@ -205,18 +206,23 @@ void Test::startTestsEvaluation() { const QString testsRepo("hifi_tests"); const QString branch("addRecursionToAutotester"); + resultImagesFullFilenames.clear(); + expectedImagesFilenames.clear(); + expectedImagesFullFilenames.clear(); + foreach(QString currentFilename, sortedTestResultsFilenames) { QString fullCurrentFilename = pathToTestResultsDirectory + "/" + currentFilename; if (isInSnapshotFilenameFormat(currentFilename)) { - resultImagesFilenames << fullCurrentFilename; + resultImagesFullFilenames << fullCurrentFilename; QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); // extract the digits at the end of the filename (exluding the file extension) QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); - QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + EXPECTED_IMAGE_TYPE; + QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + IMAGE_FORMAT; expectedImagesFilenames << expectedImageFilename; + expectedImagesFullFilenames << pathToTestResultsDirectory + "/" + expectedImageFilename; QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + expectedImagePartialSourceDirectory + "/" + expectedImageFilename); expectedImagesURLs << imageURLString; @@ -332,9 +338,10 @@ void Test::createTest() { return; } - QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(imageSourceDirectory); + QStringList sortedImageFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(imageSourceDirectory); - int i = 1; + int i = 1; + const int maxImages = pow(10, NUM_DIGITS); foreach (QString currentFilename, sortedImageFilenames) { QString fullCurrentFilename = imageSourceDirectory + "/" + currentFilename; if (isInExpectedImageFilenameFormat(currentFilename)) { @@ -343,12 +350,12 @@ void Test::createTest() { exit(-1); } } else if (isInSnapshotFilenameFormat(currentFilename)) { - const int maxImages = pow(10, NUM_DIGITS); + if (i >= maxImages) { messageBox.critical(0, "Error", "More than " + QString::number(maxImages) + " images not supported"); exit(-1); } - QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".jpg"; + QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + IMAGE_FORMAT; QString imageDestinationDirectory = getExpectedImageDestinationDirectory(currentFilename); QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; @@ -383,7 +390,7 @@ void Test::deleteOldSnapshots() { continue; } - QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(directory); + QStringList sortedImageFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(directory); // Delete any file that is a snapshot (NOT the Expected Images) QStringList expectedImages; @@ -400,10 +407,10 @@ void Test::deleteOldSnapshots() { } } -QStringList Test::createListOfAllJPEGimagesInDirectory(QString pathToImageDirectory) { +QStringList Test::createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToImageDirectory) { imageDirectory = QDir(pathToImageDirectory); QStringList nameFilters; - nameFilters << "*.jpg"; + nameFilters << "*" + IMAGE_FORMAT; return imageDirectory.entryList(nameFilters, QDir::Files, QDir::Name); } @@ -422,9 +429,9 @@ bool Test::isInSnapshotFilenameFormat(QString filename) { bool last5CharactersAreDigits; filenameParts[0].right(5).toInt(&last5CharactersAreDigits, 10); - bool extensionIsJPG = filenameParts[1] == "jpg"; + bool extensionIsIMAGE_FORMAT = filenameParts[1] == IMAGE_FORMAT.right(3); // without the period - return (filnameHasNoPeriods && contains_tests && last5CharactersAreDigits && extensionIsJPG); + return (filnameHasNoPeriods && contains_tests && last5CharactersAreDigits && extensionIsIMAGE_FORMAT); } // For a file named "D_GitHub_hifi-tests_tests_content_entity_zone_create_0.jpg", the test directory is diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index bb7831da5e..56d924b82a 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -33,7 +33,7 @@ public: bool compareImageLists(bool isInteractiveMode, QProgressBar* progressBar); - QStringList createListOfAllJPEGimagesInDirectory(QString pathToImageDirectory); + QStringList createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToImageDirectory); bool isInSnapshotFilenameFormat(QString filename); bool isInExpectedImageFilenameFormat(QString filename); @@ -71,11 +71,12 @@ private: // Expected images are in the format ExpectedImage_dddd.jpg (d == decimal digit) const int NUM_DIGITS { 5 }; const QString EXPECTED_IMAGE_PREFIX { "ExpectedImage_" }; - const QString EXPECTED_IMAGE_TYPE { ".jpg" }; + const QString IMAGE_FORMAT { ".png" }; QString pathToTestResultsDirectory; QStringList expectedImagesFilenames; - QStringList resultImagesFilenames; + QStringList expectedImagesFullFilenames; + QStringList resultImagesFullFilenames; }; #endif // hifi_test_h \ No newline at end of file diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 52499cd448..ade6b0514e 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -75,8 +75,11 @@ void AutoTester::downloadImages(const QStringList& URLs, const QString& director } void AutoTester::saveImage(int index) { - QPixmap image; - image.loadFromData(downloaders[index]->downloadedData()); + QPixmap pixmap; + pixmap.loadFromData(downloaders[index]->downloadedData()); + + QImage image = pixmap.toImage(); + image = image.convertToFormat(QImage::Format_ARGB32); image.save(_directoryName + "/" + _filenames[index], 0, 100); From b32ad2f69c7120cfcd76d5464bd6591141160aca Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sat, 3 Mar 2018 18:22:51 -0800 Subject: [PATCH 09/24] createTests fixed. --- tools/auto-tester/src/Test.cpp | 13 ++----------- tools/auto-tester/src/Test.h | 1 - 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 48fa530384..dbaa3a05a5 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -344,13 +344,7 @@ void Test::createTest() { const int maxImages = pow(10, NUM_DIGITS); foreach (QString currentFilename, sortedImageFilenames) { QString fullCurrentFilename = imageSourceDirectory + "/" + currentFilename; - if (isInExpectedImageFilenameFormat(currentFilename)) { - if (!QFile::remove(fullCurrentFilename)) { - messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); - exit(-1); - } - } else if (isInSnapshotFilenameFormat(currentFilename)) { - + if (isInSnapshotFilenameFormat(currentFilename)) { if (i >= maxImages) { messageBox.critical(0, "Error", "More than " + QString::number(maxImages) + " images not supported"); exit(-1); @@ -360,6 +354,7 @@ void Test::createTest() { QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; try { + QFile::remove(fullNewFileName); QFile::copy(fullCurrentFilename, fullNewFileName); } catch (...) { messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); @@ -471,7 +466,3 @@ QString Test::getExpectedImagePartialSourceDirectory(QString filename) { return result; } - -bool Test::isInExpectedImageFilenameFormat(QString filename) { - return (expectedImageFilenameFormat.match(filename).hasMatch()); -} \ No newline at end of file diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 56d924b82a..29e1b135ed 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -36,7 +36,6 @@ public: QStringList createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToImageDirectory); bool isInSnapshotFilenameFormat(QString filename); - bool isInExpectedImageFilenameFormat(QString filename); void importTest(QTextStream& textStream, const QString& testPathname); From 913ad569c0585769e53bc2d1e926a0afef47c572 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sun, 4 Mar 2018 17:36:20 -0800 Subject: [PATCH 10/24] Added completion message. --- tools/auto-tester/src/Test.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index dbaa3a05a5..7b6293dcbc 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -234,6 +234,13 @@ void Test::startTestsEvaluation() { void Test::finishTestsEvaluation(bool interactiveMode, QProgressBar* progressBar) { bool success = compareImageLists(interactiveMode, progressBar); + + if (success) { + messageBox.information(0, "Success", "All images are as expected"); + } else { + messageBox.information(0, "Failure", "One or more images are not as expected"); + } + zipAndDeleteTestResultsFolder(); } From 5a79f272f3e9ef29ed87977c586b2d7c34edc852 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Sun, 4 Mar 2018 20:56:57 -0800 Subject: [PATCH 11/24] Allow multiple evaluations. --- tools/auto-tester/src/Test.cpp | 18 ++++++++++++------ tools/auto-tester/src/ui/AutoTester.cpp | 3 ++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 7b6293dcbc..fbd30e7307 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -216,16 +216,22 @@ void Test::startTestsEvaluation() { resultImagesFullFilenames << fullCurrentFilename; QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); - - // extract the digits at the end of the filename (exluding the file extension) + + // Images are stored on GitHub as ExpectedImage_ddddd.png + // Extract the digits at the end of the filename (exluding the file extension) QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); - QString expectedImageFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + IMAGE_FORMAT; + QString expectedImageStoredFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + IMAGE_FORMAT; + + QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + + expectedImagePartialSourceDirectory + "/" + expectedImageStoredFilename); + + expectedImagesURLs << imageURLString; + + // The image retrieved from Github needs a unique name + QString expectedImageFilename = currentFilename.replace("/", "_").replace(".", "_EI."); expectedImagesFilenames << expectedImageFilename; expectedImagesFullFilenames << pathToTestResultsDirectory + "/" + expectedImageFilename; - - QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + expectedImagePartialSourceDirectory + "/" + expectedImageFilename); - expectedImagesURLs << imageURLString; } } diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index ade6b0514e..5ac7be3dd8 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -81,7 +81,8 @@ void AutoTester::saveImage(int index) { QImage image = pixmap.toImage(); image = image.convertToFormat(QImage::Format_ARGB32); - image.save(_directoryName + "/" + _filenames[index], 0, 100); + QString fullPathname = _directoryName + "/" + _filenames[index]; + image.save(fullPathname, 0, 100); ++_numberOfImagesDownloaded; From 84815fadaeb6bf2476074466cc0d0da28dfb549d Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Mon, 5 Mar 2018 17:45:51 -0800 Subject: [PATCH 12/24] Use JPG->PNG trick to keep file sizes down. --- tools/auto-tester/src/Test.cpp | 79 +++++++++++-------------- tools/auto-tester/src/Test.h | 7 ++- tools/auto-tester/src/ui/AutoTester.cpp | 4 -- tools/auto-tester/src/ui/AutoTester.h | 1 - tools/auto-tester/src/ui/AutoTester.ui | 21 ++----- 5 files changed, 43 insertions(+), 69 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index fbd30e7307..53687fdeda 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -20,7 +22,7 @@ extern AutoTester* autoTester; Test::Test() { - QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + IMAGE_FORMAT); + QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + ".png"); expectedImageFilenameFormat = QRegularExpression(regex); @@ -194,11 +196,23 @@ void Test::startTestsEvaluation() { return; } + // Before any processing - all images are converted to PNGs, as this is the format stored on GitHub + QStringList sortedSnapshotFilenames = createListOfAll_imagesInDirectory("jpg", pathToTestResultsDirectory); + foreach(QString filename, sortedSnapshotFilenames) { + QStringList stringParts = filename.split("."); + copyJPGtoPNG( + pathToTestResultsDirectory + "/" + stringParts[0] + ".jpg", + pathToTestResultsDirectory + "/" + stringParts[0] + ".png" + ); + + QFile::remove(pathToTestResultsDirectory + "/" + stringParts[0] + ".jpg"); + } + // Create two lists. The first is the test results, the second is the expected images - // The expected images are represented as a URL to enabel download from GitHub + // The expected images are represented as a URL to enable download from GitHub // Images that are in the wrong format are ignored. - QStringList sortedTestResultsFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(pathToTestResultsDirectory); + QStringList sortedTestResultsFilenames = createListOfAll_imagesInDirectory("png", pathToTestResultsDirectory); QStringList expectedImagesURLs; const QString URLPrefix("https://raw.githubusercontent.com"); @@ -212,7 +226,7 @@ void Test::startTestsEvaluation() { foreach(QString currentFilename, sortedTestResultsFilenames) { QString fullCurrentFilename = pathToTestResultsDirectory + "/" + currentFilename; - if (isInSnapshotFilenameFormat(currentFilename)) { + if (isInSnapshotFilenameFormat("png", currentFilename)) { resultImagesFullFilenames << fullCurrentFilename; QString expectedImagePartialSourceDirectory = getExpectedImagePartialSourceDirectory(currentFilename); @@ -220,7 +234,7 @@ void Test::startTestsEvaluation() { // Images are stored on GitHub as ExpectedImage_ddddd.png // Extract the digits at the end of the filename (exluding the file extension) QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); - QString expectedImageStoredFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + IMAGE_FORMAT; + QString expectedImageStoredFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + ".png"; QString imageURLString(URLPrefix + "/" + githubUser + "/" + testsRepo + "/" + branch + "/" + expectedImagePartialSourceDirectory + "/" + expectedImageStoredFilename); @@ -351,24 +365,23 @@ void Test::createTest() { return; } - QStringList sortedImageFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(imageSourceDirectory); + QStringList sortedImageFilenames = createListOfAll_imagesInDirectory("jpg", imageSourceDirectory); int i = 1; const int maxImages = pow(10, NUM_DIGITS); foreach (QString currentFilename, sortedImageFilenames) { QString fullCurrentFilename = imageSourceDirectory + "/" + currentFilename; - if (isInSnapshotFilenameFormat(currentFilename)) { + if (isInSnapshotFilenameFormat("jpg", currentFilename)) { if (i >= maxImages) { messageBox.critical(0, "Error", "More than " + QString::number(maxImages) + " images not supported"); exit(-1); } - QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + IMAGE_FORMAT; + QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".png"; QString imageDestinationDirectory = getExpectedImageDestinationDirectory(currentFilename); QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; try { - QFile::remove(fullNewFileName); - QFile::copy(fullCurrentFilename, fullNewFileName); + copyJPGtoPNG(fullCurrentFilename, fullNewFileName); } catch (...) { messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); exit(-1); @@ -380,45 +393,23 @@ void Test::createTest() { messageBox.information(0, "Success", "Test images have been created"); } -void Test::deleteOldSnapshots() { - // Select folder to start recursing from - QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select root folder for snapshot deletion", ".", QFileDialog::ShowDirsOnly); - if (topLevelDirectory == "") { - return; - } +void Test::copyJPGtoPNG(QString sourceJPGFullFilename, QString destinationPNGFullFilename) { + QFile::remove(destinationPNGFullFilename); - // Recurse over folders - QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); - while (it.hasNext()) { - QString directory = it.next(); + QImageReader reader; + reader.setFileName(sourceJPGFullFilename); - // Only process directories - QDir dir(directory); - if (!isAValidDirectory(directory)) { - continue; - } + QImage image = reader.read(); - QStringList sortedImageFilenames = createListOfAll_IMAGE_FORMAT_imagesInDirectory(directory); - - // Delete any file that is a snapshot (NOT the Expected Images) - QStringList expectedImages; - QStringList resultImages; - foreach(QString currentFilename, sortedImageFilenames) { - QString fullCurrentFilename = directory + "/" + currentFilename; - if (isInSnapshotFilenameFormat(currentFilename)) { - if (!QFile::remove(fullCurrentFilename)) { - messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nSnapshot deletion aborted"); - exit(-1); - } - } - } - } + QImageWriter writer; + writer.setFileName(destinationPNGFullFilename); + writer.write(image); } -QStringList Test::createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToImageDirectory) { +QStringList Test::createListOfAll_imagesInDirectory(QString imageFormat, QString pathToImageDirectory) { imageDirectory = QDir(pathToImageDirectory); QStringList nameFilters; - nameFilters << "*" + IMAGE_FORMAT; + nameFilters << "*." + imageFormat; return imageDirectory.entryList(nameFilters, QDir::Files, QDir::Name); } @@ -428,7 +419,7 @@ QStringList Test::createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToI // Filename (i.e. without extension) contains _tests_ (this is based on all test scripts being within the tests folder // Last 5 characters in filename are digits // Extension is jpg -bool Test::isInSnapshotFilenameFormat(QString filename) { +bool Test::isInSnapshotFilenameFormat(QString imageFormat, QString filename) { QStringList filenameParts = filename.split("."); bool filnameHasNoPeriods = (filenameParts.size() == 2); @@ -437,7 +428,7 @@ bool Test::isInSnapshotFilenameFormat(QString filename) { bool last5CharactersAreDigits; filenameParts[0].right(5).toInt(&last5CharactersAreDigits, 10); - bool extensionIsIMAGE_FORMAT = filenameParts[1] == IMAGE_FORMAT.right(3); // without the period + bool extensionIsIMAGE_FORMAT = (filenameParts[1] == imageFormat); return (filnameHasNoPeriods && contains_tests && last5CharactersAreDigits && extensionIsIMAGE_FORMAT); } diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 29e1b135ed..b849ab577f 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -33,9 +33,9 @@ public: bool compareImageLists(bool isInteractiveMode, QProgressBar* progressBar); - QStringList createListOfAll_IMAGE_FORMAT_imagesInDirectory(QString pathToImageDirectory); + QStringList createListOfAll_imagesInDirectory(QString imageFormat, QString pathToImageDirectory); - bool isInSnapshotFilenameFormat(QString filename); + bool isInSnapshotFilenameFormat(QString imageFormat, QString filename); void importTest(QTextStream& textStream, const QString& testPathname); @@ -49,6 +49,8 @@ public: QString getExpectedImageDestinationDirectory(QString filename); QString getExpectedImagePartialSourceDirectory(QString filename); + void copyJPGtoPNG(QString sourceJPGFullFilename, QString destinationPNGFullFilename); + private: const QString TEST_FILENAME { "test.js" }; const QString TEST_RESULTS_FOLDER { "TestResults" }; @@ -70,7 +72,6 @@ private: // Expected images are in the format ExpectedImage_dddd.jpg (d == decimal digit) const int NUM_DIGITS { 5 }; const QString EXPECTED_IMAGE_PREFIX { "ExpectedImage_" }; - const QString IMAGE_FORMAT { ".png" }; QString pathToTestResultsDirectory; QStringList expectedImagesFilenames; diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 5ac7be3dd8..a5e13331dd 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -36,10 +36,6 @@ void AutoTester::on_createTestButton_clicked() { test->createTest(); } -void AutoTester::on_deleteOldSnapshotsButton_clicked() { - test->deleteOldSnapshots(); -} - void AutoTester::on_closeButton_clicked() { exit(0); } diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index acf34c60a3..938e7ca2d2 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -30,7 +30,6 @@ private slots: void on_createRecursiveScriptButton_clicked(); void on_createRecursiveScriptsRecursivelyButton_clicked(); void on_createTestButton_clicked(); - void on_deleteOldSnapshotsButton_clicked(); void on_closeButton_clicked(); void saveImage(int index); diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index 70060940d1..55c3897e58 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -30,8 +30,8 @@ - 360 - 210 + 20 + 30 220 40 @@ -44,7 +44,7 @@ 20 - 75 + 135 220 40 @@ -70,7 +70,7 @@ 23 - 40 + 100 131 20 @@ -95,19 +95,6 @@ 24 - - - - 360 - 270 - 220 - 40 - - - - Delete Old Snapshots - - From 4b3d63eea4952c46749593fdb49d1e79699172d2 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 6 Mar 2018 16:37:05 -0800 Subject: [PATCH 13/24] Added math.h to includes (MacOS build error). --- tools/auto-tester/src/Test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 53687fdeda..2b3d121638 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -21,6 +21,8 @@ #include "ui/AutoTester.h" extern AutoTester* autoTester; +#include + Test::Test() { QString regex(EXPECTED_IMAGE_PREFIX + QString("\\\\d").repeated(NUM_DIGITS) + ".png"); From da414b94fdd88344cb0e8f06c72dbfc575f6a18f Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 7 Mar 2018 10:47:37 -0800 Subject: [PATCH 14/24] WIP - adding the creation of recursive scripts. --- tools/auto-tester/src/Test.cpp | 45 +++++++++++++++++++++++++--------- tools/auto-tester/src/Test.h | 4 +++ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 2b3d121638..f514696ad3 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -84,7 +84,7 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) QImage expectedImage(expectedImagesFullFilenames[i]); if (resultImage.width() != expectedImage.width() || resultImage.height() != expectedImage.height()) { - messageBox.critical(0, "Internal error", "Images are not the same size"); + messageBox.critical(0, "Internal error #1", "Images are not the same size"); exit(-1); } @@ -92,7 +92,7 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) try { similarityIndex = imageComparer.compareImages(resultImage, expectedImage); } catch (...) { - messageBox.critical(0, "Internal error", "Image not in expected format"); + messageBox.critical(0, "Internal error #2", "Image not in expected format"); exit(-1); } @@ -139,20 +139,20 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage) { if (!QDir().exists(testResultsFolderPath)) { - messageBox.critical(0, "Internal error", "Folder " + testResultsFolderPath + " not found"); + messageBox.critical(0, "Internal error #3", "Folder " + testResultsFolderPath + " not found"); exit(-1); } QString failureFolderPath { testResultsFolderPath + "/" + "Failure_" + QString::number(index) }; if (!QDir().mkdir(failureFolderPath)) { - messageBox.critical(0, "Internal error", "Failed to create folder " + failureFolderPath); + messageBox.critical(0, "Internal error #4", "Failed to create folder " + failureFolderPath); exit(-1); } ++index; QFile descriptionFile(failureFolderPath + "/" + TEST_RESULTS_FILENAME); if (!descriptionFile.open(QIODevice::ReadWrite)) { - messageBox.critical(0, "Internal error", "Failed to create file " + TEST_RESULTS_FILENAME); + messageBox.critical(0, "Internal error #5", "Failed to create file " + TEST_RESULTS_FILENAME); exit(-1); } @@ -172,14 +172,14 @@ void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure te sourceFile = testFailure._pathname + testFailure._expectedImageFilename; destinationFile = failureFolderPath + "/" + "Expected Image.jpg"; if (!QFile::copy(sourceFile, destinationFile)) { - messageBox.critical(0, "Internal error", "Failed to copy " + sourceFile + " to " + destinationFile); + messageBox.critical(0, "Internal error #6", "Failed to copy " + sourceFile + " to " + destinationFile); exit(-1); } sourceFile = testFailure._pathname + testFailure._actualImageFilename; destinationFile = failureFolderPath + "/" + "Actual Image.jpg"; if (!QFile::copy(sourceFile, destinationFile)) { - messageBox.critical(0, "Internal error", "Failed to copy " + sourceFile + " to " + destinationFile); + messageBox.critical(0, "Internal error #7", "Failed to copy " + sourceFile + " to " + destinationFile); exit(-1); } @@ -282,7 +282,24 @@ bool Test::isAValidDirectory(QString pathname) { } void Test::importTest(QTextStream& textStream, const QString& testPathname) { - textStream << "Script.include(\"" << "file:///" << testPathname + "?raw=true\");" << endl; + // `testPathname` includes the full path to the test. We need the portion below (and including) `tests` + QStringList filenameParts = testPathname.split('/'); + int i{ 0 }; + while (i < filenameParts.length() && filenameParts[i] != "tests") { + ++i; + } + + if (i == filenameParts.length()) { + messageBox.critical(0, "Internal error #10", "Bad testPathname"); + exit(-1); + } + + QString filename; + for (int j = i; j < filenameParts.length(); ++j) { + filename += "/" + filenameParts[j]; + } + + textStream << "Script.include(\"" << "https://raw.githubusercontent.com/" << user << "/hifi_tests/" << branch << filename + "\");" << endl; } // Creates a single script in a user-selected folder. @@ -298,7 +315,7 @@ void Test::createRecursiveScript() { QFile allTestsFilename(topLevelDirectory + "/" + recursiveTestsFilename); if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { messageBox.critical(0, - "Internal Error", + "Internal Error #8", "Failed to create \"" + recursiveTestsFilename + "\" in directory \"" + topLevelDirectory + "\"" ); @@ -308,7 +325,7 @@ void Test::createRecursiveScript() { QTextStream textStream(&allTestsFilename); textStream << "// This is an automatically generated file, created by auto-tester" << endl << endl; - textStream << "var autoTester = Script.require(\"https://github.com/highfidelity/hifi_tests/blob/master/tests/utils/autoTester.js?raw=true\");" << endl; + textStream << "var autoTester = Script.require(\"https://raw.githubusercontent.com/" + user + "/hifi_tests/" + branch + "/tests/utils/autoTester.js\");" << endl; textStream << "autoTester.enableRecursive();" << endl << endl; QVector testPathnames; @@ -459,11 +476,17 @@ QString Test::getExpectedImagePartialSourceDirectory(QString filename) { QString filenameWithoutExtension = filename.split(".")[0]; QStringList filenameParts = filenameWithoutExtension.split("_"); + // Note that the topmost "tests" folder is assumed to be the root int i { 0 }; - while (filenameParts[i] != "tests") { + while (i < filenameParts.length() && filenameParts[i] != "tests") { ++i; } + if (i == filenameParts.length()) { + messageBox.critical(0, "Internal error #9", "Bad filename"); + exit(-1); + } + QString result = filenameParts[i]; for (int j = i + 1; j < filenameParts.length() - 1; ++j) { diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index b849ab577f..2a26e042b9 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -77,6 +77,10 @@ private: QStringList expectedImagesFilenames; QStringList expectedImagesFullFilenames; QStringList resultImagesFullFilenames; + + // Used for accessing GitHub + const QString user{ "NissimHadar" }; + const QString branch{ "addRecursionToAutotester" }; }; #endif // hifi_test_h \ No newline at end of file From 9bd7f31ff32b7a68bcc333e71217604194c5034f Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 7 Mar 2018 11:30:30 -0800 Subject: [PATCH 15/24] Now search for `tests` folder bottom-up. --- tools/auto-tester/src/Test.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index f514696ad3..8267435fad 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -476,13 +476,14 @@ QString Test::getExpectedImagePartialSourceDirectory(QString filename) { QString filenameWithoutExtension = filename.split(".")[0]; QStringList filenameParts = filenameWithoutExtension.split("_"); - // Note that the topmost "tests" folder is assumed to be the root - int i { 0 }; - while (i < filenameParts.length() && filenameParts[i] != "tests") { - ++i; + // Note that the bottom-most "tests" folder is assumed to be the root + // This is required because the tests folder is named hifi_tests + int i { filenameParts.length() - 1 }; + while (i >= 0 && filenameParts[i] != "tests") { + --i; } - if (i == filenameParts.length()) { + if (i < 0) { messageBox.critical(0, "Internal error #9", "Bad filename"); exit(-1); } From b47b512ab9a767039b629e26daa75b2d2528b025 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 7 Mar 2018 13:25:40 -0800 Subject: [PATCH 16/24] Completed recursive creation of recursive scripts. --- tools/auto-tester/src/Test.cpp | 58 ++++++++++++++++++++++++++++++---- tools/auto-tester/src/Test.h | 2 ++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 8267435fad..1078ce1bc4 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -311,6 +311,52 @@ void Test::createRecursiveScript() { return; } + createRecursiveScript(topLevelDirectory, true); +} + +// This method creates a `testRecursive.js` script in every sub-folder. +void Test::createRecursiveScriptsRecursively() { + // Select folder to start recursing from + QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the root folder for the recursive scripts", ".", QFileDialog::ShowDirsOnly); + if (topLevelDirectory == "") { + return; + } + + createRecursiveScript(topLevelDirectory, false); + + QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + while (it.hasNext()) { + QString directory = it.next(); + + // Only process directories + QDir dir(); + if (!isAValidDirectory(directory)) { + continue; + } + + // Only process directories that have sub-directories + bool hasNoSubDirectories{ true }; + QDirIterator it2(directory.toStdString().c_str(), QDirIterator::Subdirectories); + while (it2.hasNext()) { + QString directory2 = it2.next(); + + // Only process directories + QDir dir(); + if (isAValidDirectory(directory2)) { + hasNoSubDirectories = false; + break; + } + } + + if (!hasNoSubDirectories) { + createRecursiveScript(directory, false); + } + } + + messageBox.information(0, "Success", "Scripts have been created"); +} + +void Test::createRecursiveScript(QString topLevelDirectory, bool interactiveMode) { const QString recursiveTestsFilename("testRecursive.js"); QFile allTestsFilename(topLevelDirectory + "/" + recursiveTestsFilename); if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { @@ -350,7 +396,7 @@ void Test::createRecursiveScript() { continue; } - const QString testPathname{ directory + "/" + TEST_FILENAME }; + const QString testPathname { directory + "/" + TEST_FILENAME }; QFileInfo fileInfo(testPathname); if (fileInfo.exists()) { // Current folder contains a test @@ -360,7 +406,7 @@ void Test::createRecursiveScript() { } } - if (testPathnames.length() <= 0) { + if (interactiveMode && testPathnames.length() <= 0) { messageBox.information(0, "Failure", "No \"" + TEST_FILENAME + "\" files found"); allTestsFilename.close(); return; @@ -370,10 +416,10 @@ void Test::createRecursiveScript() { textStream << "autoTester.runRecursive();" << endl; allTestsFilename.close(); - messageBox.information(0, "Success", "Script has been created"); -} - -void Test::createRecursiveScriptsRecursively() { + + if (interactiveMode) { + messageBox.information(0, "Success", "Script has been created"); + } } void Test::createTest() { diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 2a26e042b9..411f27eae6 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -28,6 +28,8 @@ public: void createRecursiveScript(); void createRecursiveScriptsRecursively(); + void createRecursiveScript(QString topLevelDirectory, bool interactiveMode); + void createTest(); void deleteOldSnapshots(); From a4854839a4c3148e91d1a103f2b5b634f581fe14 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Wed, 7 Mar 2018 17:45:10 -0800 Subject: [PATCH 17/24] Enable user selection of destination folder when creating a test. --- tools/auto-tester/src/Test.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 1078ce1bc4..c14c6b9437 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -430,6 +430,11 @@ void Test::createTest() { return; } + QString imageDestinationDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder to save the test images", ".", QFileDialog::ShowDirsOnly); + if (imageDestinationDirectory == "") { + return; + } + QStringList sortedImageFilenames = createListOfAll_imagesInDirectory("jpg", imageSourceDirectory); int i = 1; @@ -442,7 +447,6 @@ void Test::createTest() { exit(-1); } QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".png"; - QString imageDestinationDirectory = getExpectedImageDestinationDirectory(currentFilename); QString fullNewFileName = imageDestinationDirectory + "/" + newFilename; try { From 47b08d722880ba24c94b8fd730c049d221499f13 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 8 Mar 2018 15:38:00 -0800 Subject: [PATCH 18/24] Update Hifi icon --- android/app/src/main/AndroidManifest.xml | 4 ++-- .../app/src/main/res/drawable/ic_launcher.xml | 17 +++++++++++++++++ android/app/src/main/res/drawable/icon.png | Bin 9914 -> 0 bytes .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 5195 -> 0 bytes .../main/res/mipmap-hdpi/ic_launcher_round.png | Bin 5023 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 4333 -> 0 bytes .../main/res/mipmap-mdpi/ic_launcher_round.png | Bin 4369 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 5931 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 5635 -> 0 bytes .../src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin 7424 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 6905 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 9114 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 8380 -> 0 bytes 13 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 android/app/src/main/res/drawable/ic_launcher.xml delete mode 100644 android/app/src/main/res/drawable/icon.png delete mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5e93bdffa3..b3a8c87649 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -19,9 +19,9 @@ android:allowBackup="true" android:screenOrientation="unspecified" android:theme="@style/NoSystemUI" - android:icon="@mipmap/ic_launcher" + android:icon="@drawable/ic_launcher" android:launchMode="singleTop" - android:roundIcon="@mipmap/ic_launcher_round"> + android:roundIcon="@drawable/ic_launcher"> diff --git a/android/app/src/main/res/drawable/ic_launcher.xml b/android/app/src/main/res/drawable/ic_launcher.xml new file mode 100644 index 0000000000..03b1edc4e9 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/icon.png b/android/app/src/main/res/drawable/icon.png deleted file mode 100644 index 70aaf9b4ed60a80081821907d53086beb249eb3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9914 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 P0B~TR#op}QjIjR)wK5d} diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index d376d7af8852da4934eed5fb8b3fa718a6977d33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5195 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 FV1h;$)&2kg diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index 81a137957d489151137f4ec48490fed96ddf0373..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5023 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

FpAv>ypK&zL`d0&`aN|8w zg&BM-aN6V<;pwx&q4TQIN0n!uPRC=Ub~O;&_$jfkK1o>Hey#;x7QxW^tkV(Sf2$~k zvXWzzZQm#((M$ExvU3CDCKVW?E76KdkdbIQ5T^U#bhYEOG?Uu?8_C~)>~vb1zjfoW z&xK*G5N6;HzdI-f<#!w9qHMcFrL2i4H5MonQY%8rkXLUcaNSm*5h=F`!~98TdedOU bmA?l7BAQ7ybVso%00000NkvXXu0mjfd0HQi diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index d032c300142532c9cd1d2679277d365c20f4e964..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4369 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 N002ovPDHLkV1nK$3jhEB diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index 3cccf1037b45e43400c9648cdc9cc129d8df2e86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5635 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 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index e97062e0ee222ba85204e3e6b2758c622eddd6d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7424 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 diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index f01203c738e29c6371cd4185ab10c9a817ea33d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9114 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 Tu8OV$002TsQ?W|kJmh}>;TD+- From 77901e5089b38ae91b810d23d0b4c80f1c8c89dc Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Thu, 8 Mar 2018 20:11:35 -0800 Subject: [PATCH 19/24] Corrected MacOS warnings. --- tools/auto-tester/src/Test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index c14c6b9437..9bced3d1fc 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -329,7 +329,7 @@ void Test::createRecursiveScriptsRecursively() { QString directory = it.next(); // Only process directories - QDir dir(); + QDir dir; if (!isAValidDirectory(directory)) { continue; } @@ -341,7 +341,7 @@ void Test::createRecursiveScriptsRecursively() { QString directory2 = it2.next(); // Only process directories - QDir dir(); + QDir dir; if (isAValidDirectory(directory2)) { hasNoSubDirectories = false; break; From 317d9a8dbc40d1c28d441c35b758db39037645a5 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 9 Mar 2018 11:45:39 -0800 Subject: [PATCH 20/24] Correct can cast shadow flag being visible on entities that can't cast shadows. --- scripts/system/html/entityProperties.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 7389442649..82a450bedd 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -313,7 +313,7 @@ -

+
From 10447bf10e6c4a370b842a2d11039a376af1f25f Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 9 Mar 2018 13:04:04 -0800 Subject: [PATCH 21/24] Fix the fact that all avatars should cast shadows, not just MyAvatar. since this is always a SkeletonMOdel class let s just turn it on by default there --- interface/src/avatar/MyAvatar.cpp | 6 ++---- .../avatars-renderer/src/avatars-renderer/SkeletonModel.cpp | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a5e24b8707..9620a2dcec 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1115,7 +1115,6 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) { void MyAvatar::setEnableMeshVisible(bool isEnabled) { _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); - _skeletonModel->setCanCastShadow(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); } void MyAvatar::setEnableInverseKinematics(bool isEnabled) { @@ -1468,7 +1467,6 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { int skeletonModelChangeCount = _skeletonModelChangeCount; Avatar::setSkeletonModelURL(skeletonModelURL); _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); - _skeletonModel->setCanCastShadow(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); _headBoneSet.clear(); _cauterizationNeedsUpdate = true; @@ -2043,8 +2041,8 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) { _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); - _attachmentModels[i]->setCanCastShadow(shouldDrawHead, qApp->getMain3DScene(), - render::ItemKey::TAG_BITS_NONE, true); + _attachmentModels[i]->setCanCastShadow(shouldDrawHead, qApp->getMain3DScene(), + render::ItemKey::TAG_BITS_NONE, true); } } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp index b2a494230b..b25df633c0 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp @@ -33,6 +33,10 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : { // SkeletonModels, and by extention Avatars, use Dual Quaternion skinning. _useDualQuaternionSkinning = true; + + // Avatars all cast shadow + _canCastShadow = true; + assert(_owningAvatar); } From fec30b83637683fd75b2e20d1e210cc8554c02e9 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 9 Mar 2018 15:04:14 -0800 Subject: [PATCH 22/24] Fixing the menu for Shadow and AO to do the correct path to engine config --- interface/src/Menu.cpp | 45 +++++++++++++++++++------- interface/src/Menu.h | 2 +- interface/src/ui/PreferencesDialog.cpp | 28 ---------------- 3 files changed, 34 insertions(+), 41 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ca6f7a31d1..733fd785d4 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -45,6 +45,9 @@ #include "LocationBookmarks.h" #include "DeferredLightingEffect.h" +#include "AmbientOcclusionEffect.h" +#include "RenderShadowTask.h" + #if defined(Q_OS_MAC) || defined(Q_OS_WIN) #include "SpeechRecognizer.h" #endif @@ -361,18 +364,6 @@ Menu::Menu() { // Developer menu ---------------------------------- MenuWrapper* developerMenu = addMenu("Developer", "Developer"); - // Developer > Graphics - MenuWrapper* graphicsOptionsMenu = developerMenu->addMenu("Render"); - action = addCheckableActionToQMenuAndActionHash(graphicsOptionsMenu, MenuOption::Shadows, 0, true); - connect(action, &QAction::triggered, [action] { - DependencyManager::get()->setShadowMapEnabled(action->isChecked()); - }); - - action = addCheckableActionToQMenuAndActionHash(graphicsOptionsMenu, MenuOption::AmbientOcclusion, 0, false); - connect(action, &QAction::triggered, [action] { - DependencyManager::get()->setAmbientOcclusionEnabled(action->isChecked()); - }); - // Developer > UI >>> MenuWrapper* uiOptionsMenu = developerMenu->addMenu("UI"); action = addCheckableActionToQMenuAndActionHash(uiOptionsMenu, MenuOption::DesktopTabletToToolbar, 0, @@ -389,6 +380,36 @@ Menu::Menu() { // Developer > Render >>> MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render"); + action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, true); + connect(action, &QAction::triggered, [action] { + auto renderConfig = qApp->getRenderEngine()->getConfiguration(); + if (renderConfig) { + auto mainViewShadowTaskConfig = renderConfig->getConfig("RenderMainView.RenderShadowTask"); + if (mainViewShadowTaskConfig) { + if (action->isChecked()) { + mainViewShadowTaskConfig->setPreset("Enabled"); + } else { + mainViewShadowTaskConfig->setPreset("None"); + } + } + } + }); + + action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion, 0, false); + connect(action, &QAction::triggered, [action] { + auto renderConfig = qApp->getRenderEngine()->getConfiguration(); + if (renderConfig) { + auto mainViewAmbientOcclusionConfig = renderConfig->getConfig("RenderMainView.AmbientOcclusion"); + if (mainViewAmbientOcclusionConfig) { + if (action->isChecked()) { + mainViewAmbientOcclusionConfig->setPreset("Enabled"); + } else { + mainViewAmbientOcclusionConfig->setPreset("None"); + } + } + } + }); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DefaultSkybox, 0, true); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 1d37b74ffe..cf9eed1a27 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -205,7 +205,7 @@ namespace MenuOption { const QString DesktopTabletToToolbar = "Desktop Tablet Becomes Toolbar"; const QString HMDTabletToToolbar = "HMD Tablet Becomes Toolbar"; const QString Shadows = "Shadows"; - const QString AmbientOcclusion = "AmbientOcclusion"; + const QString AmbientOcclusion = "Ambient Occlusion"; } #endif // hifi_Menu_h diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 48b56c7ced..4c233b986c 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -24,10 +24,6 @@ #include "SnapshotAnimated.h" #include "UserActivityLogger.h" -#include "AmbientOcclusionEffect.h" -#include "AntialiasingEffect.h" -#include "RenderShadowTask.h" - void setupPreferences() { auto preferences = DependencyManager::get(); auto nodeList = DependencyManager::get(); @@ -295,30 +291,6 @@ void setupPreferences() { } #endif - - { - static const QString RENDER("Graphics"); - auto renderConfig = qApp->getRenderEngine()->getConfiguration(); - if (renderConfig) { - auto mainViewAmbientOcclusionConfig = renderConfig->getConfig("RenderMainView.AmbientOcclusion"); - if (mainViewAmbientOcclusionConfig) { - auto getter = [mainViewAmbientOcclusionConfig]()->QString { return mainViewAmbientOcclusionConfig->getPreset(); }; - auto setter = [mainViewAmbientOcclusionConfig](QString preset) { mainViewAmbientOcclusionConfig->setPreset(preset); }; - auto preference = new ComboBoxPreference(RENDER, "Ambient occlusion", getter, setter); - preference->setItems(mainViewAmbientOcclusionConfig->getPresetList()); - preferences->addPreference(preference); - } - - auto mainViewShadowConfig = renderConfig->getConfig("RenderMainView.RenderShadowTask"); - if (mainViewShadowConfig) { - auto getter = [mainViewShadowConfig]()->QString { return mainViewShadowConfig->getPreset(); }; - auto setter = [mainViewShadowConfig](QString preset) { mainViewShadowConfig->setPreset(preset); }; - auto preference = new ComboBoxPreference(RENDER, "Shadows", getter, setter); - preference->setItems(mainViewShadowConfig->getPresetList()); - preferences->addPreference(preference); - } - } - } { static const QString NETWORKING("Networking"); From c78df4d96724589e690351b26db3d70fa75132e7 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 9 Mar 2018 15:41:56 -0800 Subject: [PATCH 23/24] Setting the correct Job config for ssao check box and fixing typo --- interface/src/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 733fd785d4..fa0e8087f0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -399,7 +399,7 @@ Menu::Menu() { connect(action, &QAction::triggered, [action] { auto renderConfig = qApp->getRenderEngine()->getConfiguration(); if (renderConfig) { - auto mainViewAmbientOcclusionConfig = renderConfig->getConfig("RenderMainView.AmbientOcclusion"); + auto mainViewAmbientOcclusionConfig = renderConfig->getConfig("RenderMainView.AmbientOcclusion"); if (mainViewAmbientOcclusionConfig) { if (action->isChecked()) { mainViewAmbientOcclusionConfig->setPreset("Enabled"); From 84cc4c18a40c7025da738137da87ee4bc91628bc Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Fri, 9 Mar 2018 18:13:26 -0800 Subject: [PATCH 24/24] Added date/time to testResultsFolder. --- tools/auto-tester/src/Test.cpp | 22 +++++++--------------- tools/auto-tester/src/Test.h | 7 ++++--- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 9bced3d1fc..347cfd90dc 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -31,21 +31,13 @@ Test::Test() { mismatchWindow.setModal(true); } -bool Test::createTestResultsFolderPathIfNeeded(QString directory) { - // The test results folder is located in the root of the tests (i.e. for recursive test evaluation) - if (testResultsFolderPath == "") { - testResultsFolderPath = directory + "/" + TEST_RESULTS_FOLDER; - QDir testResultsFolder(testResultsFolderPath); +bool Test::createTestResultsFolderPath(QString directory) { + QDateTime now = QDateTime::currentDateTime(); + testResultsFolderPath = directory + "/" + TEST_RESULTS_FOLDER + "--" + now.toString(DATETIME_FORMAT); + QDir testResultsFolder(testResultsFolderPath); - if (testResultsFolder.exists()) { - testResultsFolder.removeRecursively(); - } - - // Create a new test results folder - return QDir().mkdir(testResultsFolderPath); - } else { - return true; - } + // Create a new test results folder + return QDir().mkdir(testResultsFolderPath); } void Test::zipAndDeleteTestResultsFolder() { @@ -194,7 +186,7 @@ void Test::startTestsEvaluation() { } // Quit if test results folder could not be created - if (!createTestResultsFolderPathIfNeeded(pathToTestResultsDirectory)) { + if (!createTestResultsFolderPath(pathToTestResultsDirectory)) { return; } diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 411f27eae6..cd5075002a 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -43,7 +43,7 @@ public: void appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage); - bool createTestResultsFolderPathIfNeeded(QString directory); + bool createTestResultsFolderPath(QString directory); void zipAndDeleteTestResultsFolder(); bool isAValidDirectory(QString pathname); @@ -81,8 +81,9 @@ private: QStringList resultImagesFullFilenames; // Used for accessing GitHub - const QString user{ "NissimHadar" }; - const QString branch{ "addRecursionToAutotester" }; + const QString user { "NissimHadar" }; + const QString branch { "addRecursionToAutotester" }; + const QString DATETIME_FORMAT { "yyyy-MM-dd_hh-mm-ss" }; }; #endif // hifi_test_h \ No newline at end of file