ScriptReporter.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #pragma once
  9. #include <AzCore/Debug/TraceMessageBus.h>
  10. #include <AzFramework/StringFunc/StringFunc.h>
  11. #include <Atom/Utils/ImageComparison.h>
  12. #include <Automation/ImageComparisonConfig.h>
  13. #include <Utils/ImGuiMessageBox.h>
  14. namespace AtomSampleViewer
  15. {
  16. struct ImageComparisonToleranceLevel;
  17. namespace ScreenshotPaths
  18. {
  19. //! Returns the path to the screenshots capture folder.
  20. //! @resolvePath indicates whether to call ResolvePath() which will produce a full path, or keep the shorter asset folder path.
  21. AZStd::string GetScreenshotsFolder(bool resolvePath);
  22. //! Returns the path to the local baseline folder, which stores copies of screenshots previously taken on this machine.
  23. //! @resolvePath indicates whether to call ResolvePath() which will produce a full path, or keep the shorter asset folder path.
  24. AZStd::string GetLocalBaselineFolder(bool resolvePath);
  25. //! Returns the path to the official baseline folder, which stores copies of expected screenshots saved in source control.
  26. //! @resolvePath indicates whether to call ResolvePath() which will produce a full path, or keep the shorter asset folder path.
  27. AZStd::string GetOfficialBaselineFolder(bool resolvePath);
  28. //! Returns the path to the local baseline image that corresponds to @forScreenshotFile
  29. AZStd::string GetLocalBaseline(const AZStd::string& forScreenshotFile);
  30. //! Returns the path to the official baseline image that corresponds to @forScreenshotFile
  31. AZStd::string GetOfficialBaseline(const AZStd::string& forScreenshotFile);
  32. }
  33. //! Collects data about each script run by the ScriptManager.
  34. //! This includes counting errors, checking screenshots, and providing a final report dialog.
  35. class ScriptReporter
  36. {
  37. public:
  38. //! Set the list of available tolerance levels, so the report can suggest an alternate level that matches the actual results.
  39. void SetAvailableToleranceLevels(const AZStd::vector<ImageComparisonToleranceLevel>& toleranceLevels);
  40. //! Clears all recorded data.
  41. void Reset();
  42. //! Invalidates the final results when displaying a report to the user. This can be used to highlight
  43. //! local changes that were made, and remind the user that these results should not be considered official.
  44. //! Use an empty string to clear the invalidation.
  45. void SetInvalidationMessage(const AZStd::string& message);
  46. //! Indicates that a new script has started processing.
  47. //! Any subsequent errors will be included as part of this script's report.
  48. void PushScript(const AZStd::string& scriptAssetPath);
  49. //! Indicates that the current script has finished executing.
  50. //! Any subsequent errors will be included as part of the prior script's report.
  51. void PopScript();
  52. //! Returns whether there are active processing scripts (i.e. more PushScript() calls than PopScript() calls)
  53. bool HasActiveScript() const;
  54. //! Indicates that a new screenshot is about to be captured.
  55. bool AddScreenshotTest(const AZStd::string& path);
  56. //! Check the latest screenshot using default thresholds.
  57. void CheckLatestScreenshot(const ImageComparisonToleranceLevel* comparisonPreset);
  58. //! Opens the script report dialog.
  59. //! This displays all the collected script reporting data, provides links to tools for analyzing data like
  60. //! viewing screenshot diffs. It can be left open during processing and will update in real-time.
  61. void OpenReportDialog();
  62. //! Called every frame to update the ImGui dialog
  63. void TickImGui();
  64. //! Returns true if there are any errors or asserts in the script report
  65. bool HasErrorsAssertsInReport() const;
  66. // For exporting test results
  67. void ExportTestResults();
  68. struct ImageComparisonResult
  69. {
  70. enum class ResultCode
  71. {
  72. None,
  73. Pass,
  74. FileNotFound,
  75. FileNotLoaded,
  76. WrongSize,
  77. WrongFormat,
  78. NullImageComparisonToleranceLevel,
  79. ThresholdExceeded
  80. };
  81. ResultCode m_resultCode = ResultCode::None;
  82. float m_standardDiffScore = 0.0f;
  83. float m_filteredDiffScore = 0.0f; //!< The diff score after filtering out visually imperceptible differences.
  84. float m_finalDiffScore = 0.0f; //! The diff score that was used for comparison. May be m_diffScore or m_filteredDiffScore.
  85. AZStd::string GetSummaryString() const;
  86. };
  87. //! Records all the information about a screenshot comparison test.
  88. struct ScreenshotTestInfo
  89. {
  90. AZStd::string m_screenshotFilePath;
  91. AZStd::string m_officialBaselineScreenshotFilePath; //!< The path to the official baseline image that is checked into source control
  92. AZStd::string m_localBaselineScreenshotFilePath; //!< The path to a local baseline image that was established by the user
  93. ImageComparisonToleranceLevel m_toleranceLevel; //!< Tolerance for checking against the official baseline image
  94. ImageComparisonResult m_officialComparisonResult; //!< Result of comparing against the official baseline image, for reporting test failure
  95. ImageComparisonResult m_localComparisonResult; //!< Result of comparing against a local baseline, for reporting warnings
  96. };
  97. //! Records all the information about a single test script.
  98. struct ScriptReport : public AZ::Debug::TraceMessageBus::Handler
  99. {
  100. ~ScriptReport()
  101. {
  102. AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
  103. }
  104. bool OnPreAssert(const char* /*fileName*/, int /*line*/, const char* /*func*/, [[maybe_unused]] const char* message) override
  105. {
  106. ++m_assertCount;
  107. return false;
  108. }
  109. bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) override
  110. {
  111. if (AZStd::string::npos == AzFramework::StringFunc::Find(message, "Screenshot check failed"))
  112. {
  113. ++m_generalErrorCount;
  114. }
  115. else
  116. {
  117. ++m_screenshotErrorCount;
  118. }
  119. return false;
  120. }
  121. bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) override
  122. {
  123. if (AZStd::string::npos == AzFramework::StringFunc::Find(message, "Screenshot does not match the local baseline"))
  124. {
  125. ++m_generalWarningCount;
  126. }
  127. else
  128. {
  129. ++m_screenshotWarningCount;
  130. }
  131. return false;
  132. }
  133. AZStd::string m_scriptAssetPath;
  134. uint32_t m_assertCount = 0;
  135. uint32_t m_generalErrorCount = 0;
  136. uint32_t m_screenshotErrorCount = 0;
  137. uint32_t m_generalWarningCount = 0;
  138. uint32_t m_screenshotWarningCount = 0;
  139. AZStd::vector<ScreenshotTestInfo> m_screenshotTests;
  140. };
  141. const AZStd::vector<ScriptReport>& GetScriptReport() const { return m_scriptReports; }
  142. private:
  143. // Reports a script error using standard formatting that matches ScriptManager
  144. enum class TraceLevel
  145. {
  146. Error,
  147. Warning
  148. };
  149. // Controls which results are shown to the user
  150. // Must match static const char* DiplayOptions in .cpp file
  151. enum DisplayOption : int
  152. {
  153. AllResults,
  154. WarningsAndErrors,
  155. ErrorsOnly
  156. };
  157. static void ReportScriptError(const AZStd::string& message);
  158. static void ReportScriptWarning(const AZStd::string& message);
  159. static void ReportScriptIssue(const AZStd::string& message, TraceLevel traceLevel);
  160. static void ReportScreenshotComparisonIssue(const AZStd::string& message, const AZStd::string& expectedImageFilePath, const AZStd::string& actualImageFilePath, TraceLevel traceLevel);
  161. // Loads image data from a .png file.
  162. // @param imageComparisonResult will be set to an error code if the function fails
  163. // @param path the path the .png file
  164. // @param buffer will be filled with the raw image data from the .png file
  165. // @param size will be set to the image size of the .png file
  166. // @param format will be set to the pixel format of the .png file
  167. // @return true if the file was loaded successfully
  168. static bool LoadPngData(ImageComparisonResult& imageComparisonResult, const AZStd::string& path, AZStd::vector<uint8_t>& buffer, AZ::RHI::Size& size, AZ::RHI::Format& format, TraceLevel traceLevel);
  169. // Compares two image files and updates the ImageComparisonResult accordingly.
  170. // Returns false if an error prevented the comparison.
  171. static bool DiffImages(ImageComparisonResult& imageComparisonResult, const AZStd::string& expectedImageFilePath, const AZStd::string& actualImageFilePath, TraceLevel traceLevel);
  172. // Copies all captured screenshots to the local baseline folder. These can be used as an alternative to the central baseline for comparison.
  173. void UpdateAllLocalBaselineImages();
  174. // Copies a single captured screenshot to the local baseline folder. This can be used as an alternative to the central baseline for comparison.
  175. bool UpdateLocalBaselineImage(ScreenshotTestInfo& screenshotTest, bool showResultDialog);
  176. // Copies a single captured screenshot to the official baseline source folder.
  177. bool UpdateSourceBaselineImage(ScreenshotTestInfo& screenshotTest, bool showResultDialog);
  178. // Clears comparison result to passing with no errors or warnings
  179. void ClearImageComparisonResult(ImageComparisonResult& comparisonResult);
  180. // Show a message box to let the user know the results of updating local baseline images
  181. void ShowUpdateLocalBaselineResult(int successCount, int failureCount);
  182. const ImageComparisonToleranceLevel* FindBestToleranceLevel(float diffScore, bool filterImperceptibleDiffs) const;
  183. void ShowReportDialog();
  184. void ShowDiffButton(const char* buttonLabel, const AZStd::string& imagePathA, const AZStd::string& imagePathB);
  185. // Generates a path to the exported test results file.
  186. AZStd::string GenerateAndCreateExportedTestResultsPath() const;
  187. ScriptReport* GetCurrentScriptReport();
  188. ImGuiMessageBox m_messageBox;
  189. AZStd::vector<ImageComparisonToleranceLevel> m_availableToleranceLevels;
  190. AZStd::string m_invalidationMessage;
  191. AZStd::vector<ScriptReport> m_scriptReports; //< Tracks errors for the current active script
  192. AZStd::vector<size_t> m_currentScriptIndexStack; //< Tracks which of the scripts in m_scriptReports is currently active
  193. bool m_showReportDialog = false;
  194. DisplayOption m_displayOption = DisplayOption::AllResults;
  195. bool m_forceShowUpdateButtons = false; //< By default, the "Update" buttons are visible only for failed screenshots. This forces them to be visible.
  196. AZStd::string m_officialBaselineSourceFolder; //< Used for updating official baseline screenshots
  197. AZStd::string m_exportedTestResultsPath = "Click the 'Export Test Results' button."; //< Path to exported test results file (if exported).
  198. };
  199. } // namespace AtomSampleViewer