Пример #1
0
 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)
Пример #3
0
 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"))
Пример #4
0
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)
Пример #5
0
 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)
Пример #6
0
 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 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"))
Пример #8
0
    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"
Пример #9
0
    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()
Пример #10
0
 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
Пример #11
0
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
Пример #13
0
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)
Пример #15
0
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']}."
                )
Пример #16
0
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}"
                )
Пример #17
0
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"
Пример #18
0
    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."
                )
Пример #19
0
 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)