Salome HOME
Merge multi-study removal branch.
[modules/gui.git] / tools / CurvePlot / src / python / test / PlotTestBase.py
1 # -*- coding: utf-8 -*-
2 #  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
3 #
4 #  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
5 #  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 #
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.
11 #
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.
16 #
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
20 #
21 #  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 #
23 # Author : A. Bruneton
24 #
25 import unittest, sys, os, filecmp, shutil, tempfile
26 from pyqtside.QtGui import QApplication, QPixmap, QPainter
27 from PlotController import PlotController
28 from XYView import XYView
29
30 def runOnly(func):
31   func.__runOnly__ = True
32   return func
33
34 def processDecorator(mod_name):
35   """ Little trick to be able to mark a test with the decorator
36     @runOnly
37       If one or more tests bear this decorator, only them will be run
38   """
39   import inspect
40   someRunOnly = False
41   for name, obj in inspect.getmembers(sys.modules[mod_name]):
42     if name == "PlotTest" and inspect.isclass(obj):
43       for p in dir(obj):
44         if p.startswith("test") and hasattr(obj.__dict__[p], "__runOnly__"):
45           someRunOnly = True
46           break
47   if someRunOnly:
48     for name, obj in inspect.getmembers(sys.modules[mod_name]):
49       if name == "PlotTest" and inspect.isclass(obj):
50         for p in dir(obj):
51           # Note the "not":
52           if p.startswith("test") and not hasattr(obj.__dict__[p], "__runOnly__"):
53             delattr(obj, p)
54  
55 class PlotTestBase(unittest.TestCase):
56   """ Unit test suite for the curve plotter. This class deals with the set up and the screenshot generation/
57   comparison. The tests themselves are stored in the derived class PlotTest below.
58    
59   The class variable below can be turned on to regenerate base line files (reference images).
60   All baselines start with the name of the corresponding test, plus a possible suffix.
61   The baselines directory is set relative to the path of this script.
62   """
63   REBUILD_BASELINES = False
64   
65   __BASE_LINE_DIR = "baselines"
66   __FORMAT = "png"
67   
68   def __init__(self, methodName):
69     unittest.TestCase.__init__(self, methodName)
70      
71     if self.REBUILD_BASELINES:
72       self.tmpBaselineDir = os.path.join(tempfile.gettempdir(), "curveplot_baselines")
73       if not os.path.isdir(self.tmpBaselineDir):
74         os.mkdir(self.tmpBaselineDir)
75       print "### Rebuilding base lines. Reference files will be saved to '%s'" % self.tmpBaselineDir
76        
77     PlotController.WITH_CURVE_BROWSER = True
78     XYView._DEFAULT_LEGEND_STATE = True   # always show legend by default
79     self._this_dir = os.path.dirname(os.path.realpath(__file__))
80     
81 #     import matplotlib as mpl
82 #     mpl.use('Agg')
83   
84   def setUp(self):
85     from SalomePyQt_MockUp import SalomePyQt
86     from TableModel import TableModel
87     from CurveModel import CurveModel
88     from XYPlotSetModel import XYPlotSetModel
89
90     self.qpixmap = None
91     self.keepDir = False
92     if not self.REBUILD_BASELINES:
93       self.tmpDir = tempfile.mkdtemp(prefix="curveplot_tests")
94     else:
95       self.tmpDir = None
96     # Minimal UI setup:
97     self.sgPyQt = SalomePyQt()
98     # Reinstanciate from scratch the PlotController:
99     self.plotController = PlotController.GetInstance(self.sgPyQt)
100     self.plotController.setFixedSizeWidget()
101     # Reset some class var to make sure IDs appearing in screenshots do not depend on test seq order:
102     CurveModel.START_ID = -1
103     TableModel.START_ID = -1
104     XYPlotSetModel.START_ID = -1
105         
106   def tearDown(self):
107     if not self.REBUILD_BASELINES:
108       # Clean up temp dir where the file comparison has been made:
109       if not self.keepDir:
110         shutil.rmtree(self.tmpDir, False)
111     PlotController.Destroy()
112
113   def getTestName(self):
114     return self.id().split(".")[-1]
115
116   def saveCurrentPix(self, direct, suffix):
117     fileName = os.path.join(direct, self.getTestName() + suffix + "." + self.__FORMAT)
118     self.qpixmap.save(fileName, self.__FORMAT)
119     return fileName
120
121   def areScreenshotEqual(self, widget, suffix=""):
122     """ Test equality between a reference file saved in the baseline directory, and whose name is built as
123           "<test_name><suffix>.png"
124         and the file generated on the fly by taking a snapshot of the widget provided in argument.
125         The comparison is made in a temp dir which is kept if the file differ.
126     """
127     import glob
128     # Smiiiile :-)
129     self.qpixmap = QPixmap.grabWidget(widget)
130     
131     # Nothing to compare if rebuilding base lines, just saving file:
132     if self.REBUILD_BASELINES:
133       self.saveCurrentPix(self.tmpBaselineDir, suffix)
134       return True
135     
136     gen_path = self.saveCurrentPix(self.tmpDir, suffix)
137     base_ref = os.path.join(self._this_dir, self.__BASE_LINE_DIR, self.getTestName() + suffix)
138     ret = False
139     for ref_path in glob.glob("%s_*.%s" % (base_ref, self.__FORMAT)):
140       try:
141         ret = filecmp.cmp(ref_path, gen_path, shallow=False)
142         if ret:
143           break
144       except OSError:
145         ret = False
146     if not ret:
147       # Keep file if assert is false
148       self.keepDir = True
149       print "[%s] -- Failed screenshot equality, or unable to open baseline file - directory is kept alive: %s" % (self.getTestName(), self.tmpDir)
150     return ret 
151   
152   def showTabWidget(self):
153     tabW = self.plotController._sgPyQt._tabWidget
154     # No simpler way found so far:
155     tabW.show()
156     return tabW
157     
158   def getBrowserWidget(self):
159     return self.plotController._curveBrowserView._treeWidget