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
20 changes: 10 additions & 10 deletions message.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ func parseGroup(mp *msgParser, tags []Tag) {
dm := mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]
fields := getGroupFields(mp.msg, tags, mp.appDataDictionary)

parseLoop:
for {
mp.fieldIndex++
mp.parsedFieldBytes = &mp.msg.fields[mp.fieldIndex]
Expand Down Expand Up @@ -350,16 +351,15 @@ func parseGroup(mp *msgParser, tags []Tag) {
fields = getGroupFields(mp.msg, searchTags, mp.appDataDictionary)
continue
}
if len(tags) > 1 {
searchTags = tags[:len(tags)-1]
}
// Did this tag occur after a nested group and belongs to the parent group.
if isNumInGroupField(mp.msg, searchTags, mp.appDataDictionary) {
// Add the field member to the group.
dm = append(dm, *mp.parsedFieldBytes)
// Continue parsing the parent group.
fields = getGroupFields(mp.msg, searchTags, mp.appDataDictionary)
continue
// The tag isn't a member of the current group. Walk up: if an
// ancestor group includes it, resume there; otherwise it's body-level.
for len(tags) > 1 {
tags = tags[:len(tags)-1]
fields = getGroupFields(mp.msg, tags, mp.appDataDictionary)
if isGroupMember(mp.parsedFieldBytes.tag, fields) {
dm = append(dm, *mp.parsedFieldBytes)
continue parseLoop
}
}
// Add the repeating group.
mp.msg.Body.add(dm)
Expand Down
39 changes: 39 additions & 0 deletions message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,45 @@ func (s *MessageSuite) TestParseOutOfOrder() {
s.Nil(ParseMessage(s.msg, rawMsg))
}

func (s *MessageSuite) TestParseGroup_BodyFieldAfterNestedGroup() {
dict, dictErr := datadictionary.Parse("spec/FIX44.xml")
s.Nil(dictErr)

// Wire layout (FIX 4.4 MassQuoteAcknowledgement):
// 117=QID QuoteID (body)
// 296=1 NoQuoteSets count (body group)
// 302=SET1 QuoteSetID (inside NoQuoteSets)
// 295=1 NoQuoteEntries count (nested group)
// 299=E1 QuoteEntryID (inside NoQuoteEntries)
// 132=100 BidPx (inside NoQuoteEntries)
// 133=101 OfferPx (inside NoQuoteEntries)
// 297=0 QuoteStatus (BODY level, AFTER the group)
rawMsg := bytes.NewBufferString(
"8=FIX.4.49=6335=b117=QID" +
"296=1302=SET1" +
"295=1299=E1132=100133=101" +
"297=1" +
"10=002")

err := ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)
s.Nil(err)

rebuildBytes := s.msg.build()
expectedBytes := rawMsg.Bytes()
s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n +%s\n -%s", rebuildBytes, expectedBytes)

// NoQuoteSets count (group delimiter) lands in Body as expected.
s.True(s.msg.Body.Has(Tag(296)))

// QuoteStatus (297) must be a top-level body field per FIX 4.4.
s.True(s.msg.Body.Has(Tag(297)),
"QuoteStatus (297) must land at the body level; it is a body field "+
"in MassQuoteAcknowledgement, not a member of NoQuoteSets.")
val, verr := s.msg.Body.GetInt(Tag(297))
s.Nil(verr)
s.Equal(1, val)
}

func (s *MessageSuite) TestBuild() {
s.msg.Header.SetField(tagBeginString, FIXString(BeginStringFIX44))
s.msg.Header.SetField(tagMsgType, FIXString("A"))
Expand Down
Loading