1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE
4 # Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
5 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 # Author : A. Bruneton
25 import unittest, sys, os, filecmp, shutil, tempfile
26 from pyqtside.QtWidgets import QApplication
27 from pyqtside.QtGui import QPixmap, QPainter
28 from pyqtside.QtCore import QTimer
30 from curveplot.PlotController import PlotController
31 from curveplot.XYView import XYView
32 from PyQt5.Qt import QMainWindow
35 func.__runOnly__ = True
38 def processDecorator(mod_name):
39 """ Little trick to be able to mark a test with the decorator
41 If one or more tests bear this decorator, only them will be run
45 for name, obj in inspect.getmembers(sys.modules[mod_name]):
46 if name == "PlotTest" and inspect.isclass(obj):
48 if p.startswith("test") and hasattr(obj.__dict__[p], "__runOnly__"):
52 for name, obj in inspect.getmembers(sys.modules[mod_name]):
53 if name == "PlotTest" and inspect.isclass(obj):
56 if p.startswith("test") and not hasattr(obj.__dict__[p], "__runOnly__"):
59 class PlotTestBase(unittest.TestCase):
60 """ Unit test suite for the curve plotter. This class deals with the set up and the screenshot generation/
61 comparison. The tests themselves are stored in the derived class PlotTest below.
63 The class variable below can be turned on to regenerate base line files (reference images).
64 All baselines start with the name of the corresponding test, plus a possible suffix.
65 The baselines directory is set relative to the path of this script.
67 REBUILD_BASELINES = False
69 __BASE_LINE_DIR = "baselines"
72 def __init__(self, methodName):
73 unittest.TestCase.__init__(self, methodName)
75 if self.REBUILD_BASELINES:
76 self.tmpBaselineDir = os.path.join(tempfile.gettempdir(), "curveplot_baselines")
77 if not os.path.isdir(self.tmpBaselineDir):
78 os.mkdir(self.tmpBaselineDir)
79 print("### Rebuilding base lines. Reference files will be saved to '%s'" % self.tmpBaselineDir)
81 PlotController.WITH_CURVE_BROWSER = True
82 XYView._DEFAULT_LEGEND_STATE = True # always show legend by default
83 self._this_dir = os.path.dirname(os.path.realpath(__file__))
87 from curveplot.SalomePyQt_MockUp import SalomePyQt
88 from curveplot.TableModel import TableModel
89 from curveplot.CurveModel import CurveModel
90 from curveplot.XYPlotSetModel import XYPlotSetModel
91 from curveplot.TestDesktop import TestDesktop
95 if not self.REBUILD_BASELINES:
96 self.tmpDir = tempfile.mkdtemp(prefix="curveplot_tests")
101 self.app = QApplication(sys.argv)
102 desktop = TestDesktop(None)
103 self.sgPyQt = SalomePyQt(desktop)
104 desktop._sgPyQt = self.sgPyQt
106 self.plotController = PlotController.GetInstance(self.sgPyQt)
107 desktop.resize(800, 600)
109 self._execQtWasCalled = False # Used to automatically finish Qt execution loop on tests not doing a screenshot
111 # Reset some class var to make sure IDs appearing in screenshots do not depend on test seq order:
112 CurveModel.START_ID = -1
113 TableModel.START_ID = -1
114 XYPlotSetModel.START_ID = -1
117 if not self.REBUILD_BASELINES:
118 # Clean up temp dir where the file comparison has been made:
120 shutil.rmtree(self.tmpDir, False)
121 if not self._execQtWasCalled:
122 self._execQt(withShot=False)
123 PlotController.Destroy()
125 def getTestName(self):
126 return self.id().split(".")[-1]
128 def saveCurrentPix(self, direct, suffix):
129 fileName = os.path.join(direct, self.getTestName() + suffix + "." + self.__FORMAT)
130 self.qpixmap.save(fileName, self.__FORMAT)
133 def _execQt(self, withShot=False):
135 QTimer.singleShot(50, self._shotEvent) # take picture
136 QTimer.singleShot(200, self.app.quit) # quit
137 self.app.exec_() # will hang till quit is fired
139 # Important make sure previous app is properly killed before launching next test!
140 # Qt doesn't like multiple running instance
144 def areScreenshotEqual(self, widget):
145 """ Finish the launching of the Qt application so that the widgets and the curve have a chance to display
146 and trigger snapshot comparison """
148 self._execQtWasCalled = True
149 self._execQt(withShot=True)
152 def _shotEvent(self):
153 self.retValue = self._snapAndCompare(self.saveW)
155 def _snapAndCompare(self, widget, suffix=""):
156 """ Test equality between a reference file saved in the baseline directory, and whose name is built as
157 "<test_name><suffix>.png"
158 and the file generated on the fly by taking a snapshot of the widget provided in argument.
159 The comparison is made in a temp dir which is kept if the file differ.
163 self.qpixmap = QPixmap(widget.size())
165 widget.render(self.qpixmap)
166 #self.qpixmap = widget.grab()
168 # Nothing to compare if rebuilding base lines, just saving file:
169 if self.REBUILD_BASELINES:
170 self.saveCurrentPix(self.tmpBaselineDir, suffix)
173 gen_path = self.saveCurrentPix(self.tmpDir, suffix)
174 base_ref = os.path.join(self._this_dir, self.__BASE_LINE_DIR, self.getTestName() + suffix)
176 for ref_path in glob.glob("%s_*.%s" % (base_ref, self.__FORMAT)):
178 ret = filecmp.cmp(ref_path, gen_path, shallow=False)
184 # Keep file if assert is false
186 print("[%s] -- Failed screenshot equality, or unable to open baseline file - directory is kept alive: %s" % (self.getTestName(), self.tmpDir))
189 def showTabWidget(self):
190 tabW = self.plotController._sgPyQt._tabWidget
191 # No simpler way found so far:
195 def getBrowserWidget(self):
196 return self.plotController._curveBrowserView._treeWidget