Skip to content

Commit 63e5cd6

Browse files
committed
parseGroup: stop misattributing body fields after nested groups
1 parent 7dfe5b3 commit 63e5cd6

2 files changed

Lines changed: 20 additions & 20 deletions

File tree

message.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ func parseGroup(mp *msgParser, tags []Tag) {
310310
dm := mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]
311311
fields := getGroupFields(mp.msg, tags, mp.appDataDictionary)
312312

313+
parseLoop:
313314
for {
314315
mp.fieldIndex++
315316
mp.parsedFieldBytes = &mp.msg.fields[mp.fieldIndex]
@@ -350,16 +351,18 @@ func parseGroup(mp *msgParser, tags []Tag) {
350351
fields = getGroupFields(mp.msg, searchTags, mp.appDataDictionary)
351352
continue
352353
}
353-
if len(tags) > 1 {
354-
searchTags = tags[:len(tags)-1]
355-
}
356-
// Did this tag occur after a nested group and belongs to the parent group.
357-
if isNumInGroupField(mp.msg, searchTags, mp.appDataDictionary) {
358-
// Add the field member to the group.
359-
dm = append(dm, *mp.parsedFieldBytes)
360-
// Continue parsing the parent group.
361-
fields = getGroupFields(mp.msg, searchTags, mp.appDataDictionary)
362-
continue
354+
// The field closed one or more nested groups. Pop back up the
355+
// group stack: if some ancestor's template owns this tag, resume
356+
// parsing in that scope. Otherwise the field belongs at the body
357+
// level and must surface there — not be absorbed into the parent.
358+
for len(tags) > 1 {
359+
tags = tags[:len(tags)-1]
360+
ancestorFields := getGroupFields(mp.msg, tags, mp.appDataDictionary)
361+
if isGroupMember(mp.parsedFieldBytes.tag, ancestorFields) {
362+
dm = append(dm, *mp.parsedFieldBytes)
363+
fields = ancestorFields
364+
continue parseLoop
365+
}
363366
}
364367
// Add the repeating group.
365368
mp.msg.Body.add(dm)

message_test.go

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,13 @@ func (s *MessageSuite) TestParseGroup_BodyFieldAfterNestedGroup() {
143143
// NoQuoteSets count (group delimiter) lands in Body as expected.
144144
s.True(s.msg.Body.Has(Tag(296)))
145145

146-
// ToDo: should be correct — QuoteStatus (297) must be a top-level body
147-
// field per FIX 4.4. Current parseGroup logic silently absorbs 297 into
148-
// the NoQuoteSets group buffer because it only checks whether the
149-
// parent tag is a NumInGroup, not whether 297 is a member of the
150-
// parent group template.
151-
s.False(s.msg.Body.Has(Tag(297)),
152-
"BUG: QuoteStatus (297) is absent from Body.FieldMap — parser "+
153-
"mis-attributed it to the parent NoQuoteSets group. This "+
154-
"assertion documents the bug; flip to s.True(...) when "+
155-
"parseGroup is fixed.")
146+
// QuoteStatus (297) must be a top-level body field per FIX 4.4.
147+
s.True(s.msg.Body.Has(Tag(297)),
148+
"QuoteStatus (297) must land at the body level; it is a body field "+
149+
"in MassQuoteAcknowledgement, not a member of NoQuoteSets.")
150+
val, verr := s.msg.Body.GetInt(Tag(297))
151+
s.Nil(verr)
152+
s.Equal(1, val)
156153
}
157154

158155
func (s *MessageSuite) TestBuild() {

0 commit comments

Comments
 (0)