Skip to content

Commit 437b447

Browse files
committed
fix: emit boolean case values for IF flows
Symptom: MPR validation can report duplicate output variables for values declared in mutually exclusive IF branches after exec builds the graph, even though the source paths are exclusive. Root cause: IF sequence flows used EnumerationCase values with the strings "true" and "false". Studio Pro accepts the graph shape, but its consistency checker does not treat those flows as proper boolean split branches for variable scoping. Fix: emit BooleanCase for true/false flow cases and keep EnumerationCase for real enum branch values. Update existing tests to assert boolean cases for boolean split continuations. Tests: make build, make test, make lint-go.
1 parent da6f250 commit 437b447

3 files changed

Lines changed: 53 additions & 17 deletions

File tree

mdl/executor/cmd_microflows_builder_enum_split_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func TestEnumSplitNestedEmptyThenBranchKeepsContinuationCase(t *testing.T) {
111111
if flow.OriginID != nestedSplitID {
112112
continue
113113
}
114-
if value, ok := enumCaseValue(flow); ok && value == "true" {
114+
if flowCaseString(flow.CaseValue) == "true" {
115115
if _, ok := objects[flow.DestinationID].(*microflows.ExclusiveMerge); ok {
116116
return
117117
}

mdl/executor/cmd_microflows_builder_flows.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -653,10 +653,7 @@ func newHorizontalFlow(originID, destinationID model.ID) *microflows.SequenceFlo
653653
// newHorizontalFlowWithCase creates a horizontal SequenceFlow with a boolean case value (for splits)
654654
func newHorizontalFlowWithCase(originID, destinationID model.ID, caseValue string) *microflows.SequenceFlow {
655655
flow := newHorizontalFlow(originID, destinationID)
656-
flow.CaseValue = microflows.EnumerationCase{
657-
BaseElement: model.BaseElement{ID: model.ID(types.GenerateID())},
658-
Value: caseValue, // "true" or "false" as string
659-
}
656+
flow.CaseValue = caseValueForFlow(caseValue)
660657
return flow
661658
}
662659

@@ -678,10 +675,27 @@ func newDownwardFlowWithCase(originID, destinationID model.ID, caseValue string)
678675
DestinationID: destinationID,
679676
OriginConnectionIndex: AnchorBottom, // Connect from bottom of origin (going down)
680677
DestinationConnectionIndex: AnchorLeft, // Connect to left side of destination
681-
CaseValue: microflows.EnumerationCase{
678+
CaseValue: caseValueForFlow(caseValue),
679+
}
680+
}
681+
682+
func caseValueForFlow(caseValue string) microflows.CaseValue {
683+
switch caseValue {
684+
case "true":
685+
return microflows.BooleanCase{
682686
BaseElement: model.BaseElement{ID: model.ID(types.GenerateID())},
683-
Value: caseValue, // "true" or "false" as string
684-
},
687+
Value: true,
688+
}
689+
case "false":
690+
return microflows.BooleanCase{
691+
BaseElement: model.BaseElement{ID: model.ID(types.GenerateID())},
692+
Value: false,
693+
}
694+
default:
695+
return microflows.EnumerationCase{
696+
BaseElement: model.BaseElement{ID: model.ID(types.GenerateID())},
697+
Value: caseValue,
698+
}
685699
}
686700
}
687701

mdl/executor/cmd_microflows_guard_pattern_test.go

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,11 @@ func TestBuilder_GuardPatternPreservesFalseBranchAnchor(t *testing.T) {
4747
oc := fb.buildFlowGraph(body, nil)
4848

4949
// Find the flow from the split to the tail log. It's the only one with
50-
// an EnumerationCase Value=="false" that doesn't target an EndEvent.
50+
// a BooleanCase Value==false that doesn't target an EndEvent.
5151
var found *microflows.SequenceFlow
5252
for _, f := range oc.Flows {
53-
cv, ok := f.CaseValue.(microflows.EnumerationCase)
54-
if !ok {
55-
if p, okp := f.CaseValue.(*microflows.EnumerationCase); okp {
56-
cv = *p
57-
ok = true
58-
}
59-
}
60-
if !ok || cv.Value != "false" {
53+
cv, ok := f.CaseValue.(microflows.BooleanCase)
54+
if !ok || cv.Value {
6155
continue
6256
}
6357
// Exclude flows pointing at an EndEvent.
@@ -85,3 +79,31 @@ func TestBuilder_GuardPatternPreservesFalseBranchAnchor(t *testing.T) {
8579
t.Errorf("destination: got %d, want %d (Top)", found.DestinationConnectionIndex, AnchorTop)
8680
}
8781
}
82+
83+
func TestCaseValueForFlowUsesBooleanCaseForBooleanBranches(t *testing.T) {
84+
for _, tc := range []struct {
85+
value string
86+
want bool
87+
}{
88+
{value: "true", want: true},
89+
{value: "false", want: false},
90+
} {
91+
got, ok := caseValueForFlow(tc.value).(microflows.BooleanCase)
92+
if !ok {
93+
t.Fatalf("caseValueForFlow(%q) = %T, want BooleanCase", tc.value, caseValueForFlow(tc.value))
94+
}
95+
if got.Value != tc.want {
96+
t.Fatalf("caseValueForFlow(%q).Value = %v, want %v", tc.value, got.Value, tc.want)
97+
}
98+
}
99+
}
100+
101+
func TestCaseValueForFlowKeepsEnumValuesAsEnumerationCase(t *testing.T) {
102+
got, ok := caseValueForFlow("Submitted").(microflows.EnumerationCase)
103+
if !ok {
104+
t.Fatalf("caseValueForFlow(enum) = %T, want EnumerationCase", caseValueForFlow("Submitted"))
105+
}
106+
if got.Value != "Submitted" {
107+
t.Fatalf("enum case value = %q, want Submitted", got.Value)
108+
}
109+
}

0 commit comments

Comments
 (0)