Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions mdl-examples/bug-tests/316-endevent-no-trailing-newline.mdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
-- ============================================================================
-- Bug #316: Synthetic trailing newline appended to EndEvent ReturnValue
-- ============================================================================
--
-- Symptom (before fix):
-- The microflow writer appended `"\n"` to every non-empty `ReturnValue`
-- when serializing EndEvent objects. Pristine Studio Pro MPRs do not
-- store that trailing newline, so any roundtrip through mxcli left a
-- detectable BSON drift versus the original .mpr — visible in `mx check`
-- diffs and in `mxcli diff-local` output even when no semantic change
-- had been authored.
--
-- After fix:
-- `writer_microflow.go` passes `ReturnValue` through directly. Empty
-- return values stay empty; non-empty ones are written without an
-- extra trailing newline.
--
-- Usage:
-- mxcli exec mdl-examples/bug-tests/316-endevent-no-trailing-newline.mdl -p app.mpr
-- mxcli -p app.mpr -c "describe microflow BugTest316.MF_ReturnExpr"
-- The describe output must round-trip cleanly under describe → exec → describe
-- and (when applied to a pristine Studio Pro project) `mx check` must
-- not report any cosmetic diff in the EndEvent ReturnValue field.
-- ============================================================================

create module BugTest316;

-- Microflow with a non-empty return value: the EndEvent's ReturnValue must
-- not pick up a synthetic trailing newline on serialization.
create microflow BugTest316.MF_ReturnExpr (
$value: integer
)
returns boolean as $isPositive
begin
return $value > 0;
end;
/

-- Microflow with no return value (procedure): EndEvent ReturnValue stays empty.
create microflow BugTest316.MF_NoReturn ()
begin
log info node 'BugTest316' 'side effect only';
end;
/
11 changes: 4 additions & 7 deletions sdk/mpr/writer_microflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,13 +466,10 @@ func serializeMicroflowObject(obj microflows.MicroflowObject) bson.D {
}

case *microflows.EndEvent:
// Pristine EndEvents always carry `ReturnValue` (empty string for void
// microflows; expression + "\n" when a value is returned). Omitting it
// diverges from the pristine key set on Mx 9 roundtrips.
returnValue := ""
if o.ReturnValue != "" {
returnValue = o.ReturnValue + "\n"
}
// Pristine Mx 9 EndEvents carry `ReturnValue` but not a synthetic trailing
// line break. Adding one can make Studio Pro reject list-return EndEvents
// with CE0117 even though mxcli's parser accepts the expression.
returnValue := o.ReturnValue
doc := bson.D{
{Key: "$ID", Value: idToBsonBinary(string(o.ID))},
{Key: "$Type", Value: "Microflows$EndEvent"},
Expand Down
32 changes: 32 additions & 0 deletions sdk/mpr/writer_microflow_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,38 @@ func TestSerializeSequenceFlow_Mx10_UsesModernShape(t *testing.T) {
}
}

func TestSerializeEndEvent_EmptyReturnValueHasNoTrailingLineBreak(t *testing.T) {
end := &microflows.EndEvent{
BaseMicroflowObject: microflows.BaseMicroflowObject{
BaseElement: model.BaseElement{ID: "end-empty"},
Position: model.Point{X: 10, Y: 20},
Size: model.Size{Width: 20, Height: 20},
},
ReturnValue: "empty",
}

doc := serializeMicroflowObject(end)
if got := bsonGetKey(doc, "ReturnValue"); got != "empty" {
t.Fatalf("ReturnValue = %q, want %q", got, "empty")
}
}

func TestSerializeEndEvent_NonEmptyReturnValueHasNoSyntheticLineBreak(t *testing.T) {
end := &microflows.EndEvent{
BaseMicroflowObject: microflows.BaseMicroflowObject{
BaseElement: model.BaseElement{ID: "end-result"},
Position: model.Point{X: 10, Y: 20},
Size: model.Size{Width: 20, Height: 20},
},
ReturnValue: "$Result",
}

doc := serializeMicroflowObject(end)
if got := bsonGetKey(doc, "ReturnValue"); got != "$Result" {
t.Fatalf("ReturnValue = %q, want %q", got, "$Result")
}
}

func TestSerializeAnnotationFlow_VersionShapes(t *testing.T) {
af := &microflows.AnnotationFlow{
BaseElement: model.BaseElement{ID: "af-1"},
Expand Down