def setup(self): self.temp_dir = mkdtemp() self.allComp = getAllComponents(fetchIcons=False) self.exp = Experiment() # create once, not every test # Create correctScript subdir for holding correct scripts if not os.path.isdir(os.path.join(TESTS_DATA_PATH, "correctScript", "js")): os.mkdir(os.path.join(TESTS_DATA_PATH, "correctScript", "js"))
class TestComponentCompilerJS(object): """A class for testing the JS code compiler for all components""" def setup(self): self.temp_dir = mkdtemp() self.allComp = getAllComponents(fetchIcons=False) self.exp = Experiment() # create once, not every test # Create correctScript subdir for holding correct scripts if not os.path.isdir( os.path.join(TESTS_DATA_PATH, "correctScript", "js")): os.mkdir(os.path.join(TESTS_DATA_PATH, "correctScript", "js")) def teardown(self): shutil.rmtree(self.temp_dir) def test_all_components(self): """Test all component code outputs, except for Settings and Unknown""" for compName in self.allComp: if compName not in ['SettingsComponent', 'UnknownComponent']: # reset exp self.reset_experiment(compName) # Add components psychoJSComponent = self.add_components(compName) # Create output script if component is a PsychoJS target if psychoJSComponent: self.create_component_output(compName) # Get correct script path correctPath = os.path.join(TESTS_DATA_PATH, "correctScript", "js", 'correct{}.js'.format(compName)) # Compare files, raising assertions on fails above tolerance (%) try: compareTextFiles('new{}.js'.format(compName), correctPath, tolerance=3) except IOError as err: compareTextFiles('new{}.js'.format(compName), correctPath, tolerance=3) def reset_experiment(self, compName): """Resets the exp object for each component""" self.exp = Experiment() # create once, not every test self.exp.addRoutine('trial') self.exp.flow.addRoutine(self.exp.routines['trial'], pos=0) self.exp.filename = compName def add_components(self, compName): """Add components to routine if they have a PsychoJS target""" thisComp = self.allComp[compName](parentName='trial', exp=self.exp) if 'PsychoJS' in thisComp.targets: self.exp.routines['trial'].addComponent(thisComp) return True return False def create_component_output(self, compName): """Create the JS script""" jsFilePath = os.path.join(os.getcwd(), 'new{}.js'.format(compName)) psyexpCompile.compileScript(infile=self.exp, outfile=jsFilePath)
def setup(self): self.temp_dir = mkdtemp() self.allComp = getAllComponents(fetchIcons=False) self.exp = Experiment() # create once, not every test self.exp.addRoutine('trial') self.exp.flow.addRoutine(self.exp.routines['trial'], pos=0) # Create correctScript subdir for holding correct scripts if not os.path.isdir(os.path.join(TESTS_DATA_PATH, "correctScript", "python")): os.mkdir(os.path.join(TESTS_DATA_PATH, "correctScript", "python"))
class TestComponentCompilerJS(object): """A class for testing the JS code compiler for all components""" def setup(self): self.temp_dir = mkdtemp() self.allComp = getAllComponents(fetchIcons=False) self.exp = Experiment() # create once, not every test # Create correctScript subdir for holding correct scripts if not os.path.isdir(os.path.join(TESTS_DATA_PATH, "correctScript", "js")): os.mkdir(os.path.join(TESTS_DATA_PATH, "correctScript", "js")) def teardown(self): shutil.rmtree(self.temp_dir) def test_all_components(self): """Test all component code outputs, except for Settings and Unknown""" for compName in self.allComp: if compName not in ['SettingsComponent', 'UnknownComponent']: # reset exp self.reset_experiment(compName) # Add components psychoJSComponent = self.add_components(compName) # Create output script if component is a PsychoJS target if psychoJSComponent: self.create_component_output(compName) # Get correct script path correctPath = os.path.join(TESTS_DATA_PATH, "correctScript", "js", 'correct{}.js'.format(compName)) # Compare files, raising assertions on fails above tolerance (%) try: compareTextFiles('new{}.js'.format(compName), correctPath, tolerance=3) except IOError as err: compareTextFiles('new{}.js'.format(compName), correctPath, tolerance=3) def reset_experiment(self, compName): """Resets the exp object for each component""" self.exp = Experiment() # create once, not every test self.exp.addRoutine('trial') self.exp.flow.addRoutine(self.exp.routines['trial'], pos=0) self.exp.filename = compName def add_components(self, compName): """Add components to routine if they have a PsychoJS target""" thisComp = self.allComp[compName](parentName='trial', exp=self.exp) if 'PsychoJS' in thisComp.targets: self.exp.routines['trial'].addComponent(thisComp) return True return False def create_component_output(self, compName): """Create the JS script""" jsFilePath = os.path.join(os.getcwd(), 'new{}.js'.format(compName)) psyexpCompile.compileScript(infile=self.exp, outfile=jsFilePath)
def setup(self): # Make blank experiment self.exp = Experiment() # Make blank routine self.routine = Routine(name="testRoutine", exp=self.exp) self.exp.addRoutine("testRoutine", self.routine) self.exp.flow.addRoutine(self.routine, 0) # Add loop around routine self.loop = TrialHandler(exp=self.exp, name="testLoop") self.exp.flow.addLoop(self.loop, 0, -1) # Make a rect for when we need something to click on self.comp = PolygonComponent(exp=self.exp, parentName="testRoutine", name="testPolygon") self.routine.addComponent(self.comp)
def setup(self): # Set ErrorHandler self.error = _BaseErrorHandler() # Create experiment, trial, flow and test components self.exp = Experiment() trial = self.exp.addRoutine('trial') self.exp.flow.addRoutine(trial, 0) allComp = getAllComponents(fetchIcons=False) # Polygon self.polygonComp = allComp["PolygonComponent"](parentName='trial', exp=self.exp) trial.addComponent(self.polygonComp) self.polygonComp.params['units'].val = 'height' self.polygonComp.params['startType'].val = "time (s)" self.polygonComp.params['stopType'].val = "time (s)" # Code component self.codeComp = allComp["CodeComponent"](parentName='trial', exp=self.exp) self.codeComp.params['Begin Experiment'].val = "(\n" self.codeComp.params['Begin JS Experiment'].val = "{\n"
def setup(self): # Create experiment and test components exp = Experiment() allComp = getAllComponents(fetchIcons=False) # Polygon self.polygonComp = allComp["PolygonComponent"](parentName='trial', exp=exp) self.polygonComp.params['units'].val = 'height' self.polygonComp.params['startType'].val = "time (s)" self.polygonComp.params['stopType'].val = "time (s)" # Code component self.codeComp = allComp["CodeComponent"](parentName='trial', exp=exp) self.codeComp.params['Begin Experiment'].val = "(\n" self.codeComp.params['Begin JS Experiment'].val = "{\n" # Set ErrorHandler sys.stderr = self.error = _BaseErrorHandler()
def test_disabled_routine_is_not_written_to_script(self): # Make experiment and two test routines exp = Experiment() rt1 = UnknownRoutine(exp, name="testRoutine1") rt2 = UnknownRoutine(exp, name="testRoutine2") # Disable one routine rt1.params['disabled'].val = True rt2.params['disabled'].val = False # Add routines to expriment exp.addStandaloneRoutine("testRoutine1", rt1) exp.flow.addRoutine(rt1, 0) exp.addStandaloneRoutine("testRoutine2", rt2) exp.flow.addRoutine(rt2, 0) # Write python script pyScript = exp.writeScript(target="PsychoPy") # Check that one routine is present and the other is not assert "testRoutine1" not in pyScript and "testRoutine2" in pyScript
class TestAlertTools(object): """A class for testing the alerttools module""" def setup(self): # Set ErrorHandler self.error = _BaseErrorHandler() # Create experiment, trial, flow and test components self.exp = Experiment() trial = self.exp.addRoutine('trial') self.exp.flow.addRoutine(trial, 0) allComp = getAllComponents(fetchIcons=False) # Polygon self.polygonComp = allComp["PolygonComponent"](parentName='trial', exp=self.exp) trial.addComponent(self.polygonComp) self.polygonComp.params['units'].val = 'height' self.polygonComp.params['startType'].val = "time (s)" self.polygonComp.params['stopType'].val = "time (s)" # Code component self.codeComp = allComp["CodeComponent"](parentName='trial', exp=self.exp) self.codeComp.params['Begin Experiment'].val = "(\n" self.codeComp.params['Begin JS Experiment'].val = "{\n" def test_2115_X_too_large(self): self.polygonComp.params['size'].val = [4, .5] self.exp.integrityCheck() assert ('Your stimulus size exceeds the X dimension of your window.' in self.error.alerts[0].msg) def test_2115_Y_too_large(self): self.polygonComp.params['size'].val = [.5, 4] self.exp.integrityCheck() assert ('Your stimulus size exceeds the Y dimension of your window.' in self.error.alerts[0].msg) def test_size_too_small_x(self): self.polygonComp.params['size'].val = [.0000001, .05] self.exp.integrityCheck() assert ('Your stimulus size is smaller than 1 pixel (X dimension)' in self.error.alerts[0].msg) def test_size_too_small_y(self): self.polygonComp.params['size'].val = [.05, .0000001] self.exp.integrityCheck() assert ('Your stimulus size is smaller than 1 pixel (Y dimension)' in self.error.alerts[0].msg) def test_position_x_dimension(self): self.polygonComp.params['pos'].val = [4, .5] self.exp.integrityCheck() assert ('Your stimulus position exceeds the X dimension' in self.error.alerts[0].msg) def test_position_y_dimension(self): self.polygonComp.params['pos'].val = [.5, 4] self.exp.integrityCheck() assert ('Your stimulus position exceeds the Y dimension' in self.error.alerts[0].msg) def test_variable_fail(self): self.polygonComp.params['pos'].val = '$pos' self.polygonComp.params['size'].val = '$size' self.exp.integrityCheck() assert (len(self.error.alerts) == 0) def test_timing(self): self.polygonComp.params['startVal'].val = 12 self.polygonComp.params['stopVal'].val = 10 self.exp.integrityCheck() assert ('Your stimulus start time exceeds the stop time' in self.error.alerts[0].msg) def test_disabled(self): self.polygonComp.params['disabled'].val = True alerttools.testDisabled(self.polygonComp) assert ('Your component is currently disabled' in self.error.alerts[0].msg) def test_achievable_visual_stim_onset(self): self.polygonComp.params['startVal'].val = .001 self.exp.integrityCheck() assert ('Your stimulus start time of 0.001 is less than a screen refresh for a 60Hz monitor' in self.error.alerts[0].msg) def test_achievable_visual_stim_offset(self): self.polygonComp.params['stopVal'].val = .001 self.polygonComp.params['stopType'].val = "duration (s)" self.exp.integrityCheck() assert ('Your stimulus stop time of 0.001 is less than a screen refresh for a 60Hz monitor' in self.error.alerts[0].msg) def test_valid_visual_timing(self): self.polygonComp.params['startVal'].val = 1.01 self.polygonComp.params['stopVal'].val = 2.01 self.exp.integrityCheck() assert ('start time of 1.01 seconds cannot be accurately presented' in self.error.alerts[0].msg) def test_4115_frames_as_int(self): self.polygonComp.params['startVal'].val = .5 self.polygonComp.params['startType'].val = "duration (frames)" self.exp.integrityCheck() assert ("Your stimulus start type \'duration (frames)\' must be expressed as a whole number" in self.error.alerts[0].msg) def test_python_syntax(self): alerttools.checkPythonSyntax(self.codeComp, 'Begin Experiment') assert ("Python Syntax Error in 'Begin Experiment'" in self.error.alerts[0].msg) def test_javascript_syntax(self): alerttools.checkJavaScriptSyntax(self.codeComp, 'Begin JS Experiment') assert ("JavaScript Syntax Error in 'Begin JS Experiment'" in self.error.alerts[0].msg)
def reset_experiment(self, compName): """Resets the exp object for each component""" self.exp = Experiment() # create once, not every test self.exp.addRoutine('trial') self.exp.flow.addRoutine(self.exp.routines['trial'], pos=0) self.exp.filename = compName
class TestMouseComponent: """ Test that Mouse coponents have the correct params and write as expected. """ def setup(self): # Make blank experiment self.exp = Experiment() # Make blank routine self.routine = Routine(name="testRoutine", exp=self.exp) self.exp.addRoutine("testRoutine", self.routine) self.exp.flow.addRoutine(self.routine, 0) # Add loop around routine self.loop = TrialHandler(exp=self.exp, name="testLoop") self.exp.flow.addLoop(self.loop, 0, -1) # Make Mouse component self.comp = MouseComponent(exp=self.exp, parentName="testRoutine", name="testMouse") self.routine.addComponent(self.comp) # Make a rect for when we need something to click on self.target = PolygonComponent(exp=self.exp, parentName="testRoutine", name="testPolygon") self.routine.addComponent(self.target) def test_click_save_end_clickable_cases(self): """ Test all combinations of options for what to save, what can be clicked on & what kind of clicks to end the routine on. """ saveMouseStateCases = [ { 'val': "final", 'want': ["thisExp.addData('testMouse.x', x)" ], # should contain code for adding final value of x 'avoid': ["testMouse.x.append(x)"] }, # should not contain code to update testMouse.x in frame loop { 'val': "on click", 'want': [ "thisExp.addData('testMouse.x', testMouse.x)", # should add testMouse.x at the end "testMouse.x.append(x)" ], # should contain code to update testMouse.x in frame loop 'avoid': ["thisExp.addData('testMouse.x', x)"] }, # should not add final value of x { 'val': "on valid click", 'want': [ "thisExp.addData('testMouse.x', testMouse.x)", # should add testMouse.x at the end "testMouse.x.append(x)", # should contain code to update testMouse.x in frame loop "if gotValidClick:" ], # should check for valid clicks 'avoid': ["thisExp.addData('testMouse.x', x)"] }, # should not add final value of x { 'val': "every frame", 'want': [ "thisExp.addData('testMouse.x', testMouse.x)", # should add testMouse.x at the end "testMouse.x.append(x)" ], # should contain code to update testMouse.x in frame loop 'avoid': ["thisExp.addData('testMouse.x', x)"] }, # should not add final value of x { 'val': "never", 'want': [], 'avoid': [ "thisExp.addData('testMouse.x', testMouse.x)", # should not add testMouse.x at the end "testMouse.x.append(x)", # should not contain code to update testMouse.x in frame loop "thisExp.addData('testMouse.x', x)" ] }, # should not add final value of x]}, ] forceEndRoutineOnPressCases = [ { 'val': "never", 'want': [], 'avoid': [ "# abort routine on response", # should not include code to abort routine "# abort routine on response" ] }, { 'val': "any click", 'want': ["# abort routine on response" ], # should include code to abort routine on response 'avoid': [] }, { 'val': "valid click", 'want': [ "# abort routine on response", # should include code to abort routine on response "if gotValidClick:" ], # should check for valid clicks 'avoid': [] }, ] clickableCases = [ { 'val': "[]", 'want': [], 'avoid': ["clickableList = [testPolygon]"] }, # should not define a populated clickables list { 'val': "[testPolygon]", 'want': [], 'avoid': ["clickableList = []"] }, # should not define a blank clickables list ] # Iterate through saveMouseState cases for SMScase in saveMouseStateCases: # Set saveMouseState self.comp.params['saveMouseState'].val = SMScase['val'] for FEROPcase in forceEndRoutineOnPressCases: # Set forceEndRoutineOnPress self.comp.params['forceEndRoutineOnPress'].val = FEROPcase[ 'val'] for Ccase in clickableCases: # Set clickable self.comp.params['clickable'].val = Ccase['val'] # Compile script script = self.exp.writeScript(target="PsychoPy") try: # Look for wanted phrases for phrase in SMScase['want']: assert phrase in script, ( f"{phrase} not found in script when saveMouseState={self.comp.params['saveMouseState']}, " f"forceEndRoutineOnPress={self.comp.params['forceEndRoutineOnPress']} and " f"clickable={self.comp.params['clickable']}") for phrase in FEROPcase['want']: assert phrase in script, ( f"{phrase} not found in script when saveMouseState={self.comp.params['saveMouseState']}, " f"forceEndRoutineOnPress={self.comp.params['forceEndRoutineOnPress']} and " f"clickable={self.comp.params['clickable']}") for phrase in Ccase['want']: assert phrase in script, ( f"{phrase} not found in script when saveMouseState={self.comp.params['saveMouseState']}, " f"forceEndRoutineOnPress={self.comp.params['forceEndRoutineOnPress']} and " f"clickable={self.comp.params['clickable']}") # Check there's no avoid phrases for phrase in SMScase['avoid']: assert phrase not in script, ( f"{phrase} found in script when saveMouseState={self.comp.params['saveMouseState']}, " f"forceEndRoutineOnPress={self.comp.params['forceEndRoutineOnPress']} and " f"clickable={self.comp.params['clickable']}") for phrase in FEROPcase['avoid']: assert phrase not in script, ( f"{phrase} found in script when saveMouseState={self.comp.params['saveMouseState']}, " f"forceEndRoutineOnPress={self.comp.params['forceEndRoutineOnPress']} and " f"clickable={self.comp.params['clickable']}") for phrase in Ccase['avoid']: assert phrase not in script, ( f"{phrase} found in script when saveMouseState={self.comp.params['saveMouseState']}, " f"forceEndRoutineOnPress={self.comp.params['forceEndRoutineOnPress']} and " f"clickable={self.comp.params['clickable']}") except AssertionError as err: # If any assertion fails, save script to view filename = Path( TESTS_DATA_PATH ) / f"{__class__.__name__}_clicks_cases_local.py" with open(filename, "w") as f: f.write(script) # Append ref to saved script in error message print(f"Script saved at: {filename}") # Raise original error raise err
class TestComponentCompilerPython(object): """A class for testing the Python code compiler for all components""" def setup(self): self.temp_dir = mkdtemp() self.allComp = getAllComponents(fetchIcons=False) self.exp = Experiment() # create once, not every test self.exp.addRoutine('trial') self.exp.flow.addRoutine(self.exp.routines['trial'], pos=0) # Create correctScript subdir for holding correct scripts if not os.path.isdir(os.path.join(TESTS_DATA_PATH, "correctScript", "python")): os.mkdir(os.path.join(TESTS_DATA_PATH, "correctScript", "python")) def teardown(self): shutil.rmtree(self.temp_dir) def test_all_components(self): """Test all component code outputs, except for Settings and Unknown""" for compName in self.allComp: if compName not in ['SettingsComponent', 'UnknownComponent']: # reset exp self.reset_experiment() # Add components self.add_components(compName) # Create output script self.create_component_output(compName) # Get correct script path correctPath = os.path.join(TESTS_DATA_PATH, "correctScript", "python", 'correct{}.py'.format(compName)) # Compare files, raising assertions on fails above tolerance (%) try: compareTextFiles('new{}.py'.format(compName), correctPath, tolerance=3) except IOError as err: compareTextFiles('new{}.py'.format(compName), correctPath, tolerance=3) def reset_experiment(self): """Resets the exp object for each component""" self.exp = Experiment() # create once, not every test self.exp.addRoutine('trial') self.exp.flow.addRoutine(self.exp.routines['trial'], pos=0) def add_components(self, compName): """Add components to routine""" thisComp = self.allComp[compName](parentName='trial', exp=self.exp) if compName == 'StaticComponent': # Create another component to trigger param updates for static textStim = self.allComp['TextComponent'](parentName='trial', exp=self.exp) textStim.params['color'].allowedUpdates.append('set during: trial.ISI') textStim.params['color'].updates = 'set during: trial.ISI' self.exp.routines['trial'].addComponent(textStim) # Create static component thisComp.addComponentUpdate('trial', 'text', 'color') thisComp.params['code'].val = "customStaticCode = True" # Add the custom code self.exp.routines['trial'].addComponent(thisComp) else: self.exp.routines['trial'].addComponent(thisComp) def create_component_output(self, compName): """Create the Python script""" psyexpCompile.compileScript(infile=self.exp, outfile='new{}.py'.format(compName)) def test_component_type_in_experiment(self): for compName in self.allComp: if compName not in ['SettingsComponent', 'UnknownComponent']: # reset exp self.reset_experiment() # Add components self.add_components(compName) # Check component in exp component = compName.split('Component')[0] assert self.exp.getComponentFromType(component)
class TestPolygonComponent(_TestBaseComponentsMixin, _TestDisabledMixin): """ Test that Polygon coponents have the correct params and write as expected. """ def setup(self): # Make blank experiment self.exp = Experiment() # Make blank routine self.routine = Routine(name="testRoutine", exp=self.exp) self.exp.addRoutine("testRoutine", self.routine) self.exp.flow.addRoutine(self.routine, 0) # Add loop around routine self.loop = TrialHandler(exp=self.exp, name="testLoop") self.exp.flow.addLoop(self.loop, 0, -1) # Make a rect for when we need something to click on self.comp = PolygonComponent(exp=self.exp, parentName="testRoutine", name="testPolygon") self.routine.addComponent(self.comp) def test_vertices_usage(self): """ Test that vertices values are used only under the correct conditions """ # Define values to look for and avoid in code according to value of shape cases = [ # Shape is a line { 'val': "line", 'seek': ["visual.Line("], 'avoid': ["___nVertices___", "___vertices___"] }, { 'val': "triangle", 'seek': ["visual.ShapeStim("], 'avoid': ["___nVertices___", "___vertices___"] }, { 'val': "rectangle", 'seek': ["visual.Rect("], 'avoid': ["___nVertices___", "___vertices___"] }, { 'val': "circle", 'seek': ["visual.ShapeStim(", "vertices='circle'"], 'avoid': ["___nVertices___", "___vertices___"] }, { 'val': "cross", 'seek': ["visual.ShapeStim(", "vertices='cross'"], 'avoid': ["___nVertices___", "___vertices___"] }, { 'val': "star", 'seek': ["visual.ShapeStim(", "vertices='star7'"], 'avoid': ["___nVertices___", "___vertices___"] }, { 'val': "regular polygon...", 'seek': ["___nVertices___", "visual.Polygon("], 'avoid': ["___vertices___"] }, { 'val': "custom polygon...", 'seek': ["___vertices___", "visual.ShapeStim("], 'avoid': ["___nVertices___"] }, ] # Setup component with markers for nVertices and vertices self.comp.params['nVertices'].val = "___nVertices___" self.comp.params['vertices'].val = "___vertices___" # Test each case for case in cases: # Set shape self.comp.params['shape'].val = case['val'] # Write experiment pyScript = self.exp.writeScript(target="PsychoPy") # Look for sought values in experiment script for seekVal in case['seek']: assert seekVal in pyScript, ( f"Could not find wanted value `{seekVal}` in experiment when polygon shape was {case['val']}." ) # Look for avoid values in experiment script for avoidVal in case['avoid']: assert avoidVal not in pyScript, ( f"Found unwanted value `{avoidVal}` in experiment when polygon shape was {case['val']}." )
class TestComponentCompilerPython(): """A class for testing the Python code compiler for all components""" def setup(self): self.temp_dir = mkdtemp() self.allComp = getAllComponents(fetchIcons=False) self.exp = Experiment() # create once, not every test self.exp.addRoutine('trial') self.exp.flow.addRoutine(self.exp.routines['trial'], pos=0) # Create correctScript subdir for holding correct scripts if not os.path.isdir( os.path.join(TESTS_DATA_PATH, "correctScript", "python")): os.mkdir(os.path.join(TESTS_DATA_PATH, "correctScript", "python")) def teardown(self): shutil.rmtree(self.temp_dir) def test_all_components(self): """Test all component code outputs, except for Settings and Unknown""" for compName in self.allComp: if compName not in ['SettingsComponent', 'UnknownComponent']: # reset exp self.reset_experiment() # Add components self.add_components(compName) # Create output script self.create_component_output(compName) # Get correct script path # correctPath = os.path.join(TESTS_DATA_PATH, "correctScript", "python", 'correct{}.py'.format(compName)) # Compare files, raising assertions on fails above tolerance (%) # try: # compareTextFiles('new{}.py'.format(compName), correctPath, tolerance=5) # except IOError as err: # compareTextFiles('new{}.py'.format(compName), correctPath, tolerance=5) def reset_experiment(self): """Resets the exp object for each component""" self.exp = Experiment() self.exp.addRoutine('trial') self.exp.flow.addRoutine(self.exp.routines['trial'], pos=0) def add_components(self, compName): """Add components to routine""" thisComp = self.allComp[compName](parentName='trial', exp=self.exp) if compName == 'StaticComponent': # Create another component to trigger param updates for static textStim = self.allComp['TextComponent'](parentName='trial', exp=self.exp) textStim.params['color'].allowedUpdates.append( 'set during: trial.ISI') textStim.params['color'].updates = 'set during: trial.ISI' self.exp.routines['trial'].addComponent(textStim) # Create static component thisComp.addComponentUpdate('trial', 'text', 'color') thisComp.params[ 'code'].val = "customStaticCode = True" # Add the custom code self.exp.routines['trial'].addComponent(thisComp) else: self.exp.routines['trial'].addComponent(thisComp) def create_component_output(self, compName): """Create the Python script""" pyFilePath = os.path.join(self.temp_dir, 'new{}.py'.format(compName)) psyexpCompile.compileScript(infile=self.exp, outfile=pyFilePath) def test_component_type_in_experiment(self): for compName, compObj in self.allComp.items(): if compName not in ['SettingsComponent', 'UnknownComponent' ] and "PsychoPy" in compObj.targets: # reset exp self.reset_experiment() # Add components self.add_components(compName) # Check component in exp component = compName.split('Component')[0] assert self.exp.getComponentFromType(component), ( f"Could not find component of type {compName} in: {self.exp.flow}" )
def test_get_resources_js(): cases = [ # Resource not handled, no loop present {'exp': "unhandled_noloop", 'seek': ['blue.png'], 'avoid': ['white.png', 'yellow.png', 'groups.csv', 'groupA.csv', 'groupB.csv']}, # Resource not handled, loop defined by string {'exp': "unhandled_strloop", 'seek': ['blue.png', 'white.png', 'groupA.csv'], 'avoid': ['yellow.png', 'groupB.csv', 'groups.csv']}, # Resource not handled, loop defined by constructed string {'exp': "unhandled_constrloop", 'seek': ['blue.png', 'white.png', 'yellow.png', 'groupA.csv', 'groupB.csv', 'groups.csv'], 'avoid': []}, # Resource not handled, loop defined by constructed string from loop {'exp': "unhandled_recurloop", 'seek': ['blue.png', 'white.png', 'yellow.png', 'groupA.csv', 'groupB.csv', 'groups.csv'], 'avoid': []}, # Resource handled by static component, no loop present {'exp': "handledbystatic_noloop", 'seek': [], 'avoid': ['blue.png', 'white.png', 'yellow.png', 'groups.csv', 'groupA.csv', 'groupB.csv']}, # Resource handled by static component, loop defined by string {'exp': "handledbystatic_strloop", 'seek': ['groupA.csv'], 'avoid': ['blue.png', 'white.png', 'yellow.png', 'groupB.csv', 'groups.csv']}, # Resource handled by static component, loop defined by constructed string {'exp': "handledbystatic_constrloop", 'seek': ['groupA.csv', 'groupB.csv', 'groups.csv'], 'avoid': ['blue.png', 'white.png', 'yellow.png']}, # Resource handled by static component, loop defined by constructed string from loop {'exp': "handledbystatic_recurloop", 'seek': ['groupA.csv', 'groupB.csv', 'groups.csv'], 'avoid': ['blue.png', 'white.png', 'yellow.png']}, # Resource handled by resource manager component, no loop present {'exp': "handledbyrm_noloop", 'seek': [], 'avoid': ['blue.png', 'white.png', 'yellow.png', 'groups.csv', 'groupA.csv', 'groupB.csv']}, # Resource handled by resource manager component, loop defined by constructed string {'exp': "handledbyrm_strloop", 'seek': ['groupA.csv'], 'avoid': ['blue.png', 'white.png', 'yellow.png', 'groupB.csv', 'groups.csv']}, # Resource handled by resource manager component, loop defined by constructed string {'exp': "handledbyrm_constrloop", 'seek': ['groupA.csv', 'groupB.csv', 'groups.csv'], 'avoid': ['blue.png', 'white.png', 'yellow.png']}, # Resource handled by resource manager component, loop defined by constructed string from loop {'exp': "handledbyrm_recurloop", 'seek': ['groupA.csv', 'groupB.csv', 'groups.csv'], 'avoid': ['blue.png', 'white.png', 'yellow.png']}, ] exp = Experiment() for case in cases: # Load experiment exp.loadFromXML(Path(TESTS_DATA_PATH) / "test_get_resources" / (case['exp'] + ".psyexp")) # Write to JS script = exp.writeScript(target="PsychoJS") # Extract resources def at start of experiment resources = re.search("(?<=resources: \[)[^\]]*", script).group(0) # Check that all "seek" phrases are included for phrase in case['seek']: assert phrase in resources, f"'{phrase}' was not found in resources for {case['exp']}.psyexp" # Check that all "avoid" phrases are excluded for phrase in case['avoid']: assert phrase not in resources, f"'{phrase}' was found in resources for {case['exp']}.psyexp"
def test_muting(self): """ Test that component and standalone routines are muted under the correct conditions (i.e. if target is unimplemented or if disabled) """ # Make experiment to hold everything exp = Experiment() comp_rt = Routine("comp_rt", exp) comp_rt = exp.addRoutine("comp_rt", comp_rt) exp.flow.append(comp_rt) # Define some routines/components which should or should not compile exemplars = [] # standalone routine + disabled + no target obj = UnknownRoutine(exp, name="test_rt_disabled_notarget") obj.disabled = True obj.targets = [] exp.addStandaloneRoutine(obj.name, obj) exp.flow.append(obj) exemplars.append({"obj": obj, "ans": []}) # standalone routine + disabled + py target obj = UnknownRoutine(exp, name="test_rt_disabled_pytarget") obj.disabled = True obj.targets = ['PsychoPy'] exp.addStandaloneRoutine(obj.name, obj) exp.flow.append(obj) exemplars.append({"obj": obj, "ans": []}) # standalone routine + disabled + js target obj = UnknownRoutine(exp, name="test_rt_disabled_jstarget") obj.disabled = True obj.targets = ['PsychoJS'] exp.addStandaloneRoutine(obj.name, obj) exp.flow.append(obj) exemplars.append({"obj": obj, "ans": []}) # standalone routine + disabled + both targets obj = UnknownRoutine(exp, name="test_rt_disabled_bothtarget") obj.disabled = True obj.targets = ['PsychoPy', 'PsychoJS'] exp.addStandaloneRoutine(obj.name, obj) exp.flow.append(obj) exemplars.append({"obj": obj, "ans": []}) # standalone routine + enabled + no target obj = UnknownRoutine(exp, name="test_rt_enabled_notarget") obj.disabled = False obj.targets = [] exp.addStandaloneRoutine(obj.name, obj) exp.flow.append(obj) exemplars.append({"obj": obj, "ans": obj.targets}) # standalone routine + enabled + py target obj = UnknownRoutine(exp, name="test_rt_enabled_pytarget") obj.disabled = False obj.targets = ['PsychoPy'] exp.addStandaloneRoutine(obj.name, obj) exp.flow.append(obj) exemplars.append({"obj": obj, "ans": obj.targets}) # standalone routine + enabled + js target obj = UnknownRoutine(exp, name="test_rt_enabled_jstarget") obj.disabled = False obj.targets = ['PsychoJS'] exp.addStandaloneRoutine(obj.name, obj) exp.flow.append(obj) exemplars.append({"obj": obj, "ans": obj.targets}) # standalone routine + enabled + both target obj = UnknownRoutine(exp, name="test_rt_enabled_bothtarget") obj.disabled = False obj.targets = ['PsychoPy', 'PsychoJS'] exp.addStandaloneRoutine(obj.name, obj) exp.flow.append(obj) exemplars.append({"obj": obj, "ans": obj.targets}) # component + disabled + no target obj = UnknownComponent(exp, parentName="comp_rt", name="test_cmp_disabled_notarget") obj.disabled = True obj.targets = [] comp_rt.addComponent(obj) exemplars.append({"obj": obj, "ans": []}) # component + disabled + py target obj = UnknownComponent(exp, parentName="comp_rt", name="test_cmp_disabled_pytarget") obj.disabled = True obj.targets = ['PsychoPy'] comp_rt.addComponent(obj) exemplars.append({"obj": obj, "ans": []}) # component + disabled + js target obj = UnknownComponent(exp, parentName="comp_rt", name="test_cmp_disabled_jstarget") obj.disabled = True obj.targets = ['PsychoJS'] comp_rt.addComponent(obj) exemplars.append({"obj": obj, "ans": []}) # component + disabled + both target obj = UnknownComponent(exp, parentName="comp_rt", name="test_cmp_disabled_bothtarget") obj.disabled = True obj.targets = ['PsychoPy', 'PsychoJS'] comp_rt.addComponent(obj) exemplars.append({"obj": obj, "ans": []}) # component + enabled + no target obj = UnknownComponent(exp, parentName="comp_rt", name="test_cmp_enabled_notarget") obj.disabled = False obj.targets = [] comp_rt.addComponent(obj) exemplars.append({"obj": obj, "ans": obj.targets}) # component + enabled + py target obj = UnknownComponent(exp, parentName="comp_rt", name="test_cmp_enabled_pytarget") obj.disabled = False obj.targets = ['PsychoPy'] comp_rt.addComponent(obj) exemplars.append({"obj": obj, "ans": obj.targets}) # component + enabled + js target obj = UnknownComponent(exp, parentName="comp_rt", name="test_cmp_enabled_jstarget") obj.disabled = False obj.targets = ['PsychoJS'] comp_rt.addComponent(obj) exemplars.append({"obj": obj, "ans": obj.targets}) # component + enabled + both target obj = UnknownComponent(exp, parentName="comp_rt", name="test_cmp_enabled_bothtarget") obj.disabled = False obj.targets = ['PsychoPy', 'PsychoJS'] comp_rt.addComponent(obj) exemplars.append({"obj": obj, "ans": obj.targets}) tykes = [] # Compile experiment pyScript = exp.writeScript(target="PsychoPy") # jsScript = exp.writeScript(target="PsychoJS") ## disabled until js can compile without saving # Test all cases for case in exemplars + tykes: # Check Python script if "PsychoPy" in case['ans']: assert case['obj'].name in pyScript, ( f"{case['obj']} not found in Python script when it should be." ) else: assert case['obj'].name not in pyScript, ( f"{case['obj']} found in Python script when it should not be." )
def reset_experiment(self): """Resets the exp object for each component""" self.exp = Experiment() self.exp.addRoutine('trial') self.exp.flow.addRoutine(self.exp.routines['trial'], pos=0)
def reset_experiment(self): """Resets the exp object for each component""" self.exp = Experiment() # create once, not every test self.exp.addRoutine('trial') self.exp.flow.addRoutine(self.exp.routines['trial'], pos=0)