def test_two_parents_for_one_goal_is_forbidden(): with pytest.raises(AssertionError): build_goaltree( open_(1, "First parent of 3", [2, 3]), open_(2, "Second parent of 3", [3]), open_(3, "Fellow child"), )
def goaltree(): return FilterView( build_goaltree( open_(1, "Alpha", [2], [], selected), open_(2, "Beta", [3]), open_(3, "Gamma", []), ))
def test_how_should_we_deal_with_zooming(): g = build_goaltree( open_(1, "Root", [2]), open_(2, "Zoomed", blockers=[3], select=selected), open_(3, "Ex-top"), ) v = SwitchableView(persistent_layers(g)) v.accept_all(ToggleZoom(), ToggleSwitchableView()) assert v.q("name,select") == { 2: { "name": "Zoomed", "select": "select" }, 3: { "name": "Ex-top", "select": None }, } v.accept(Add("Unexpectedly hidden")) assert v.q("name,select") == { 2: { "name": "Zoomed", "select": "select" }, 3: { "name": "Ex-top", "select": None }, 4: { "name": "Unexpectedly hidden", "select": None }, }
def tree_3i_goals(): return AutoLink( build_goaltree( open_(1, "Root", [2]), open_(2, "Autolink on me", [3], select=selected), open_(3, "Another subgoal"), ))
def test_do_not_hide_unswitchable_goals_when_they_have_selection(): v = SwitchableView( build_goaltree( open_(1, "Selected", [2], select=selected), open_(2, "Prev-selected", [3], select=previous), open_(3, "Switchable"), )) v.accept_all(ToggleSwitchableView()) assert v.q("name,switchable,select") == { 1: { "name": "Selected", "switchable": False, "select": "select" }, 2: { "name": "Prev-selected", "switchable": False, "select": "prev" }, 3: { "name": "Switchable", "switchable": True, "select": None }, }
def extract_target(): return persistent_layers( build_goaltree( open_(1, "Extract root", [2, 3], select=selected), open_(2, "Subgoal", blockers=[3]), open_(3, "Selected subgoal (selection will be lost)", [4]), clos_(4, "Closed subgoal"), ))
def goaltree(): return ProgressView( build_goaltree( open_(1, "Root", [2, 3], select=selected), open_(2, "With blocker", [], [4]), open_(3, "With subgoal", [4]), open_(4, "Top goal"), ))
def test_toggle_hide_non_switchable_goals(): g = build_goaltree( open_(1, "Root", [2, 3]), open_(2, "Switchable 1", select=selected), open_(3, "Switchable 2"), ) e = SwitchableView(g) assert e.q(keys="name,switchable,select") == { 1: { "name": "Root", "switchable": False, "select": None }, 2: { "name": "Switchable 1", "switchable": True, "select": "select" }, 3: { "name": "Switchable 2", "switchable": True, "select": None }, } e.accept(ToggleSwitchableView()) assert e.q(keys="name,switchable,select") == { 2: { "name": "Switchable 1", "switchable": True, "select": "select" }, 3: { "name": "Switchable 2", "switchable": True, "select": None }, } e.accept(ToggleSwitchableView()) assert e.q(keys="name,switchable,select") == { 1: { "name": "Root", "switchable": False, "select": None }, 2: { "name": "Switchable 1", "switchable": True, "select": "select" }, 3: { "name": "Switchable 2", "switchable": True, "select": None }, }
def test_enumerated_goals_must_have_the_same_dimension(): e = Enumeration( build_goaltree( open_(1, "a", [2, 20], select=selected), open_(2, "b"), open_(20, "x") ) ) assert e.q(keys="name,switchable,select") == { 1: {"name": "a", "switchable": False, "select": "select"}, 2: {"name": "b", "switchable": True, "select": None}, 3: {"name": "x", "switchable": True, "select": None}, }
def test_use_different_long_edge_types(): goals = build_goaltree( open_(1, "Root", [2], [3], select=selected), open_(2, "A", [3]), open_(3, "B", []), ) result = Renderer(goals).build().graph assert get_in(result, "edge_render") == { 3: [], 2: [(3, EdgeType.PARENT)], "1_1": [(3, EdgeType.BLOCKER)], 1: [(2, EdgeType.PARENT), ("1_1", EdgeType.BLOCKER)], }
def test_simple_enumeration_is_not_changed(): e = Enumeration( build_goaltree( open_(1, "a", [2, 3]), open_(2, "b", blockers=[3], select=previous), open_(3, "c", select=selected), ) ) assert e.q(keys="name,edge") == { 1: {"name": "a", "edge": [(2, EdgeType.PARENT), (3, EdgeType.PARENT)]}, 2: {"name": "b", "edge": [(3, EdgeType.BLOCKER)]}, 3: {"name": "c", "edge": []}, }
def test_render_add_fake_vertex(): goals = build_goaltree( open_(1, "Root", [2, 3], select=selected), open_(2, "A", blockers=[3]), open_(3, "B"), ) result = Renderer(goals).build().graph assert get_in(result, "row") == { 3: 0, 2: 1, "1_1": 1, 1: 2, }
def test_closed_goals_are_shown_when_selected(): v = OpenView( build_goaltree( open_(1, "Root", [2, 3], select=selected), clos_(2, "closed"), clos_(3, "closed too", [4]), clos_(4, "closed and not selected"), )) v.accept_all(ToggleOpenView(), Select(2), HoldSelect(), Select(3)) assert v.q("name,select,open") == { 1: { "name": "Root", "open": True, "select": None }, 2: { "name": "closed", "open": False, "select": "prev" }, 3: { "name": "closed too", "open": False, "select": "select" }, 4: { "name": "closed and not selected", "open": False, "select": None }, } v.accept(ToggleOpenView()) # Still show: open goals, selected goals assert v.q("name,select,open") == { 1: { "name": "Root", "open": True, "select": None }, 2: { "name": "closed", "open": False, "select": "prev" }, 3: { "name": "closed too", "open": False, "select": "select" }, }
def goal_chain_10(): """a → b → c → ... → j""" return build_goaltree( open_(1, "a", [2], select=selected), open_(2, "b", [3]), open_(3, "c", [4]), open_(4, "d", [5]), open_(5, "e", [6]), open_(6, "f", [7]), open_(7, "g", [8]), open_(8, "h", [9]), open_(9, "i", [10]), open_(10, "j", []), )
def test_render_in_switchable_view(): goals = build_goaltree( open_(1, "Uno", [2, 3, 4, 5, 6]), open_(2, "Dos"), open_(3, "Tres"), open_(4, "Quatro"), open_(5, "Cinco"), open_(6, "Sext", select=selected), ) view = Enumeration(SwitchableView(goals)) view.accept(ToggleSwitchableView()) result = Renderer(view).build().graph # Just verify that it renders fine assert len(result) == 5
def test_do_not_add_autolink_to_root_goal(): messages: List[str] = [] goals = AutoLink( build_goaltree(open_(1, "Root", select=selected), message_fn=messages.append)) goals.accept(ToggleAutoLink("misused")) assert goals.q("name,edge") == { 1: { "name": "Root", "edge": [] }, } assert messages == ["Autolink cannot be set for the root goal"] assert _autolink_events(goals) == []
def test_render_simplest_goal_tree(): goals = build_goaltree(open_(1, "Alone", [], select=selected)) result = Renderer(goals).build().graph assert result == { 1: { "row": 0, "col": 0, "edge": [], "edge_render": [], "name": "Alone", "open": True, "select": "select", "switchable": True, } }
def test_render_4_subgoals_in_a_row(): goals = build_goaltree( open_(1, "Root", [2, 3, 4, 5], select=selected), open_(2, "A"), open_(3, "B"), open_(4, "C"), open_(5, "D"), ) result = Renderer(goals).build().graph assert get_in(result, "row") == { 2: 0, 3: 0, 4: 0, 5: 0, 1: 1, }
def test_dot_export(): goals = build_goaltree( open_(1, "Root", [2, 3, 4, 5], blockers=[6]), clos_( 2, "This is closed goal with no children or blockers. " "It also has a long name that must be compacted", ), open_(3, 'I have some "special" symbols', [6, 7], select=selected), clos_(4, ""), open_(5, "Many blockerz", blockers=[2, 4, 6, 7]), clos_(6, "!@#$%^&*()\\/,.?"), open_(7, ";:[{}]<>", select=previous), ) verify(dot_export(goals), reporter=GenericDiffReporterFactory().get_first_working())
def test_build_fake_links_to_far_closed_goals(): v = OpenView( build_goaltree( open_(1, "Root", blockers=[2], select=previous), clos_(2, "Middle", blockers=[3]), clos_(3, "Top", select=selected), )) assert v.q("select,edge") == { 1: { "select": "prev", "edge": [(3, EdgeType.BLOCKER)] }, 3: { "select": "select", "edge": [] }, }
def extract_source(): # Legend: goals marked with 'NX' must not be extracted return Enumeration( all_layers( build_goaltree( open_(1, "Root NX", [2, 3], select=selected), open_(2, "Extract root", [4, 5], blockers=[3]), open_(3, "External blocker NX", [7]), open_(4, "Subgoal", blockers=[5]), open_( 5, "Selected subgoal (selection will be lost)", [6], select=previous, ), clos_(6, "Closed subgoal", blockers=[7]), clos_(7, "Another external blocker NX"), )))
def test_still_show_root_when_it_is_closed_and_unselected(): v = OpenView( build_goaltree( clos_(1, "Hidden root", [2]), clos_(2, "Visible", select=selected), )) assert v.q("select,open,edge") == { 1: { "select": None, "open": False, "edge": [(2, EdgeType.PARENT)] }, 2: { "select": "select", "open": False, "edge": [] }, }
def test_render_5_subgoals_in_several_rows(): goals = build_goaltree( open_(1, "One", [2, 3, 4, 5, 6], select=selected), open_(2, "Two"), open_(3, "Three"), open_(4, "Four"), open_(5, "Five"), open_(6, "Six"), ) result = Renderer(goals).build().graph assert get_in(result, "row") == { 2: 0, 3: 0, 4: 0, 5: 0, 6: 1, "1_1": 1, 1: 2, }
def test_render_add_several_fake_vertex(): goals = build_goaltree( open_(1, "Root", [2, 5], select=selected), open_(2, "A", [3]), open_(3, "B", [4]), open_(4, "C", blockers=[5]), open_(5, "top"), ) result = Renderer(goals).build().graph assert get_in(result, "row") == { 5: 0, 4: 1, "1_1": 1, 3: 2, "1_2": 2, 2: 3, "1_3": 3, 1: 4, }
def test_extract_misordered(): source = Enumeration( all_layers( build_goaltree( open_(1, "Global root", [3], select=selected), open_(2, "Top"), open_(3, "Extraction root", [2]), ))) result = extract_subtree(source, 3) assert result.q("name,edge") == { 1: { "name": "Extraction root", "edge": [(2, EdgeType.PARENT)] }, 2: { "name": "Top", "edge": [] }, }
def test_split_long_edges_using_fake_goals(): goals = build_goaltree( open_(1, "Root", [2], blockers=[5], select=selected), open_(2, "A", [3]), open_(3, "B", [4]), open_(4, "C", [5]), open_(5, "top"), ) result = Renderer(goals).build().graph assert get_in(result, "edge_render") == { 5: [], 4: [(5, EdgeType.PARENT)], "1_1": [(5, EdgeType.BLOCKER)], 3: [(4, EdgeType.PARENT)], "1_2": [("1_1", EdgeType.BLOCKER)], 2: [(3, EdgeType.PARENT)], "1_3": [("1_2", EdgeType.BLOCKER)], 1: [(2, EdgeType.PARENT), ("1_3", EdgeType.BLOCKER)], }
def test_simple_open_enumeration_workflow(): e = OpenView( build_goaltree( open_(1, "Root", [2, 3], select=previous), open_(2, "1", select=selected), open_(3, "2"), )) assert e.q(keys="name,select,open,edge") == { 1: { "name": "Root", "select": "prev", "open": True, "edge": [(2, EdgeType.PARENT), (3, EdgeType.PARENT)], }, 2: { "name": "1", "select": "select", "open": True, "edge": [] }, 3: { "name": "2", "select": None, "open": True, "edge": [] }, } e.accept(ToggleClose()) assert e.q(keys="name,select,open,edge") == { 1: { "name": "Root", "select": "select", "open": True, "edge": [(3, EdgeType.PARENT)], }, 3: { "name": "2", "select": None, "open": True, "edge": [] }, }
def test_do_not_enumerate_goals_with_negative_id(): g = all_layers( build_goaltree( open_(1, "Root", [2]), open_(2, "Zoomed", [3], select=selected), open_(3, "Top"), ) ) g.accept(ToggleZoom()) assert g.q("name,select,edge") == { -1: {"name": "Root", "select": None, "edge": [(2, EdgeType.BLOCKER)]}, 2: {"name": "Zoomed", "select": "select", "edge": [(3, EdgeType.PARENT)]}, 3: {"name": "Top", "select": None, "edge": []}, } e = Enumeration(g) assert e.q("name,select,edge") == { -1: {"name": "Root", "select": None, "edge": [(1, EdgeType.BLOCKER)]}, 1: {"name": "Zoomed", "select": "select", "edge": [(2, EdgeType.PARENT)]}, 2: {"name": "Top", "select": None, "edge": []}, }
def test_do_not_add_autolink_to_closed_goals(): messages: List[str] = [] goals = AutoLink( build_goaltree( open_(1, "Root", [2]), clos_(2, "Well, it's closed", select=selected), message_fn=messages.append, )) goals.accept(ToggleAutoLink("Failed")) assert goals.q("name,edge") == { 1: { "name": "Root", "edge": [(2, EdgeType.PARENT)] }, 2: { "name": "Well, it's closed", "edge": [] }, } assert messages == ["Autolink cannot be set for closed goals"] assert _autolink_events(goals) == []
def test_render_example(): g = build_goaltree( open_(1, "Root", [2, 3, 4, 5, 6], [7, 8]), clos_(2, "Closed", blockers=[7]), open_(3, "Simply 3", blockers=[5, 8]), open_(4, "Also 4", blockers=[5, 6, 7, 8], select=selected), open_(5, "Now 5", blockers=[6]), clos_(6, "Same 6", blockers=[7]), clos_(7, "Lucky 7", [8], select=previous), clos_(8, "Finally 8"), ) r = Renderer(g) result = r.build() gp = FakeGeometry() adjust_graph(result, gp) lines = render_lines(gp, result) with io.StringIO() as out: print("== Graph\n", file=out) pprint(result.graph, out) print("\n== Geometry change after adjust\n", file=out) total_delta = Point(0, 0) for goal_id in g.goals: goal = result.graph[goal_id] delta = gp.top_left(goal["row"], goal["col"]) - Point( goal["x"], goal["y"]) total_delta += delta print(f"{goal_id}: dx={delta.x}, dy={delta.y}", file=out) avg_dx = total_delta.x // len(g.goals) avg_dy = total_delta.y // len(g.goals) print(f"Avg: dx={avg_dx}, dy={avg_dy}", file=out) print("\n== Edge options\n", file=out) pprint(result.edge_opts, out) print("\n== Lines", file=out) pprint(lines, out) verify(out.getvalue(), reporter=GenericDiffReporterFactory().get_first_working())