Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added xml counterparts for all examples #5

Merged
merged 13 commits into from
Nov 1, 2023
2 changes: 1 addition & 1 deletion bpmnconstraints/compiler/bpmn_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def __compile(self):
self.__create_response_constraint()

def _create_gateway_constraints(self):
if self.__get_cfo_type() == XOR_GATEWAY:
if self.__get_cfo_type() in XOR_GATEWAY:
self.__create_exclusive_choice_constraint()

if self.__get_cfo_type() == AND_GATEWAY:
Expand Down
6 changes: 4 additions & 2 deletions bpmnconstraints/parser/bpmn_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,13 @@ def validate_splitting_and_joining_gateway_cases(self):

item_indices = {item["name"]: index for index, item in enumerate(self.sequence)}
for cfo in self.sequence:
if cfo["is start"] and cfo["name"] == "XOR":
if cfo["is start"] and (cfo["type"] in DISCARDED_START_GATEWAYS):
cfo["is start"] = False
for successor in cfo["successor"]:
self.sequence[item_indices[successor["name"]]]["is start"] = True
if cfo["is end"] and cfo["name"] in GATEWAY_NAMES:
if cfo["is end"] and (
cfo["name"] in GATEWAY_NAMES or cfo["type"] == "exclusivegateway"
):
cfo["is end"] = False
for predecessor in cfo["predecessor"]:
self.sequence[item_indices[predecessor["name"]]]["is end"] = True
Expand Down
5 changes: 4 additions & 1 deletion bpmnconstraints/parser/xml_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ def __xml_to_dict(self, input_dict):
if key.startswith("@"):
new_dict[key[1:]] = value
elif key.endswith(":outgoing"):
new_dict["outgoing"].append(value)
if isinstance(value, list):
new_dict["outgoing"].extend(value)
else:
new_dict["outgoing"].append(value)
else:
new_dict[key] = value
return new_dict
Expand Down
4 changes: 3 additions & 1 deletion bpmnconstraints/utils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"exclusivegateway",
]

DISCARDED_START_GATEWAYS = ["exclusive_databased_gateway", "exclusivegateway"]

ALLOWED_ACTIVITIES = [
"task",
"event",
Expand Down Expand Up @@ -148,7 +150,7 @@
"OR",
]

XOR_GATEWAY = "exclusive_databased_gateway"
XOR_GATEWAY = ["exclusive_databased_gateway", "exclusivegateway"]
AND_GATEWAY = "parallelgateway"
OR_GATEWAY = "inclusivegateway"

Expand Down
844 changes: 844 additions & 0 deletions examples/advanced/student_project.xml

Large diffs are not rendered by default.

508 changes: 508 additions & 0 deletions examples/advanced/underwriter.xml

Large diffs are not rendered by default.

1,172 changes: 1,172 additions & 0 deletions examples/and_gates/longer_and.xml

Large diffs are not rendered by default.

514 changes: 514 additions & 0 deletions examples/and_gates/single_and.xml

Large diffs are not rendered by default.

688 changes: 688 additions & 0 deletions examples/combinations/nested_and_or.xml

Large diffs are not rendered by default.

868 changes: 868 additions & 0 deletions examples/combinations/nested_and_or_xor.xml

Large diffs are not rendered by default.

1,173 changes: 1,173 additions & 0 deletions examples/combinations/nested_and_xor.xml

Large diffs are not rendered by default.

694 changes: 694 additions & 0 deletions examples/combinations/nested_xor_or.xml

Large diffs are not rendered by default.

565 changes: 565 additions & 0 deletions examples/linear/linear_sequence.xml

Large diffs are not rendered by default.

738 changes: 738 additions & 0 deletions examples/loops/activity_in_loop.xml

Large diffs are not rendered by default.

918 changes: 918 additions & 0 deletions examples/loops/gateway_in_loop_back.xml

Large diffs are not rendered by default.

1,028 changes: 1,028 additions & 0 deletions examples/loops/gateway_in_loop_back_2.xml

Large diffs are not rendered by default.

921 changes: 921 additions & 0 deletions examples/loops/inner_xor_loop.xml

Large diffs are not rendered by default.

1,106 changes: 1,106 additions & 0 deletions examples/loops/loop_with_multiple_xor.xml

Large diffs are not rendered by default.

810 changes: 810 additions & 0 deletions examples/loops/nested_loop.xml

Large diffs are not rendered by default.

637 changes: 637 additions & 0 deletions examples/loops/simple_loop.xml

Large diffs are not rendered by default.

848 changes: 848 additions & 0 deletions examples/loops/two_activities_in_loop.xml

Large diffs are not rendered by default.

752 changes: 752 additions & 0 deletions examples/loops/two_outgoing_loops.xml

Large diffs are not rendered by default.

1,064 changes: 1,064 additions & 0 deletions examples/main_example/Credit_quote_creation_simplified_SAP Signavio.xml

Large diffs are not rendered by default.

677 changes: 677 additions & 0 deletions examples/misc/multiple_endings.xml

Large diffs are not rendered by default.

512 changes: 512 additions & 0 deletions examples/misc/multiple_starts.xml

Large diffs are not rendered by default.

781 changes: 781 additions & 0 deletions examples/misc/nested_lanes.xml

Large diffs are not rendered by default.

394 changes: 394 additions & 0 deletions examples/misc/no_start_no_end.xml

Large diffs are not rendered by default.

852 changes: 852 additions & 0 deletions examples/or_gates/single_or_gateway.xml

Large diffs are not rendered by default.

1,264 changes: 1,264 additions & 0 deletions examples/xor_gates/3_way_split_xor.xml

Large diffs are not rendered by default.

1,546 changes: 1,546 additions & 0 deletions examples/xor_gates/double_nested_trailing_values.xml

Large diffs are not rendered by default.

1,178 changes: 1,178 additions & 0 deletions examples/xor_gates/longer_xor.xml

Large diffs are not rendered by default.

924 changes: 924 additions & 0 deletions examples/xor_gates/multiple_xor.xml

Large diffs are not rendered by default.

1,109 changes: 1,109 additions & 0 deletions examples/xor_gates/nested_xor.xml

Large diffs are not rendered by default.

1,360 changes: 1,360 additions & 0 deletions examples/xor_gates/nested_xor_with_before_and_after_activities.xml

Large diffs are not rendered by default.

1,234 changes: 1,234 additions & 0 deletions examples/xor_gates/nested_xor_with_double_ending.xml

Large diffs are not rendered by default.

740 changes: 740 additions & 0 deletions examples/xor_gates/single_xor.xml

Large diffs are not rendered by default.

26 changes: 17 additions & 9 deletions tests/file_constants.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END = {
"path": "examples/linear/linear_sequence.json",
"start element id": "sid-79912385-C358-446C-8EBB-07429B015548",
"end element id": "sid-BEA0DEB9-2482-42D9-9846-9E6C5541FA54",
"successor id": "sid-338230CF-C52B-4C83-9B4E-A8388E336593",
}

LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END_XML = {
"path": "examples/xml/Invoice processing.xml",
"xmlpath": "examples/linear/linear_sequence.xml",
"start element id": "sid-79912385-C358-446C-8EBB-07429B015548",
"end element id": "sid-BEA0DEB9-2482-42D9-9846-9E6C5541FA54",
"successor id": "sid-338230CF-C52B-4C83-9B4E-A8388E336593",
}

LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END = {
"path": "examples/misc/no_start_no_end.json",
"xmlpath": "examples/misc/no_start_no_end.xml",
"start element id": "sid-E9508543-5660-4C85-9E42-1119DAAD80C2",
"end element id": "sid-08543ADB-C8D6-4026-8A03-1228CC559A7F",
}

MULTIPLE_STARTS_DIAGRAM = {
"path": "examples/misc/multiple_starts.json",
"xmlpath": "examples/misc/multiple_starts.xml",
"start elements": [
"sid-63552E64-B2A2-4D39-A168-2C6A30BB76F7",
"sid-AB69BFC4-A028-480F-BC16-BAC74F4A8EDD",
Expand All @@ -28,6 +24,7 @@

MULTIPLE_ENDINGS_DIAGRAM = {
"path": "examples/misc/multiple_endings.json",
"xmlpath": "examples/misc/multiple_endings.xml",
"ending elements": [
"sid-F54D1372-E982-4B0F-9543-F3CC3C6F595F",
"sid-42CD2A75-895E-4E2C-9340-6CE7C5570EFF",
Expand All @@ -37,12 +34,14 @@

SINGLE_XOR_GATEWAY_DIAGRAM = {
"path": "examples/xor_gates/single_xor.json",
"xmlpath": "examples/xor_gates/single_xor.xml",
"splitting id": "sid-E1967D7F-6A3B-40CB-A8E9-31606735C37A",
"joining id": "sid-87FDC0D7-9BEE-4FB2-952A-FEDEA56F73AA",
}

THREE_SPLIT_XOR_GATEWAY_DIAGRAM = {
"path": "examples/xor_gates/3_way_split_xor.json",
"xmlpath": "examples/xor_gates/3_way_split_xor.xml",
"splitting id": "sid-7946CDE8-E0E9-4730-8D59-E48E15C331B8",
"successors": [
"sid-DEEAF1CC-6862-41BE-8FE4-C9630A72A6E7",
Expand All @@ -53,6 +52,7 @@

PARALLEL_GATEWAY_DIAGRAM = {
"path": "examples/and_gates/longer_and.json",
"xmlpath": "examples/and_gates/longer_and.xml",
"start element id": "sid-2FE6222A-6971-4860-AD8D-535CED93A0A2",
"ending element id": "sid-41F52A20-F3FC-4363-9A0C-A73114841060",
"gateway elements": [
Expand All @@ -69,18 +69,26 @@
],
}

XOR_GATEWAY_DIAGRAM = {"path": "examples/xor_gates/longer_xor.json"}
XOR_GATEWAY_DIAGRAM = {
"path": "examples/xor_gates/longer_xor.json",
"xmlpath": "examples/xor_gates/longer_xor.xml",
}

XOR_GATEWAY_SEQUENCE_DIAGRAM = {"path": "examples/xor_gates/multiple_xor.json"}
XOR_GATEWAY_SEQUENCE_DIAGRAM = {
"path": "examples/xor_gates/multiple_xor.json",
"xmlpath": "examples/xor_gates/multiple_xor.xml",
}

REQUIREMENTS_TXT = {"path": "requirements.txt"}

LINEAR_MERMAID_GRAPH = {
"path": "examples/linear/linear_sequence.json",
"xmlpath": "examples/linear/linear_sequence.xml",
"output": "flowchart LR\n0:startnoneevent:((start))-->1:task:(register invoice)\n1:task:-->2:task:(check invoice)\n2:task:-->3:task:(accept invoice)\n3:task:-->4:endnoneevent:((end))",
}

GATEWAY_MERMAID_GRAPH = {
"path": "examples/xor_gates/single_xor.json",
"xmlpath": "examples/xor_gates/single_xor.xml",
"output": "flowchart LR\n0:exclusive_databased_gateway:{XOR}-->1:task:(second activity)\n0:exclusive_databased_gateway:{XOR}-->2:task:(first activity)\n3:exclusive_databased_gateway:{XOR}-->4:task:(third activity)\n2:task:-->3:exclusive_databased_gateway:\n1:task:-->3:exclusive_databased_gateway:\n4:task:-->5:endnoneevent:((endnoneevent))\n6:startnoneevent:((startnoneevent))-->7:task:(zero activity)\n7:task:-->0:exclusive_databased_gateway:",
}
35 changes: 30 additions & 5 deletions tests/test_end_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,39 @@ def test_end_constraint_is_generated_without_explicit_end_event():
assert "End[second element]" in res


def test_end_constraint_is_generated_when_multiple_endings():
res = init_test_setup_for_parser(XOR_GATEWAY_SEQUENCE_DIAGRAM)
def test_end_constraint_is_generated_when_xor_gateway():
res = init_test_setup_for_compiler(XOR_GATEWAY_SEQUENCE_DIAGRAM)
expected_ending_constraints = [
"End[activity four]",
"End[activity five]",
]
assert all(constraint in res for constraint in expected_ending_constraints)

assert res[-1]["is end"] and res[-2]["is end"] and not res[3]["is end"]

def test_end_constraint_is_generated_when_multiple_endings_XML():
res = init_test_setup_for_compiler(MULTIPLE_ENDINGS_DIAGRAM, test_xml=True)
expected_ending_constraints = [
"End[ending one]",
"End[ending two]",
"End[ending three]",
]
assert all(constraint in res for constraint in expected_ending_constraints)

def test_end_constraint_is_generated_when_xor_gateway():
res = init_test_setup_for_compiler(XOR_GATEWAY_SEQUENCE_DIAGRAM)

def test_end_constraint_is_generated_with_linear_parser_XML():
res = init_test_setup_for_parser(LINEAR_MERMAID_GRAPH, test_xml=True)
assert res[-1]["is end"] == True


def test_end_constraint_is_generated_without_explicit_end_event_XML():
res = init_test_setup_for_compiler(
LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END, test_xml=True
)
assert "End[second element]" in res


def test_end_constraint_is_generated_when_xor_gateway_XML():
res = init_test_setup_for_compiler(XOR_GATEWAY_SEQUENCE_DIAGRAM, test_xml=True)
expected_ending_constraints = [
"End[activity four]",
"End[activity five]",
Expand Down
10 changes: 10 additions & 0 deletions tests/test_gateway_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,13 @@ def test_that_all_gateway_constraints_are_generated():
]
# assert res == expected_gateway_constraints
assert all(constraint in res for constraint in expected_gateway_constraints)


def test_that_all_gateway_constraints_are_generated_XML():
res = init_test_setup_for_compiler(THREE_SPLIT_XOR_GATEWAY_DIAGRAM, True)
expected_gateway_constraints = [
"Exclusive Choice[activity four, activity two]",
"Exclusive Choice[activity three, activity two]",
"Exclusive Choice[activity three, activity four]",
]
assert all(constraint in res for constraint in expected_gateway_constraints)
24 changes: 24 additions & 0 deletions tests/test_gateway_splitting_joining.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,27 @@ def test_gateway_splitting_to_three_paths():
assert sorted(successors_id) == sorted(
THREE_SPLIT_XOR_GATEWAY_DIAGRAM.get("successors")
)


def test_element_is_marked_as_splitting_gateway_if_it_is_splitting_xml():
res = init_test_setup_for_parser(SINGLE_XOR_GATEWAY_DIAGRAM, True)
for elem in res:
if elem.get("id") == SINGLE_XOR_GATEWAY_DIAGRAM.get("splitting id"):
assert elem.get("splitting")


def test_element_is_marked_as_joining_gateway_if_it_is_joining_xml():
res = init_test_setup_for_parser(SINGLE_XOR_GATEWAY_DIAGRAM, True)
for elem in res:
if elem.get("id") == SINGLE_XOR_GATEWAY_DIAGRAM.get("joining id"):
assert elem.get("joining")


def test_gateway_splitting_to_three_paths_xml():
res = init_test_setup_for_parser(THREE_SPLIT_XOR_GATEWAY_DIAGRAM, True)
for elem in res:
if elem.get("id") == THREE_SPLIT_XOR_GATEWAY_DIAGRAM.get("splitting id"):
successors_id = [x.get("id") for x in elem.get("successor")]
assert sorted(successors_id) == sorted(
THREE_SPLIT_XOR_GATEWAY_DIAGRAM.get("successors")
)
27 changes: 27 additions & 0 deletions tests/test_init_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,30 @@ def test_missing_init_constraints_for_XOR_gate():
"Init[activity two]",
]
assert all(constraint in res for constraint in expected_init_constraints)


def test_init_constraint_is_generated_without_explicit_start_event_xml():
res = init_test_setup_for_compiler(
LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END, True
)
assert "Init[first element]" in res


def test_that_each_start_has_init_constraint_xml():
res = init_test_setup_for_compiler(MULTIPLE_STARTS_DIAGRAM, True)
expected_init_constraints = ["Init[path one]", "Init[path two]"]
assert all(constraint in res for constraint in expected_init_constraints)


def test_missing_init_constraints_for_XOR_gate_parser_xml():
res = init_test_setup_for_parser(XOR_GATEWAY_SEQUENCE_DIAGRAM, True)
assert res[4]["is start"] and res[5]["is start"] and not res[0]["is start"]


def test_missing_init_constraints_for_XOR_gate_xml():
res = init_test_setup_for_compiler(XOR_GATEWAY_SEQUENCE_DIAGRAM, True)
expected_init_constraints = [
"Init[activity one]",
"Init[activity two]",
]
assert all(constraint in res for constraint in expected_init_constraints)
31 changes: 31 additions & 0 deletions tests/test_is_end.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,34 @@ def test_all_start_elements_are_marked_as_ending_if_multiple_endings():
):
end_count += 1
assert end_count == len(MULTIPLE_ENDINGS_DIAGRAM.get("ending elements"))


def test_element_is_marked_as_end_if_it_has_no_successors_xml():
res = init_test_setup_for_parser(
LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END, True
)
for elem in res:
if elem.get("is end"):
assert elem.get("id") == LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END.get(
"end element id"
)


def test_element_is_marked_as_end_if_successor_is_end_event_xml():
res = init_test_setup_for_parser(LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END, True)
for elem in res:
if elem.get("is end"):
assert elem.get("id") == LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END.get(
"end element id"
)


def test_all_start_elements_are_marked_as_ending_if_multiple_endings_xml():
res = init_test_setup_for_parser(MULTIPLE_ENDINGS_DIAGRAM, True)
end_count = 0
for elem in res:
if elem.get("is end") and elem.get("id") in MULTIPLE_ENDINGS_DIAGRAM.get(
"ending elements"
):
end_count += 1
assert end_count == len(MULTIPLE_ENDINGS_DIAGRAM.get("ending elements"))
31 changes: 31 additions & 0 deletions tests/test_is_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,34 @@ def test_all_start_elements_are_marked_as_starts_if_multiple_starts():
):
start_count += 1
assert start_count == len(MULTIPLE_STARTS_DIAGRAM.get("start elements"))


def test_element_is_marked_as_start_if_it_has_no_predecessors_xml():
res = init_test_setup_for_parser(
LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END, True
)
for elem in res:
if elem.get("is start"):
assert elem.get("id") == LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END.get(
"start element id"
)


def test_element_is_marked_as_start_if_predecessor_is_start_event_xml():
res = init_test_setup_for_parser(LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END, True)
for elem in res:
if elem.get("is start"):
assert elem.get("id") == LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END.get(
"start element id"
)


def test_all_start_elements_are_marked_as_starts_if_multiple_starts_xml():
res = init_test_setup_for_parser(MULTIPLE_STARTS_DIAGRAM, True)
start_count = 0
for elem in res:
if elem.get("is start") and elem.get("id") in MULTIPLE_STARTS_DIAGRAM.get(
"start elements"
):
start_count += 1
assert start_count == len(MULTIPLE_STARTS_DIAGRAM.get("start elements"))
20 changes: 20 additions & 0 deletions tests/test_part_of_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,23 @@ def test_element_outside_gateway_construct_is_not_marked_as_part_of_gateway():
assert num_elems_not_in_gateway == len(
PARALLEL_GATEWAY_DIAGRAM.get("not gateway elements")
)


def test_element_in_gateway_construct_is_marked_as_part_of_gateway_xml():
res = init_test_setup_for_parser(PARALLEL_GATEWAY_DIAGRAM, True)
num_elems_in_gateway = 0
for elem in res:
if elem.get("id") in PARALLEL_GATEWAY_DIAGRAM.get("gateway elements"):
num_elems_in_gateway += 1
assert num_elems_in_gateway == len(PARALLEL_GATEWAY_DIAGRAM.get("gateway elements"))


def test_element_outside_gateway_construct_is_not_marked_as_part_of_gateway_xml():
res = init_test_setup_for_parser(PARALLEL_GATEWAY_DIAGRAM, True)
num_elems_not_in_gateway = 0
for elem in res:
if elem.get("id") in PARALLEL_GATEWAY_DIAGRAM.get("not gateway elements"):
num_elems_not_in_gateway += 1
assert num_elems_not_in_gateway == len(
PARALLEL_GATEWAY_DIAGRAM.get("not gateway elements")
)
22 changes: 22 additions & 0 deletions tests/test_precedence_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,25 @@ def test_precedence_constraint_is_generated_for_element_between_two_gateway_cons
"Alternate Precedence[activity three, activity five]",
]
assert all(constraint in res for constraint in expected_precedence_constraints)


def test_precedence_constraint_is_generated_for_splitting_gateway_xml():
res = init_test_setup_for_compiler(XOR_GATEWAY_DIAGRAM, True)
expected_precedence_constraints = [
"Precedence[first activity, second activity upper]",
"Precedence[first activity, second activity lower]",
"Alternate Precedence[first activity, second activity upper]",
"Alternate Precedence[first activity, second activity lower]",
]
assert all(constraint in res for constraint in expected_precedence_constraints)


def test_precedence_constraint_is_generated_for_element_between_two_gateway_constructs_xml():
res = init_test_setup_for_compiler(XOR_GATEWAY_SEQUENCE_DIAGRAM, True)
expected_precedence_constraints = [
"Precedence[activity three, activity four]",
"Precedence[activity three, activity five]",
"Alternate Precedence[activity three, activity four]",
"Alternate Precedence[activity three, activity five]",
]
assert all(constraint in res for constraint in expected_precedence_constraints)
Loading