Ejemplo n.º 1
0
def test_constant() -> None:

    scene = Scene("s1")
    obj = SceneObject("test_name", Test.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position())
    project.action_points.append(ap1)

    const_value = 1234
    const = ProjectParameter("int_const", "integer", json.dumps(const_value))
    project.parameters.append(const)

    ac1 = Action(
        "ac1",
        f"{obj.id}/test_par",
        flows=[Flow()],
        parameters=[
            ActionParameter("param", ActionParameter.TypeEnum.CONSTANT,
                            json.dumps(const.id))
        ],
    )

    ap1.actions.append(ac1)

    project.logic.append(LogicItem(LogicItem.START, ac1.id))
    project.logic.append(LogicItem(ac1.id, LogicItem.END))

    src = program_src({Test.__name__: Test}, CachedProject(project),
                      CachedScene(scene))

    assert f"{const.name} = {const_value}" in src
    assert f"test_name.{Test.test_par.__name__}({const.name}, an='ac1')" in src
Ejemplo n.º 2
0
def test_make_relative_ap_global_and_relative_again():

    scene = Scene("s1", "s1")
    scene.objects.append(
        SceneObject("so1", "so1", "WhatEver",
                    Pose(Position(3, 0, 0), Orientation())))

    project = Project("p1", "p1", "s1")
    project.action_points.append(
        ProjectActionPoint("ap1", "ap1", Position(-1, 0, 0), parent="so1"))
    project.action_points.append(
        ProjectActionPoint("ap2", "ap2", Position(-1, 0, 0), parent="ap1"))
    ap3 = ProjectActionPoint("ap3", "ap3", Position(-1, 0, 0), parent="ap2")
    project.action_points.append(ap3)

    make_relative_ap_global(scene, project, ap3)

    assert ap3.parent is None
    assert ap3.position.x == .0

    make_global_ap_relative(scene, project, ap3, "ap2")

    assert ap3.parent == "ap2"
    assert ap3.position.x == -1

    ap3.parent = "something_unknown"

    with pytest.raises(Arcor2Exception):
        make_relative_ap_global(scene, project, ap3)
Ejemplo n.º 3
0
def test_blind_branch() -> None:

    scene = Scene("s1")
    obj = SceneObject("test_name", Test.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position())
    project.action_points.append(ap1)

    ac1 = Action("ac1", f"{obj.id}/test", flows=[Flow(outputs=["bool_res"])])
    ap1.actions.append(ac1)

    ac2 = Action("ac2", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac2)

    ac3 = Action("ac3", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac3)

    ac4 = Action("ac4", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac4)

    project.logic.append(LogicItem(LogicItem.START, ac1.id))

    project.logic.append(LogicItem(ac1.id, ac2.id, ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(True))))
    project.logic.append(LogicItem(ac1.id, ac3.id, ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(False))))

    project.logic.append(LogicItem(ac2.id, ac4.id))
    project.logic.append(LogicItem(ac4.id, LogicItem.END))

    with pytest.raises(SourceException, match=f"Action {ac3.name} has no outputs."):
        program_src({Test.__name__: Test}, CachedProject(project), CachedScene(scene))
Ejemplo n.º 4
0
def test_obj_relative_ap_global() -> None:

    scene = Scene("s1")
    # object rotated 90° clock-wise
    so1 = SceneObject(
        "so1", "WhatEver",
        Pose(Position(1, 0, 0), Orientation(0, 0, -0.707, 0.707)))
    scene.objects.append(so1)
    cached_scene = CachedScene(scene)

    project = Project("p1", scene.id)
    ap1 = ActionPoint("ap1", Position(1, 0, 0), parent=so1.id)
    project.action_points.append(ap1)
    ap2 = ActionPoint("ap2", Position(1, 0, 0), parent=ap1.id)
    no1 = NamedOrientation("o1", Orientation())
    ap2.orientations.append(no1)
    project.action_points.append(ap2)

    cached_project = CachedProject(project)

    make_relative_ap_global(cached_scene, cached_project, ap2)
    check_ap(ap2)

    assert ap2.position == Position(1, -2, 0)
    assert so1.pose
    assert no1.orientation == so1.pose.orientation

    make_global_ap_relative(cached_scene, cached_project, ap2, ap1.id)

    assert ap2.position == Position(1, 0, 0)
    assert no1.orientation == Orientation()
    check_ap(ap2)
Ejemplo n.º 5
0
def test_global_aps_cls() -> None:

    proj = Project("test", "scene_id")

    pos = Position(1, 2, 3)
    ap1 = ActionPoint("ap1", pos)
    ap1_o1 = NamedOrientation("o1", Orientation(0.707, 0, 0, 0.707))
    ap1.orientations.append(ap1_o1)
    ap1_j1 = ProjectRobotJoints("j1", "robot", [Joint("whatever", 1234)])
    ap1.robot_joints.append(ap1_j1)
    proj.action_points.append(ap1)

    os.environ["ARCOR2_PROJECT_PATH"] = "/tmp"
    import arcor2.resources  # noqa

    my_name = "my_module"
    my_spec = importlib.util.spec_from_loader(my_name, loader=None)
    my_module = importlib.util.module_from_spec(my_spec)

    cproj = CachedProject(proj)

    src = global_action_points_class(cproj)
    exec(src, my_module.__dict__)
    sys.modules["my_module"] = my_module

    aps = my_module.ActionPoints(SimResources(cproj))  # type: ignore

    assert aps.ap1.position == pos
    assert aps.ap1.position is not pos

    assert aps.ap1.poses.o1 == Pose(ap1.position, ap1_o1.orientation)
    assert aps.ap1.poses.o1.orientation is not ap1_o1.orientation

    assert aps.ap1.joints.j1 == ap1_j1
    assert aps.ap1.joints.j1 is not ap1_j1
Ejemplo n.º 6
0
def test_slots() -> None:
    """Tests whether classes from cached module uses __slots__."""

    s = Scene("")
    p = Project("", s.id)

    assert not hasattr(CachedScene(s), "__dict__")
    assert not hasattr(CachedProject(p), "__dict__")
    assert not hasattr(UpdateableCachedScene(s), "__dict__")
    assert not hasattr(UpdateableCachedProject(p), "__dict__")
Ejemplo n.º 7
0
def test_get_value() -> None:

    p = Pose(Position(1, 2, 3), Orientation(1, 0, 0, 0))

    scene = Scene("s1")
    obj = SceneObject("test_name", TestObject.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position(1, 0, 0))
    project.action_points.append(ap1)
    ap2 = ActionPoint("ap2", Position(), parent=ap1.id)
    project.action_points.append(ap2)

    ori1 = NamedOrientation("ori1", p.orientation)

    ap2.orientations.append(ori1)

    invalid_param_name = "invalid_param"

    ac1 = Action(
        "ac1",
        f"{obj.id}/{TestObject.action.__name__}",
        parameters=[
            ActionParameter(param_name, PosePlugin.type_name(),
                            json.dumps(ori1.id)),
            ActionParameter(invalid_param_name, PosePlugin.type_name(),
                            json.dumps("non_sense")),
        ],
    )

    ap1.actions.append(ac1)

    cscene = CachedScene(scene)
    cproject = CachedProject(project)

    with pytest.raises(Arcor2Exception):
        PosePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                   "non_sense")

    with pytest.raises(Arcor2Exception):
        PosePlugin.parameter_value(type_defs, cscene, cproject, "non_sense",
                                   param_name)

    with pytest.raises(ParameterPluginException):
        PosePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                   invalid_param_name)

    value = PosePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                       param_name)
    exe_value = PosePlugin.parameter_execution_value(type_defs, cscene,
                                                     cproject, ac1.id,
                                                     param_name)

    assert value == value
    assert value != exe_value
Ejemplo n.º 8
0
def project() -> UpdateableCachedProject:

    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position())
    project.action_points.append(ap1)

    ap1.actions.append(ac1)
    ap1.actions.append(ac2)
    ap1.actions.append(ac3)
    ap1.actions.append(ac4)
    return UpdateableCachedProject(project)
Ejemplo n.º 9
0
def test_get_value() -> None:

    img = Image.new("RGB", (320, 240))

    scene = Scene("s1", "s1")
    obj = SceneObject("test_name", TestObject.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position(1, 0, 0))
    project.action_points.append(ap1)

    invalid_param_name = "invalid_param"

    ac1 = Action(
        "ac1",
        f"{obj.id}/{TestObject.action.__name__}",
        parameters=[
            ActionParameter(param_name, ImagePlugin.type_name(),
                            ImagePlugin.value_to_json(img)),
            ActionParameter(invalid_param_name, ImagePlugin.type_name(),
                            json.dumps("non_sense")),
        ],
    )

    ap1.actions.append(ac1)

    cscene = CachedScene(scene)
    cproject = CachedProject(project)

    with pytest.raises(Arcor2Exception):
        ImagePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                    "non_sense")

    with pytest.raises(Arcor2Exception):
        ImagePlugin.parameter_value(type_defs, cscene, cproject, "non_sense",
                                    param_name)

    with pytest.raises(ParameterPluginException):
        ImagePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                    invalid_param_name)

    value = ImagePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                        param_name)
    exe_value = ImagePlugin.parameter_execution_value(type_defs, cscene,
                                                      cproject, ac1.id,
                                                      param_name)

    assert value == value
    assert value == exe_value
Ejemplo n.º 10
0
def test_get_value() -> None:

    scene = Scene("s1", "s1")
    obj = SceneObject("test_name", TestObject.__name__)
    prj = ProjectRobotJoints("name", obj.id, [Joint("name", 0.333)])
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position(1, 0, 0))
    ap1.robot_joints.append(prj)
    project.action_points.append(ap1)

    invalid_param_name = "invalid_param"

    act = Action(
        "ac1",
        f"{obj.id}/{TestObject.action.__name__}",
        parameters=[
            ActionParameter(param_name, JointsPlugin.type_name(),
                            json.dumps(prj.id)),
            ActionParameter(invalid_param_name, JointsPlugin.type_name(),
                            json.dumps("non_sense")),
        ],
    )

    ap1.actions.append(act)

    cscene = CachedScene(scene)
    cproject = CachedProject(project)

    with pytest.raises(Arcor2Exception):
        JointsPlugin.parameter_value(type_defs, cscene, cproject, act.id,
                                     "non_sense")

    with pytest.raises(Arcor2Exception):
        JointsPlugin.parameter_value(type_defs, cscene, cproject, "non_sense",
                                     param_name)

    with pytest.raises(ParameterPluginException):
        JointsPlugin.parameter_value(type_defs, cscene, cproject, act.id,
                                     invalid_param_name)

    value = JointsPlugin.parameter_value(type_defs, cscene, cproject, act.id,
                                         param_name)
    exe_value = JointsPlugin.parameter_execution_value(type_defs, cscene,
                                                       cproject, act.id,
                                                       param_name)

    assert value == value
    assert value == exe_value
Ejemplo n.º 11
0
    def test_get_value(self, val: str) -> None:

        scene = Scene("s1")
        obj = SceneObject("test_name", TestObject.__name__)
        scene.objects.append(obj)
        project = Project("p1", "s1")
        ap1 = ActionPoint("ap1", Position())
        project.action_points.append(ap1)

        invalid_param_name = "invalid_param"

        ac1 = Action(
            "ac1",
            f"{obj.id}/{TestObject.action.__name__}",
            parameters=[
                ActionParameter(param_name, StringPlugin.type_name(),
                                StringPlugin.value_to_json(val)),
                ActionParameter(invalid_param_name, StringPlugin.type_name(),
                                json.dumps(666)),
            ],
        )

        ap1.actions.append(ac1)

        cscene = CachedScene(scene)
        cproject = CachedProject(project)

        with pytest.raises(Arcor2Exception):
            StringPlugin.parameter_value({}, cscene, cproject, ac1.id,
                                         "non_sense")

        with pytest.raises(Arcor2Exception):
            StringPlugin.parameter_value({}, cscene, cproject, "non_sense",
                                         param_name)

        with pytest.raises(ParameterPluginException):
            StringPlugin.parameter_value({}, cscene, cproject, ac1.id,
                                         invalid_param_name)

        value = StringPlugin.parameter_value({}, cscene, cproject, ac1.id,
                                             param_name)
        exe_value = StringPlugin.parameter_execution_value({}, cscene,
                                                           cproject, ac1.id,
                                                           param_name)

        assert value == val
        assert value == exe_value
Ejemplo n.º 12
0
def test_make_relative_ap_global_and_relative_again() -> None:

    scene = Scene("s1")
    so1 = SceneObject("so1", "WhatEver", Pose(Position(3, 0, 0),
                                              Orientation()))
    scene.objects.append(so1)
    cached_scene = CachedScene(scene)

    project = Project("p1", scene.id)
    ap1 = ActionPoint("ap1", Position(-1, 0, 0), parent=so1.id)
    project.action_points.append(ap1)
    ap2 = ActionPoint("ap2", Position(-1, 0, 0), parent=ap1.id)
    project.action_points.append(ap2)
    ap3 = ActionPoint(
        "ap3",
        Position(-1, 0, 0),
        parent=ap2.id,
        orientations=[NamedOrientation("bla", random_orientation())])
    project.action_points.append(ap3)

    cached_project = CachedProject(project)

    assert ap3.parent
    ap3_parent = get_parent_pose(cached_scene, cached_project, ap3.parent)

    assert Pose(ap2.position, Orientation()) == ap3_parent.pose
    assert ap3_parent.parent_id == ap1.id

    make_relative_ap_global(cached_scene, cached_project, ap3)

    check_ap(ap3)

    assert ap3.parent is None
    assert ap3.position.x == 0.0  # type: ignore

    make_global_ap_relative(cached_scene, cached_project, ap3, ap2.id)

    check_ap(ap3)

    assert ap3.parent == ap2.id
    assert ap3.position.x == -1

    ap3.parent = "something_unknown"

    with pytest.raises(Arcor2Exception):
        make_relative_ap_global(cached_scene, cached_project, ap3)
Ejemplo n.º 13
0
def test_prev_result() -> None:

    scene = Scene("s1")
    obj = SceneObject("test_name", Test.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position())
    project.action_points.append(ap1)

    ac1 = Action("ac1",
                 f"{obj.id}/{Test.get_int.__name__}",
                 flows=[Flow(outputs=["res"])])
    ap1.actions.append(ac1)

    ac2 = Action(
        "ac2",
        f"{obj.id}/{Test.test_par.__name__}",
        flows=[Flow()],
        parameters=[
            ActionParameter("param", ActionParameter.TypeEnum.LINK,
                            json.dumps(f"{ac1.id}/default/0"))
        ],
    )
    ap1.actions.append(ac2)

    project.logic.append(LogicItem(LogicItem.START, ac1.id))
    project.logic.append(LogicItem(ac1.id, ac2.id))
    project.logic.append(LogicItem(ac2.id, LogicItem.END))

    src = program_src({Test.__name__: Test}, CachedProject(project),
                      CachedScene(scene))

    assert f"res = test_name.{Test.get_int.__name__}(an='{ac1.name}')" in src
    assert f"test_name.{Test.test_par.__name__}(res, an='{ac2.name}')" in src

    # test wrong order of logic
    project.logic.clear()

    project.logic.append(LogicItem(LogicItem.START, ac2.id))
    project.logic.append(LogicItem(ac2.id, ac1.id))
    project.logic.append(LogicItem(ac1.id, LogicItem.END))

    with pytest.raises(SourceException):
        program_src({Test.__name__: Test}, CachedProject(project),
                    CachedScene(scene))
Ejemplo n.º 14
0
def test_list_problems(start_processes: None, ars: ARServer) -> None:
    """This is a test for a bug in get_scene_problems and get_project_problems
    functions.

    Because of the bug, the RPC returned result=False when there was non-existing ObjectType.

    :param start_processes:
    :param ars:
    :return:
    """

    upload_def(DummyMultiArmRobot
               )  # OT has to exist first, otherwise scene can't be stored
    invalid_scene_1 = Scene("invalidScene",
                            objects=[
                                SceneObject("invalidObject",
                                            DummyMultiArmRobot.__name__,
                                            Pose())
                            ])
    invalid_project_1 = Project("invalidProject", invalid_scene_1.id)
    project_service.update_scene(invalid_scene_1)
    project_service.update_project(invalid_project_1)
    project_service.delete_object_type(
        DummyMultiArmRobot.__name__)  # now the OT can be deleted

    # initial event
    show_main_screen_event = event(ars, events.c.ShowMainScreen)
    assert show_main_screen_event.data
    assert show_main_screen_event.data.what == events.c.ShowMainScreen.Data.WhatEnum.ScenesList

    scenes = ars.call_rpc(rpc.s.ListScenes.Request(get_id()),
                          rpc.s.ListScenes.Response)
    assert scenes.result
    assert scenes.data
    assert len(scenes.data) == 1
    assert scenes.data[0].id == invalid_scene_1.id
    assert scenes.data[0].name == invalid_scene_1.name
    assert scenes.data[0].problems
    assert len(scenes.data[0].problems) == 1

    projects = ars.call_rpc(rpc.p.ListProjects.Request(get_id()),
                            rpc.p.ListProjects.Response)
    assert projects.result
    assert projects.data
    assert len(projects.data) == 1
    assert projects.data[0].id == invalid_project_1.id
    assert projects.data[0].name == invalid_project_1.name
    assert projects.data[0].problems
    assert len(projects.data[0].problems) == 1

    upload_def(DummyMultiArmRobot)

    # now the ObjectType exists, so the scene/project should be ok
    scenes2 = ars.call_rpc(rpc.s.ListScenes.Request(get_id()),
                           rpc.s.ListScenes.Response)
    assert scenes2.result
    assert scenes2.data
    assert len(scenes2.data) == 1
    assert scenes2.data[0].id == invalid_scene_1.id
    assert scenes2.data[0].name == invalid_scene_1.name
    assert scenes2.data[0].problems is None

    projects2 = ars.call_rpc(rpc.p.ListProjects.Request(get_id()),
                             rpc.p.ListProjects.Response)
    assert projects2.result
    assert projects2.data
    assert len(projects2.data) == 1
    assert projects2.data[0].id == invalid_project_1.id
    assert projects2.data[0].name == invalid_project_1.name
    assert projects2.data[0].problems is None
Ejemplo n.º 15
0
def test_branched_output_2() -> None:

    scene = Scene("s1")
    obj = SceneObject("test_name", Test.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position())
    project.action_points.append(ap1)

    ac1 = Action("ac1", f"{obj.id}/test", flows=[Flow(outputs=["bool_res"])])
    ap1.actions.append(ac1)

    ac2 = Action("ac2", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac2)

    ac3 = Action("ac3", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac3)

    ac4 = Action("ac4", f"{obj.id}/test", flows=[Flow(outputs=["bool2_res"])])
    ap1.actions.append(ac4)

    ac5 = Action("ac5", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac5)

    ac6 = Action("ac6", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac6)

    project.logic.append(LogicItem(LogicItem.START, ac1.id))

    project.logic.append(
        LogicItem(ac1.id, ac2.id,
                  ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(True))))
    project.logic.append(
        LogicItem(ac1.id, ac4.id,
                  ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(False))))

    project.logic.append(LogicItem(ac2.id, ac3.id))
    project.logic.append(LogicItem(ac3.id, ac6.id))

    project.logic.append(
        LogicItem(ac4.id, ac5.id,
                  ProjectLogicIf(f"{ac4.id}/default/0", json.dumps(True))))
    project.logic.append(LogicItem(ac5.id, ac6.id))
    project.logic.append(LogicItem(ac6.id, LogicItem.END))

    project.logic.append(
        LogicItem(ac4.id, LogicItem.END,
                  ProjectLogicIf(f"{ac4.id}/default/0", json.dumps(False))))

    src = program_src({Test.__name__: Test}, CachedProject(project),
                      CachedScene(scene))
    parse(src)
    """
    bool_res = test_name.test(res.ac1)
    if (bool_res == False):
        bool2_res = test_name.test(res.ac4)
        if (bool2_res == False):
            continue
        elif (bool2_res == True):
            test_name.test(res.ac5)
    elif (bool_res == True):
        test_name.test(res.ac2)
        test_name.test(res.ac3)
    test_name.test(res.ac6)
    """

    spl = src.splitlines()

    # it has to be robust against changed order of blocks
    ac1_idx = subs_index(spl, "bool_res = test_name.test(an='ac1')")

    if_bool_res_false_idx = subs_index(spl, "if (bool_res == False):")
    assert if_bool_res_false_idx > ac1_idx
    assert cntsp(spl[ac1_idx]) == cntsp(spl[if_bool_res_false_idx])

    bool2_res_idx = subs_index(spl, "bool2_res = test_name.test(an='ac4')")
    assert bool2_res_idx > if_bool_res_false_idx
    assert cntsp(spl[if_bool_res_false_idx]) == cntsp(spl[bool2_res_idx]) - TAB

    if_bool_2_res_false_idx = subs_index(spl, "if (bool2_res == False):")
    assert cntsp(spl[if_bool_2_res_false_idx]) == cntsp(spl[bool2_res_idx])
    assert if_bool_2_res_false_idx > bool2_res_idx
    assert "continue" in spl[if_bool_2_res_false_idx + 1]
    assert cntsp(
        spl[bool2_res_idx]) == cntsp(spl[if_bool_2_res_false_idx + 1]) - TAB

    if_bool_2_res_true_idx = subs_index(spl, "if (bool2_res == True):")
    assert if_bool_2_res_true_idx > bool2_res_idx
    assert "test_name.test(an='ac5')" in spl[if_bool_2_res_true_idx + 1]
    assert cntsp(spl[if_bool_2_res_true_idx]) == cntsp(
        spl[if_bool_2_res_true_idx + 1]) - TAB

    if_bool_res_true_idx = subs_index(spl, "if (bool_res == True):")
    assert if_bool_res_true_idx > ac1_idx
    assert cntsp(spl[ac1_idx]) == cntsp(spl[if_bool_res_true_idx])

    assert "test_name.test(an='ac2')" in spl[if_bool_res_true_idx + 1]
    assert cntsp(spl[if_bool_res_true_idx]) == cntsp(
        spl[if_bool_res_true_idx + 1]) - TAB

    assert "test_name.test(an='ac3')" in spl[if_bool_res_true_idx + 2]
    assert cntsp(spl[if_bool_res_true_idx]) == cntsp(
        spl[if_bool_res_true_idx + 2]) - TAB

    ac6_idx = subs_index(spl, "test_name.test(an='ac6')")
    assert cntsp(spl[ac1_idx]) == cntsp(spl[ac6_idx])
    assert ac6_idx > if_bool_2_res_false_idx
    assert ac6_idx > if_bool_2_res_true_idx
Ejemplo n.º 16
0
def test_branched_output() -> None:

    scene = Scene("s1")
    obj = SceneObject("test_name", "Test")
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position())
    project.action_points.append(ap1)

    ac1 = Action("ac1", f"{obj.id}/test", flows=[Flow(outputs=["bool_res"])])
    ap1.actions.append(ac1)

    ac2 = Action("ac2", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac2)

    ac3 = Action("ac3", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac3)

    ac4 = Action("ac4", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac4)

    project.logic.append(LogicItem(LogicItem.START, ac1.id))

    project.logic.append(
        LogicItem(ac1.id, ac2.id,
                  ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(True))))
    project.logic.append(
        LogicItem(ac1.id, ac3.id,
                  ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(False))))

    project.logic.append(LogicItem(ac2.id, ac4.id))
    project.logic.append(LogicItem(ac3.id, ac4.id))
    project.logic.append(LogicItem(ac4.id, LogicItem.END))

    src = program_src({Test.__name__: Test}, CachedProject(project),
                      CachedScene(scene))
    parse(src)
    """
    bool_res = test_name.test(res.ac1)
    if bool_res == False:
        test_name.test(res.ac3)
    elif bool_res == True:
        test_name.test(res.ac2)
    test_name.test(res.ac4)
    """

    spl = src.splitlines()

    ac1_idx = subs_index(spl, "bool_res = test_name.test(an='ac1')")

    if_bool_res_false_idx = subs_index(spl, "if bool_res == False:")
    assert if_bool_res_false_idx > ac1_idx
    assert cntsp(spl[if_bool_res_false_idx]) == cntsp(spl[ac1_idx])
    assert "test_name.test(an='ac3')" in spl[if_bool_res_false_idx + 1]
    assert cntsp(spl[if_bool_res_false_idx]) == cntsp(
        spl[if_bool_res_false_idx + 1]) - TAB

    if_bool_res_true_idx = subs_index(spl, "if bool_res == True:")
    assert if_bool_res_true_idx > ac1_idx
    assert cntsp(spl[if_bool_res_true_idx]) == cntsp(spl[ac1_idx])
    assert "test_name.test(an='ac2')" in spl[if_bool_res_true_idx + 1]
    assert cntsp(spl[if_bool_res_true_idx]) == cntsp(
        spl[if_bool_res_true_idx + 1]) - TAB

    ac4_idx = subs_index(spl, "test_name.test(an='ac4')")
    assert ac4_idx > if_bool_res_false_idx
    assert ac4_idx > if_bool_res_true_idx
    assert cntsp(spl[ac4_idx]) == cntsp(spl[ac1_idx])