Skip to content

Commit

Permalink
TEST: builder component screenshot in test
Browse files Browse the repository at this point in the history
- no comparison yet, several issues to deal with first
  • Loading branch information
jeremygray committed Aug 12, 2014
1 parent 224c165 commit 928b027
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 38 deletions.
51 changes: 32 additions & 19 deletions psychopy/app/builder/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
"""
Expand Down Expand Up @@ -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):
Expand Down
62 changes: 43 additions & 19 deletions psychopy/tests/test_app/test_builder/test_Experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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)

0 comments on commit 928b027

Please sign in to comment.