From 928b02755eccaecdeea2a56fa0658639f7d169a7 Mon Sep 17 00:00:00 2001 From: "Jeremy R. Gray" Date: Tue, 12 Aug 2014 19:19:59 -0400 Subject: [PATCH] TEST: builder component screenshot in test - no comparison yet, several issues to deal with first --- psychopy/app/builder/builder.py | 51 +++++++++------ .../test_app/test_builder/test_Experiment.py | 62 +++++++++++++------ 2 files changed, 75 insertions(+), 38 deletions(-) diff --git a/psychopy/app/builder/builder.py b/psychopy/app/builder/builder.py index 8f5ef42b0f1..c6cc2db496f 100644 --- a/psychopy/app/builder/builder.py +++ b/psychopy/app/builder/builder.py @@ -1501,6 +1501,11 @@ def editComponentProperties(self, event=None, component=None): def getSecsPerPixel(self): return float(self.getMaxTime())/(self.timeXposEnd-self.timeXposStart) + def getSelfSnapshot(self, event=None, path=''): + """Returns path to a .png snapshot of the wx.Frame self. + """ + return takeSelfie(self, path) + class RoutinesNotebook(wx.aui.AuiNotebook): """A notebook that stores one or more routines """ @@ -4593,26 +4598,34 @@ def generateScript(self, experimentPath): return None return script - def getSelfie(self, event=None): - """Returns path to a bitmap snapshot of self, as it appears in the UI at this moment. + def getSelfSnapshot(self, event=None, path=''): + """Returns path to a .png snapshot of the wx.Frame self. """ - # http://wxpython-users.1045709.n5.nabble.com/Screen-capture-via-wxPython-td2348994.html - offset = 0 - htReduction = 0 # see link for ideas on how to set this - dc = wx.ClientDC(self) - rect = self.GetRect() - bmp = wx.EmptyBitmap(rect.width, rect.height - htReduction) - memdc = wx.MemoryDC() - memdc.SelectObject(bmp) - - memdc.Blit(0, 0, rect.width, rect.height, dc, 0, offset) - memdc.SelectObject(wx.NullBitmap) - - img = bmp.ConvertToImage() - fileName = "BuilderFrame_selfie.png" - img.SaveFile(fileName, wx.BITMAP_TYPE_PNG) - - return os.path.abspath(fileName) + return takeSelfie(self, path) + +def takeSelfie(frame, path=''): + """Capture a visual image of a wx.frame, return full-path to .png file + """ + # http://wxpython-users.1045709.n5.nabble.com/Screen-capture-via-wxPython-td2348994.html + offset = 0 + htReduction = 0 # see link for ideas on how to set this + dc = wx.ClientDC(frame) + rect = frame.GetRect() + bmp = wx.EmptyBitmap(rect.width, rect.height - htReduction) + memdc = wx.MemoryDC() + memdc.SelectObject(bmp) + + memdc.Blit(0, 0, rect.width, rect.height, dc, 0, offset) + memdc.SelectObject(wx.NullBitmap) + + img = bmp.ConvertToImage() + if path.endswith('.png'): + fileName = path + else: + fileName = os.path.join(path, "BuilderFrame_selfie.png") + img.SaveFile(fileName, wx.BITMAP_TYPE_PNG) + + return os.path.abspath(fileName) class ReadmeFrame(wx.Frame): diff --git a/psychopy/tests/test_app/test_builder/test_Experiment.py b/psychopy/tests/test_app/test_builder/test_Experiment.py index 7e09170f7c0..cc98d085deb 100644 --- a/psychopy/tests/test_app/test_builder/test_Experiment.py +++ b/psychopy/tests/test_app/test_builder/test_Experiment.py @@ -14,6 +14,8 @@ import threading #from psychopy.info import _getSha1hexDigest as sha1hex +from psychopy.preferences import prefs + # Jeremy Gray March 2011 # caveats when comparing files: @@ -318,20 +320,16 @@ def test_Exp_NameSpace(self): assert namespace.makeLoopIndex('trials_2') == 'thisTrial_2' assert namespace.makeLoopIndex('stimuli') == 'thisStimulus' +@pytest.mark.expcomp class Test_ExptComponents(): """This test fetches all standard components and checks that, with default settings, they can be added to a Routine and result in a script that compiles """ - def test_all_components(self): - for compName, compClass in allComponents.items(): - if compName in ['SettingsComponent']: - continue - #print "testing with:", compName - thisComp = compClass(exp=self.exp, parentName='testRoutine', name=compName) - self._checkCompileWith(thisComp) @classmethod def setup_class(cls): app = psychopyApp._app #this was created already + prefs.builder['topFlow'] = False + prefs.app['largeIcons'] = True app.newBuilderFrame() cls.builder = app.builderFrames[-1] # the most recent builder frame created cls.exp = cls.builder.exp @@ -355,26 +353,52 @@ def teardown(self): # print "D: tried click" # wx.CallAfter(clickOK) - def _checkCompileWith(self, thisComp): - """Adds the component to the current Routine and makes sure it still - compiles + def _checkCompile(self, filename): + """Checks that the current Routine will compile without errors. """ - filename = thisComp.params['name'].val+'.py' filepath = path.join(self.tmp_dir, filename) - self.testRoutine.addComponent(thisComp) - #make sure the mouse code compiles - # generate a script, similar to 'lastrun.py': - buff = self.exp.writeScript() # is a StringIO object + buff = self.exp.writeScript() # is a StringIO object script = buff.getvalue() - assert len(script) > 1500 # default empty script is ~2200 chars + assert len(script) > 1500 # default empty script is ~2200 chars # save the script: - f = codecs.open(filepath, 'w', 'utf-8') - f.write(script) - f.close() + with codecs.open(filepath, 'wb', 'utf-8') as f: + f.write(script) # compile the temp file to .pyc, catching error msgs (including no file at all): py_compile.compile(filepath, doraise=True) return filepath + 'c' + + def test_all_components(self): + # add each comp to a routine, compile to script, take screenshot + + # to compare screenshots to known images: + # 1) will need setup_class to provide known values for: + # topFlow=False, largeIcons=True, favorites=[], locale = only test using English + # 2) BuilderFrame.getSelfie() needs to account for cross-platform differences in height of frame + + for compName, compClass in allComponents.items(): + if compName in ['SettingsComponent']: + continue + thisComp = compClass(exp=self.exp, parentName='testRoutine') + + # add the comp: + self.testRoutine.addComponent(thisComp) + + # compile a script, save as file, check for syntax errors: + self._checkCompile(filename=thisComp.params['name'].val+'.py') + + # add each component, get a screen-shot of the Builder frame with thisComp in a routine + #self.builder.updateAllViews() + self.builder.routinePanel.redrawRoutines() + savePath = os.path.join(self.tmp_dir, thisComp.params['name'].val + '_selfie.png') + selfie = self.builder.getSelfSnapshot(path=savePath) + + # if localization.lang.startswith('en'): + # utils.compareScreenShot(selfie, ...) -- adjust to compare two images + + # remove thisComp from the RoutineCanvas to keep it simple visually: + r = self.builder.routinePanel.getCurrentRoutine() + r.removeComponent(thisComp)