From d5914471817c475393c8abc07cc0a0e97b4b0678 Mon Sep 17 00:00:00 2001 From: Michael Ackley Date: Wed, 1 May 2024 12:40:12 -0500 Subject: [PATCH 1/3] Failing unit test for message with repeating group --- message_test.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/message_test.go b/message_test.go index fa60b3fd1..392690f92 100644 --- a/message_test.go +++ b/message_test.go @@ -146,6 +146,29 @@ func (s *MessageSuite) TestReBuild() { s.True(bytes.Equal(s.msg.bodyBytes, expectedBodyBytes), "Incorrect body bytes, got %s", string(s.msg.bodyBytes)) } +func (s *MessageSuite) TestRebuildWithRepeatingGroup() { + + dict, dictErr := datadictionary.Parse("spec/FIX44.xml") + s.Nil(dictErr) + + // Given message bytes from a valid string + rawMsg := bytes.NewBufferString("8=FIX.4.49=21035=D34=2347=UTF-852=20231231-20:19:4149=0100150=01001a56=TEST44=1211=139761=1010040021=1386=1336=NOPL55=SYMABC54=160=20231231-20:19:4138=140=259=0453=1448=4501447=D452=28354=6355=Public10=104") + + // When we parse it into a message + s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) + + // And then rebuild the message bytes + rebuildBytes := s.msg.build() + + // this method does result in test passing. + //s.msg.buildWithBodyBytes(s.msg.bodyBytes) + + expectedBytes := []byte("8=FIX.4.49=21035=D34=249=0100150=01001a52=20231231-20:19:4156=TEST347=UTF-844=1211=139761=1010040021=1386=1336=NOPL55=SYMABC54=160=20231231-20:19:4138=140=259=0453=1448=4501447=D452=28354=6355=Public10=104") + + // Then the bytes should be the same with repeating group properly ordered + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n +%s\n -%s", rebuildBytes, expectedBytes) +} + func (s *MessageSuite) TestReBuildWithRepeatingGroupForResend() { // Given the following message with a repeating group origHeader := "8=FIXT.1.19=16135=834=349=ISLD52=20240415-03:43:17.92356=TW" From 6889cf10c445cd62f6de53165d2ec27ebc01d167 Mon Sep 17 00:00:00 2001 From: Michael Ackley Date: Thu, 16 May 2024 13:46:42 -0500 Subject: [PATCH 2/3] Adds proper parsing for repeating groups to keep group field order --- in_session.go | 6 +- message.go | 283 ++++++++++++++++++++++++++++++++++++++---------- message_test.go | 228 ++++++++++++++++++++++++++++++++++++-- session.go | 1 + 4 files changed, 452 insertions(+), 66 deletions(-) diff --git a/in_session.go b/in_session.go index f157f3ea2..6f189bf49 100644 --- a/in_session.go +++ b/in_session.go @@ -232,7 +232,11 @@ func (state inSession) resendMessages(session *session, beginSeqNo, endSeqNo int nextSeqNum := seqNum msg := NewMessage() for _, msgBytes := range msgs { - _ = ParseMessageWithDataDictionary(msg, bytes.NewBuffer(msgBytes), session.transportDataDictionary, session.appDataDictionary) + err = ParseMessageWithDataDictionary(msg, bytes.NewBuffer(msgBytes), session.transportDataDictionary, session.appDataDictionary) + if err != nil { + session.log.OnEventf("Resend Msg Parse Error: %v, %v", err.Error(), bytes.NewBuffer(msgBytes).String()) + return // We cant continue with a message that cant be parsed correctly. + } msgType, _ := msg.Header.GetBytes(tagMsgType) sentMessageSeqNum, _ := msg.Header.GetInt(tagMsgSeqNum) diff --git a/message.go b/message.go index 73da79169..26a6b90c1 100644 --- a/message.go +++ b/message.go @@ -27,6 +27,19 @@ import ( // Header is first section of a FIX Message. type Header struct{ FieldMap } +// msgparser contains message parsing vars needed to parse a string into a message. +type msgParser struct { + msg *Message + transportDataDictionary *datadictionary.DataDictionary + appDataDictionary *datadictionary.DataDictionary + rawBytes []byte + fieldIndex int + parsedFieldBytes *TagValue + trailerBytes []byte + foundBody bool + foundTrailer bool +} + // in the message header, the first 3 tags in the message header must be 8,9,35. func headerFieldOrdering(i, j Tag) bool { var ordering = func(t Tag) uint32 { @@ -152,116 +165,127 @@ func ParseMessageWithDataDictionary( msg *Message, rawMessage *bytes.Buffer, transportDataDictionary *datadictionary.DataDictionary, - _ *datadictionary.DataDictionary, + appDataDictionary *datadictionary.DataDictionary, ) (err error) { - msg.Header.Clear() - msg.Body.Clear() - msg.Trailer.Clear() - msg.rawMessage = rawMessage + // Create msgparser before we go any further. + mp := &msgParser{ + msg: msg, + transportDataDictionary: transportDataDictionary, + appDataDictionary: appDataDictionary, + } + mp.msg.rawMessage = rawMessage + mp.rawBytes = rawMessage.Bytes() - rawBytes := rawMessage.Bytes() + return doParsing(mp) +} + +// doParsing executes the message parsing process. +func doParsing(mp *msgParser) (err error) { + // Initialize for parsing. + mp.msg.Header.Clear() + mp.msg.Body.Clear() + mp.msg.Trailer.Clear() - // Allocate fields in one chunk. + // Allocate expected message fields in one chunk. fieldCount := 0 - for _, b := range rawBytes { + for _, b := range mp.rawBytes { if b == '\001' { fieldCount++ } } - if fieldCount == 0 { - return parseError{OrigError: fmt.Sprintf("No Fields detected in %s", string(rawBytes))} + return parseError{OrigError: fmt.Sprintf("No Fields detected in %s", string(mp.rawBytes))} } - - if cap(msg.fields) < fieldCount { - msg.fields = make([]TagValue, fieldCount) + if cap(mp.msg.fields) < fieldCount { + mp.msg.fields = make([]TagValue, fieldCount) } else { - msg.fields = msg.fields[0:fieldCount] + mp.msg.fields = mp.msg.fields[0:fieldCount] } - fieldIndex := 0 - // Message must start with begin string, body length, msg type. - if rawBytes, err = extractSpecificField(&msg.fields[fieldIndex], tagBeginString, rawBytes); err != nil { + // Get begin string. + if mp.rawBytes, err = extractSpecificField(&mp.msg.fields[mp.fieldIndex], tagBeginString, mp.rawBytes); err != nil { return } + mp.msg.Header.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) - msg.Header.add(msg.fields[fieldIndex : fieldIndex+1]) - fieldIndex++ - - parsedFieldBytes := &msg.fields[fieldIndex] - if rawBytes, err = extractSpecificField(parsedFieldBytes, tagBodyLength, rawBytes); err != nil { + // Get body length. + mp.fieldIndex++ + mp.parsedFieldBytes = &mp.msg.fields[mp.fieldIndex] + if mp.rawBytes, err = extractSpecificField(mp.parsedFieldBytes, tagBodyLength, mp.rawBytes); err != nil { return } + mp.msg.Header.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) - msg.Header.add(msg.fields[fieldIndex : fieldIndex+1]) - fieldIndex++ - - parsedFieldBytes = &msg.fields[fieldIndex] - if rawBytes, err = extractSpecificField(parsedFieldBytes, tagMsgType, rawBytes); err != nil { + // Get msg type. + mp.fieldIndex++ + mp.parsedFieldBytes = &mp.msg.fields[mp.fieldIndex] + if mp.rawBytes, err = extractSpecificField(mp.parsedFieldBytes, tagMsgType, mp.rawBytes); err != nil { return } + mp.msg.Header.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) + + // Start parsing. + mp.fieldIndex++ xmlDataLen := 0 xmlDataMsg := false - - msg.Header.add(msg.fields[fieldIndex : fieldIndex+1]) - fieldIndex++ - - trailerBytes := []byte{} - foundBody := false - foundTrailer := false + mp.trailerBytes = []byte{} + mp.foundBody = false + mp.foundTrailer = false for { - parsedFieldBytes = &msg.fields[fieldIndex] + mp.parsedFieldBytes = &mp.msg.fields[mp.fieldIndex] if xmlDataLen > 0 { - rawBytes, err = extractXMLDataField(parsedFieldBytes, rawBytes, xmlDataLen) + mp.rawBytes, err = extractXMLDataField(mp.parsedFieldBytes, mp.rawBytes, xmlDataLen) xmlDataLen = 0 xmlDataMsg = true } else { - rawBytes, err = extractField(parsedFieldBytes, rawBytes) + mp.rawBytes, err = extractField(mp.parsedFieldBytes, mp.rawBytes) } if err != nil { return } switch { - case isHeaderField(parsedFieldBytes.tag, transportDataDictionary): - msg.Header.add(msg.fields[fieldIndex : fieldIndex+1]) - case isTrailerField(parsedFieldBytes.tag, transportDataDictionary): - msg.Trailer.add(msg.fields[fieldIndex : fieldIndex+1]) - foundTrailer = true + case isHeaderField(mp.parsedFieldBytes.tag, mp.transportDataDictionary): + mp.msg.Header.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) + case isTrailerField(mp.parsedFieldBytes.tag, mp.transportDataDictionary): + mp.msg.Trailer.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) + mp.foundTrailer = true + case isNumInGroupField(mp.msg, []Tag{mp.parsedFieldBytes.tag}, mp.appDataDictionary): + parseGroup(mp, []Tag{mp.parsedFieldBytes.tag}) default: - foundBody = true - trailerBytes = rawBytes - msg.Body.add(msg.fields[fieldIndex : fieldIndex+1]) + mp.foundBody = true + mp.trailerBytes = mp.rawBytes + mp.msg.Body.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) } - if parsedFieldBytes.tag == tagCheckSum { + if mp.parsedFieldBytes.tag == tagCheckSum { break } - if !foundBody { - msg.bodyBytes = rawBytes + if !mp.foundBody { + mp.msg.bodyBytes = mp.rawBytes } - if parsedFieldBytes.tag == tagXMLDataLen { - xmlDataLen, _ = msg.Header.GetInt(tagXMLDataLen) + if mp.parsedFieldBytes.tag == tagXMLDataLen { + xmlDataLen, _ = mp.msg.Header.GetInt(tagXMLDataLen) } - fieldIndex++ + mp.fieldIndex++ } // This will happen if there are no fields in the body - if foundTrailer && !foundBody { - trailerBytes = rawBytes - msg.bodyBytes = nil + if mp.foundTrailer && !mp.foundBody { + mp.trailerBytes = mp.rawBytes + mp.msg.bodyBytes = nil } // Body length would only be larger than trailer if fields out of order. - if len(msg.bodyBytes) > len(trailerBytes) { - msg.bodyBytes = msg.bodyBytes[:len(msg.bodyBytes)-len(trailerBytes)] + if len(mp.msg.bodyBytes) > len(mp.trailerBytes) { + mp.msg.bodyBytes = mp.msg.bodyBytes[:len(mp.msg.bodyBytes)-len(mp.trailerBytes)] } length := 0 - for _, field := range msg.fields { + for _, field := range mp.msg.fields { switch field.tag { case tagBeginString, tagBodyLength, tagCheckSum: // Tags do not contribute to length. default: @@ -269,7 +293,7 @@ func ParseMessageWithDataDictionary( } } - bodyLength, err := msg.Header.GetInt(tagBodyLength) + bodyLength, err := mp.msg.Header.GetInt(tagBodyLength) if err != nil { err = parseError{OrigError: err.Error()} } else if length != bodyLength && !xmlDataMsg { @@ -279,6 +303,149 @@ func ParseMessageWithDataDictionary( return } +// parseGroup iterates through a repeating group to maintain correct order of those fields. +func parseGroup(mp *msgParser, tags []Tag) { + mp.foundBody = true + dm := mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1] + fields := getGroupFields(mp.msg, tags, mp.appDataDictionary) + + for { + mp.fieldIndex++ + mp.parsedFieldBytes = &mp.msg.fields[mp.fieldIndex] + mp.rawBytes, _ = extractField(mp.parsedFieldBytes, mp.rawBytes) + mp.trailerBytes = mp.rawBytes + + // Is this field a member for the group. + if isGroupMember(mp.parsedFieldBytes.tag, fields) { + // Is this field a nested repeating group. + if isNumInGroupField(mp.msg, append(tags, mp.parsedFieldBytes.tag), mp.appDataDictionary) { + dm = append(dm, *mp.parsedFieldBytes) + tags = append(tags, mp.parsedFieldBytes.tag) + fields = getGroupFields(mp.msg, tags, mp.appDataDictionary) + continue + } + // Add the field member to the group. + dm = append(dm, *mp.parsedFieldBytes) + } else if isHeaderField(mp.parsedFieldBytes.tag, mp.transportDataDictionary) { + // Found a header tag for some reason.. + mp.msg.Body.add(dm) + mp.msg.Header.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) + break + } else if isTrailerField(mp.parsedFieldBytes.tag, mp.transportDataDictionary) { + // Found the trailer at the end of the message. + mp.msg.Body.add(dm) + mp.msg.Trailer.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) + mp.foundTrailer = true + break + } else { + // Found a body field outside the group. + searchTags := []Tag{mp.parsedFieldBytes.tag} + // Is this a new group not inside the existing group. + if isNumInGroupField(mp.msg, searchTags, mp.appDataDictionary) { + // Add the current repeating group. + mp.msg.Body.add(dm) + // Cycle again with the new group. + dm = mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1] + fields = getGroupFields(mp.msg, searchTags, mp.appDataDictionary) + continue + } else { + 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 + } + // Add the repeating group. + mp.msg.Body.add(dm) + // Add the next body field. + mp.msg.Body.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) + } + break + } + } +} + +// isNumInGroupField evaluates if this tag is the start of a repeating group. +// tags slice will contain multiple tags if the tag in question is found while processing a group already. +func isNumInGroupField(msg *Message, tags []Tag, appDataDictionary *datadictionary.DataDictionary) bool { + if appDataDictionary != nil { + msgt, err := msg.MsgType() + if err != nil { + return false + } + mm, ok := appDataDictionary.Messages[msgt] + if ok { + fields := mm.Fields + for idx, tag := range tags { + fd, ok := fields[int(tag)] + if ok { + if idx == len(tags) - 1 { + if len(fd.Fields) > 0 { + return true + } + } else { + // Map nested fields. + newFields := make(map[int]*datadictionary.FieldDef) + for _, ff := range fd.Fields { + newFields[ff.Tag()] = ff + } + fields = newFields + } + } + } + } + } + return false +} + +// getGroupFields gets the relevant fields for parsing a repeating group if this tag is the start of a repeating group. +// tags slice will contain multiple tags if the tag in question is found while processing a group already. +func getGroupFields(msg *Message, tags []Tag, appDataDictionary *datadictionary.DataDictionary) (fields []*datadictionary.FieldDef) { + if appDataDictionary != nil { + msgt, err := msg.MsgType() + if err != nil { + return + } + mm, ok := appDataDictionary.Messages[msgt] + if ok { + fields := mm.Fields + for idx, tag := range tags { + fd, ok := fields[int(tag)] + if ok { + if idx == len(tags) - 1 { + if len(fd.Fields) > 0 { + return fd.Fields + } + } else { + // Map nested fields. + newFields := make(map[int]*datadictionary.FieldDef) + for _, ff := range fd.Fields { + newFields[ff.Tag()] = ff + } + fields = newFields + } + } + } + } + } + return +} + +// isGroupMember evaluates if this tag belongs to a repeating group. +func isGroupMember(tag Tag, fields []*datadictionary.FieldDef) bool { + for _, f := range fields{ + if f.Tag() == int(tag) { + return true + } + } + return false +} + func isHeaderField(tag Tag, dataDict *datadictionary.DataDictionary) bool { if tag.IsHeader() { return true diff --git a/message_test.go b/message_test.go index 392690f92..13d3e3eac 100644 --- a/message_test.go +++ b/message_test.go @@ -146,12 +146,35 @@ func (s *MessageSuite) TestReBuild() { s.True(bytes.Equal(s.msg.bodyBytes, expectedBodyBytes), "Incorrect body bytes, got %s", string(s.msg.bodyBytes)) } -func (s *MessageSuite) TestRebuildWithRepeatingGroup() { +func (s *MessageSuite) TestRebuildOneRepeatingGroupWithDictionary() { + dict, dictErr := datadictionary.Parse("spec/FIX44.xml") + s.Nil(dictErr) + + // Given message bytes from a valid string with a 453 repeating group. + rawMsg := bytes.NewBufferString( + "8=FIX.4.49=16535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=1448=4501447=D452=28"+ + "10=026") + + // When we parse it into a message + s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) + // And then rebuild the message bytes + rebuildBytes := s.msg.build() + expectedBytes := []byte( + "8=FIX.4.49=16535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=1448=4501447=D452=28"+ + "10=026") + + // Then the bytes should have repeating groups properly ordered + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) +} + +func (s *MessageSuite) TestRebuildTwoRepeatingGroupsWithDictionary() { dict, dictErr := datadictionary.Parse("spec/FIX44.xml") s.Nil(dictErr) - // Given message bytes from a valid string + // Given message bytes from a valid string with a 386 repeating group and a 453 repeating group. rawMsg := bytes.NewBufferString("8=FIX.4.49=21035=D34=2347=UTF-852=20231231-20:19:4149=0100150=01001a56=TEST44=1211=139761=1010040021=1386=1336=NOPL55=SYMABC54=160=20231231-20:19:4138=140=259=0453=1448=4501447=D452=28354=6355=Public10=104") // When we parse it into a message @@ -159,14 +182,205 @@ func (s *MessageSuite) TestRebuildWithRepeatingGroup() { // And then rebuild the message bytes rebuildBytes := s.msg.build() + expectedBytes := []byte("8=FIX.4.49=21035=D34=249=0100150=01001a52=20231231-20:19:4156=TEST347=UTF-81=1010040011=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41354=6355=Public386=1336=NOPL453=1448=4501447=D452=2810=104") + + // Then the bytes should have repeating groups properly ordered + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) +} - // this method does result in test passing. - //s.msg.buildWithBodyBytes(s.msg.bodyBytes) +func (s *MessageSuite) TestRebuildOneRepeatingGroupWithTwoMembersWithDictionary() { + dict, dictErr := datadictionary.Parse("spec/FIX44.xml") + s.Nil(dictErr) - expectedBytes := []byte("8=FIX.4.49=21035=D34=249=0100150=01001a52=20231231-20:19:4156=TEST347=UTF-844=1211=139761=1010040021=1386=1336=NOPL55=SYMABC54=160=20231231-20:19:4138=140=259=0453=1448=4501447=D452=28354=6355=Public10=104") + // Given message bytes from a valid string with a 453 repeating group that has 2 child groups. + rawMsg := bytes.NewBufferString( + "8=FIX.4.49=18735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=2448=4501447=D452=28448=4502447=D452=28"+ + "10=044") - // Then the bytes should be the same with repeating group properly ordered - s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n +%s\n -%s", rebuildBytes, expectedBytes) + // When we parse it into a message + s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) + + // And then rebuild the message bytes + rebuildBytes := s.msg.build() + expectedBytes := []byte( + "8=FIX.4.49=18735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=2448=4501447=D452=28448=4502447=D452=28"+ + "10=044") + + // Then the bytes should have repeating groups properly ordered + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) +} + +func (s *MessageSuite) TestRebuildTwoSequentialRepeatingGroupWithDictionary() { + dict, dictErr := datadictionary.Parse("spec/FIX44.xml") + s.Nil(dictErr) + + // Given message bytes from a valid string with both a 78 and 453 repeating group that each have 2 child groups. + rawMsg := bytes.NewBufferString( + "8=FIX.4.49=21035=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=279=acct179=acct2453=2448=4501447=D452=28448=4502447=D452=28"+ + "10=243") + + // When we parse it into a message + s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) + + // And then rebuild the message bytes + rebuildBytes := s.msg.build() + expectedBytes := []byte( + "8=FIX.4.49=21035=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=279=acct179=acct2453=2448=4501447=D452=28448=4502447=D452=28"+ + "10=243") + + // Then the bytes should have repeating groups properly ordered + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) +} + +func (s *MessageSuite) TestRebuildNestedRepeatingGroupWithDictionary() { + dict, dictErr := datadictionary.Parse("spec/FIX44.xml") + s.Nil(dictErr) + + // Given message bytes from a valid string with a 78 repeating group that has + // a nested 539 group and then another 80 tag in the 78 group + rawMsg := bytes.NewBufferString( + "8=FIX.4.49=17735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid80=100"+ + "10=206") + + // When we parse it into a message + s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) + + // And then rebuild the message bytes + rebuildBytes := s.msg.build() + expectedBytes := []byte( + "8=FIX.4.49=17735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid80=100"+ + "10=206") + + // Then the bytes should have repeating groups properly ordered + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) +} + +func (s *MessageSuite) TestRebuildDoubleNestedRepeatingGroupWithDictionary() { + dict, dictErr := datadictionary.Parse("spec/FIX44.xml") + s.Nil(dictErr) + + // Given message bytes from a valid string with a 78 repeating group that has a + // double nested 539 and then 804 groups and then another 80 tag in the 78 group + rawMsg := bytes.NewBufferString( + "8=FIX.4.49=20235=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid80=100"+ + "10=117") + + // When we parse it into a message + s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) + + // And then rebuild the message bytes + rebuildBytes := s.msg.build() + expectedBytes := []byte( + "8=FIX.4.49=20235=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid80=100"+ + "10=117") + + // Then the bytes should have repeating groups properly ordered + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) +} + +func (s *MessageSuite) TestRebuildDoubleNestedThenAnotherRepeatingGroupWithDictionary() { + dict, dictErr := datadictionary.Parse("spec/FIX44.xml") + s.Nil(dictErr) + + // Given message bytes from a valid string with a 78 repeating group that has a double nested 539 and then 804 groups + // and then another repeating group 453 with two children. + rawMsg := bytes.NewBufferString( + "8=FIX.4.49=24535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid453=2448=4501447=D452=28448=4502447=D452=28"+ + "10=106") + + // When we parse it into a message + s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) + + // And then rebuild the message bytes + rebuildBytes := s.msg.build() + expectedBytes := []byte( + "8=FIX.4.49=24535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid453=2448=4501447=D452=28448=4502447=D452=28"+ + "10=106") + + // Then the bytes should have repeating groups properly ordered + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) +} + +func (s *MessageSuite) TestRebuildDoubleNestedThenBodyTagThenAnotherRepeatingGroupWithDictionary() { + dict, dictErr := datadictionary.Parse("spec/FIX44.xml") + s.Nil(dictErr) + + // Given message bytes from a valid string with a 78 repeating group that has a double nested 539 and then 804 groups + // then a 376 body tag and then another repeating group 453 with two children. + rawMsg := bytes.NewBufferString( + "8=FIX.4.49=25635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid376=compid453=2448=4501447=D452=28448=4502447=D452=28"+ + "10=198") + + // When we parse it into a message + s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) + + // And then rebuild the message bytes + rebuildBytes := s.msg.build() + expectedBytes := []byte( + "8=FIX.4.49=25635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid376=compid453=2448=4501447=D452=28448=4502447=D452=28"+ + "10=198") + + // Then the bytes should have repeating groups properly ordered + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) +} + +func (s *MessageSuite) TestRebuildDoubleNestedWithTwoMembersRepeatingGroupWithDictionary() { + dict, dictErr := datadictionary.Parse("spec/FIX44.xml") + s.Nil(dictErr) + + // Given message bytes from a valid string with a 78 repeating group that + // has a double nested 539 and then 804 groups all with two children. + rawMsg := bytes.NewBufferString( + "8=FIX.4.49=40635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41"+ + "78=179=acct1"+ + "539=2"+ + "524=nestedid"+ + "804=2"+ + "545=doublenestedid"+ + "545=doublenestedid2"+ + "524=nestedid2"+ + "804=2"+ + "545=doublenestedid"+ + "545=doublenestedid2"+ + "79=acct2"+ + "539=2"+ + "524=nestedid"+ + "804=2"+ + "545=doublenestedid"+ + "545=doublenestedid2"+ + "524=nestedid2"+ + "804=2"+ + "545=doublenestedid"+ + "545=doublenestedid2"+ + "10=046") + + // When we parse it into a message + s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) + + // And then rebuild the message bytes + rebuildBytes := s.msg.build() + expectedBytes := []byte( + "8=FIX.4.49=40635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41"+ + "78=179=acct1539=2524=nestedid804=2545=doublenestedid545=doublenestedid2524=nestedid2804=2545=doublenestedid545=doublenestedid2"+ + "79=acct2539=2524=nestedid804=2545=doublenestedid545=doublenestedid2524=nestedid2804=2545=doublenestedid545=doublenestedid2"+ + "10=046") + + // Then the bytes should have repeating groups properly ordered + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) } func (s *MessageSuite) TestReBuildWithRepeatingGroupForResend() { diff --git a/session.go b/session.go index 5ab8c5edc..29d0b89e9 100644 --- a/session.go +++ b/session.go @@ -335,6 +335,7 @@ func (s *session) prepMessageForSend(msg *Message, inReplyTo *Message) (msgBytes } } + // Message converted to bytes here. msgBytes = msg.build() err = s.persist(seqNum, msgBytes) From 3517c8b55165a224e4ad7cd06d64d2ef689715c1 Mon Sep 17 00:00:00 2001 From: Michael Ackley Date: Thu, 16 May 2024 14:57:43 -0500 Subject: [PATCH 3/3] Linter fixes --- Makefile | 4 ++ message.go | 63 ++++++++-------- message_test.go | 186 ++++++++++++++++++++++++------------------------ 3 files changed, 128 insertions(+), 125 deletions(-) diff --git a/Makefile b/Makefile index b68843f3c..75a60a66e 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,10 @@ linters-install: lint: linters-install golangci-lint run +# An easy way to run the linter without going through the install process - +# docker run -t --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.57.2 golangci-lint run -v +# See https://golangci-lint.run/welcome/install/ for more details. + # --------------------------------------------------------------- # Targets related to running acceptance tests - diff --git a/message.go b/message.go index 26a6b90c1..11afd7669 100644 --- a/message.go +++ b/message.go @@ -29,15 +29,15 @@ type Header struct{ FieldMap } // msgparser contains message parsing vars needed to parse a string into a message. type msgParser struct { - msg *Message + msg *Message transportDataDictionary *datadictionary.DataDictionary - appDataDictionary *datadictionary.DataDictionary - rawBytes []byte - fieldIndex int - parsedFieldBytes *TagValue - trailerBytes []byte - foundBody bool - foundTrailer bool + appDataDictionary *datadictionary.DataDictionary + rawBytes []byte + fieldIndex int + parsedFieldBytes *TagValue + trailerBytes []byte + foundBody bool + foundTrailer bool } // in the message header, the first 3 tags in the message header must be 8,9,35. @@ -169,9 +169,9 @@ func ParseMessageWithDataDictionary( ) (err error) { // Create msgparser before we go any further. mp := &msgParser{ - msg: msg, + msg: msg, transportDataDictionary: transportDataDictionary, - appDataDictionary: appDataDictionary, + appDataDictionary: appDataDictionary, } mp.msg.rawMessage = rawMessage mp.rawBytes = rawMessage.Bytes() @@ -225,7 +225,6 @@ func doParsing(mp *msgParser) (err error) { } mp.msg.Header.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) - // Start parsing. mp.fieldIndex++ xmlDataLen := 0 @@ -308,7 +307,7 @@ func parseGroup(mp *msgParser, tags []Tag) { mp.foundBody = true dm := mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1] fields := getGroupFields(mp.msg, tags, mp.appDataDictionary) - + for { mp.fieldIndex++ mp.parsedFieldBytes = &mp.msg.fields[mp.fieldIndex] @@ -327,7 +326,7 @@ func parseGroup(mp *msgParser, tags []Tag) { // Add the field member to the group. dm = append(dm, *mp.parsedFieldBytes) } else if isHeaderField(mp.parsedFieldBytes.tag, mp.transportDataDictionary) { - // Found a header tag for some reason.. + // Found a header tag for some reason.. mp.msg.Body.add(dm) mp.msg.Header.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) break @@ -348,23 +347,23 @@ func parseGroup(mp *msgParser, tags []Tag) { dm = mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1] fields = getGroupFields(mp.msg, searchTags, mp.appDataDictionary) continue - } else { - 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 - } - // Add the repeating group. - mp.msg.Body.add(dm) - // Add the next body field. - mp.msg.Body.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) } + 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 + } + // Add the repeating group. + mp.msg.Body.add(dm) + // Add the next body field. + mp.msg.Body.add(mp.msg.fields[mp.fieldIndex : mp.fieldIndex+1]) + break } } @@ -384,7 +383,7 @@ func isNumInGroupField(msg *Message, tags []Tag, appDataDictionary *datadictiona for idx, tag := range tags { fd, ok := fields[int(tag)] if ok { - if idx == len(tags) - 1 { + if idx == len(tags)-1 { if len(fd.Fields) > 0 { return true } @@ -417,7 +416,7 @@ func getGroupFields(msg *Message, tags []Tag, appDataDictionary *datadictionary. for idx, tag := range tags { fd, ok := fields[int(tag)] if ok { - if idx == len(tags) - 1 { + if idx == len(tags)-1 { if len(fd.Fields) > 0 { return fd.Fields } @@ -438,7 +437,7 @@ func getGroupFields(msg *Message, tags []Tag, appDataDictionary *datadictionary. // isGroupMember evaluates if this tag belongs to a repeating group. func isGroupMember(tag Tag, fields []*datadictionary.FieldDef) bool { - for _, f := range fields{ + for _, f := range fields { if f.Tag() == int(tag) { return true } diff --git a/message_test.go b/message_test.go index 13d3e3eac..b02508cd9 100644 --- a/message_test.go +++ b/message_test.go @@ -152,9 +152,9 @@ func (s *MessageSuite) TestRebuildOneRepeatingGroupWithDictionary() { // Given message bytes from a valid string with a 453 repeating group. rawMsg := bytes.NewBufferString( - "8=FIX.4.49=16535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=1448=4501447=D452=28"+ - "10=026") + "8=FIX.4.49=16535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=1448=4501447=D452=28" + + "10=026") // When we parse it into a message s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) @@ -162,12 +162,12 @@ func (s *MessageSuite) TestRebuildOneRepeatingGroupWithDictionary() { // And then rebuild the message bytes rebuildBytes := s.msg.build() expectedBytes := []byte( - "8=FIX.4.49=16535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=1448=4501447=D452=28"+ - "10=026") - + "8=FIX.4.49=16535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=1448=4501447=D452=28" + + "10=026") + // Then the bytes should have repeating groups properly ordered - s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes) } func (s *MessageSuite) TestRebuildTwoRepeatingGroupsWithDictionary() { @@ -183,9 +183,9 @@ func (s *MessageSuite) TestRebuildTwoRepeatingGroupsWithDictionary() { // And then rebuild the message bytes rebuildBytes := s.msg.build() expectedBytes := []byte("8=FIX.4.49=21035=D34=249=0100150=01001a52=20231231-20:19:4156=TEST347=UTF-81=1010040011=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41354=6355=Public386=1336=NOPL453=1448=4501447=D452=2810=104") - + // Then the bytes should have repeating groups properly ordered - s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes) } func (s *MessageSuite) TestRebuildOneRepeatingGroupWithTwoMembersWithDictionary() { @@ -194,9 +194,9 @@ func (s *MessageSuite) TestRebuildOneRepeatingGroupWithTwoMembersWithDictionary( // Given message bytes from a valid string with a 453 repeating group that has 2 child groups. rawMsg := bytes.NewBufferString( - "8=FIX.4.49=18735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=2448=4501447=D452=28448=4502447=D452=28"+ - "10=044") + "8=FIX.4.49=18735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=2448=4501447=D452=28448=4502447=D452=28" + + "10=044") // When we parse it into a message s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) @@ -204,12 +204,12 @@ func (s *MessageSuite) TestRebuildOneRepeatingGroupWithTwoMembersWithDictionary( // And then rebuild the message bytes rebuildBytes := s.msg.build() expectedBytes := []byte( - "8=FIX.4.49=18735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=2448=4501447=D452=28448=4502447=D452=28"+ - "10=044") - + "8=FIX.4.49=18735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41453=2448=4501447=D452=28448=4502447=D452=28" + + "10=044") + // Then the bytes should have repeating groups properly ordered - s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes) } func (s *MessageSuite) TestRebuildTwoSequentialRepeatingGroupWithDictionary() { @@ -218,9 +218,9 @@ func (s *MessageSuite) TestRebuildTwoSequentialRepeatingGroupWithDictionary() { // Given message bytes from a valid string with both a 78 and 453 repeating group that each have 2 child groups. rawMsg := bytes.NewBufferString( - "8=FIX.4.49=21035=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=279=acct179=acct2453=2448=4501447=D452=28448=4502447=D452=28"+ - "10=243") + "8=FIX.4.49=21035=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=279=acct179=acct2453=2448=4501447=D452=28448=4502447=D452=28" + + "10=243") // When we parse it into a message s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) @@ -228,24 +228,24 @@ func (s *MessageSuite) TestRebuildTwoSequentialRepeatingGroupWithDictionary() { // And then rebuild the message bytes rebuildBytes := s.msg.build() expectedBytes := []byte( - "8=FIX.4.49=21035=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=279=acct179=acct2453=2448=4501447=D452=28448=4502447=D452=28"+ - "10=243") - + "8=FIX.4.49=21035=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=279=acct179=acct2453=2448=4501447=D452=28448=4502447=D452=28" + + "10=243") + // Then the bytes should have repeating groups properly ordered - s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes) } func (s *MessageSuite) TestRebuildNestedRepeatingGroupWithDictionary() { dict, dictErr := datadictionary.Parse("spec/FIX44.xml") s.Nil(dictErr) - // Given message bytes from a valid string with a 78 repeating group that has + // Given message bytes from a valid string with a 78 repeating group that has // a nested 539 group and then another 80 tag in the 78 group rawMsg := bytes.NewBufferString( - "8=FIX.4.49=17735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid80=100"+ - "10=206") + "8=FIX.4.49=17735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid80=100" + + "10=206") // When we parse it into a message s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) @@ -253,24 +253,24 @@ func (s *MessageSuite) TestRebuildNestedRepeatingGroupWithDictionary() { // And then rebuild the message bytes rebuildBytes := s.msg.build() expectedBytes := []byte( - "8=FIX.4.49=17735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid80=100"+ - "10=206") - + "8=FIX.4.49=17735=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid80=100" + + "10=206") + // Then the bytes should have repeating groups properly ordered - s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes) } func (s *MessageSuite) TestRebuildDoubleNestedRepeatingGroupWithDictionary() { dict, dictErr := datadictionary.Parse("spec/FIX44.xml") s.Nil(dictErr) - // Given message bytes from a valid string with a 78 repeating group that has a + // Given message bytes from a valid string with a 78 repeating group that has a // double nested 539 and then 804 groups and then another 80 tag in the 78 group rawMsg := bytes.NewBufferString( - "8=FIX.4.49=20235=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid80=100"+ - "10=117") + "8=FIX.4.49=20235=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid80=100" + + "10=117") // When we parse it into a message s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) @@ -278,24 +278,24 @@ func (s *MessageSuite) TestRebuildDoubleNestedRepeatingGroupWithDictionary() { // And then rebuild the message bytes rebuildBytes := s.msg.build() expectedBytes := []byte( - "8=FIX.4.49=20235=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid80=100"+ - "10=117") - + "8=FIX.4.49=20235=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid80=100" + + "10=117") + // Then the bytes should have repeating groups properly ordered - s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes) } func (s *MessageSuite) TestRebuildDoubleNestedThenAnotherRepeatingGroupWithDictionary() { dict, dictErr := datadictionary.Parse("spec/FIX44.xml") s.Nil(dictErr) - // Given message bytes from a valid string with a 78 repeating group that has a double nested 539 and then 804 groups + // Given message bytes from a valid string with a 78 repeating group that has a double nested 539 and then 804 groups // and then another repeating group 453 with two children. rawMsg := bytes.NewBufferString( - "8=FIX.4.49=24535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid453=2448=4501447=D452=28448=4502447=D452=28"+ - "10=106") + "8=FIX.4.49=24535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid453=2448=4501447=D452=28448=4502447=D452=28" + + "10=106") // When we parse it into a message s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) @@ -303,24 +303,24 @@ func (s *MessageSuite) TestRebuildDoubleNestedThenAnotherRepeatingGroupWithDicti // And then rebuild the message bytes rebuildBytes := s.msg.build() expectedBytes := []byte( - "8=FIX.4.49=24535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid453=2448=4501447=D452=28448=4502447=D452=28"+ - "10=106") - + "8=FIX.4.49=24535=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid453=2448=4501447=D452=28448=4502447=D452=28" + + "10=106") + // Then the bytes should have repeating groups properly ordered - s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes) } func (s *MessageSuite) TestRebuildDoubleNestedThenBodyTagThenAnotherRepeatingGroupWithDictionary() { dict, dictErr := datadictionary.Parse("spec/FIX44.xml") s.Nil(dictErr) - // Given message bytes from a valid string with a 78 repeating group that has a double nested 539 and then 804 groups + // Given message bytes from a valid string with a 78 repeating group that has a double nested 539 and then 804 groups // then a 376 body tag and then another repeating group 453 with two children. rawMsg := bytes.NewBufferString( - "8=FIX.4.49=25635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid376=compid453=2448=4501447=D452=28448=4502447=D452=28"+ - "10=198") + "8=FIX.4.49=25635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid376=compid453=2448=4501447=D452=28448=4502447=D452=28" + + "10=198") // When we parse it into a message s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) @@ -328,44 +328,44 @@ func (s *MessageSuite) TestRebuildDoubleNestedThenBodyTagThenAnotherRepeatingGro // And then rebuild the message bytes rebuildBytes := s.msg.build() expectedBytes := []byte( - "8=FIX.4.49=25635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid376=compid453=2448=4501447=D452=28448=4502447=D452=28"+ - "10=198") - + "8=FIX.4.49=25635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:4178=179=acct1539=1524=nestedid804=1545=doublenestedid376=compid453=2448=4501447=D452=28448=4502447=D452=28" + + "10=198") + // Then the bytes should have repeating groups properly ordered - s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes) } func (s *MessageSuite) TestRebuildDoubleNestedWithTwoMembersRepeatingGroupWithDictionary() { dict, dictErr := datadictionary.Parse("spec/FIX44.xml") s.Nil(dictErr) - // Given message bytes from a valid string with a 78 repeating group that + // Given message bytes from a valid string with a 78 repeating group that // has a double nested 539 and then 804 groups all with two children. rawMsg := bytes.NewBufferString( - "8=FIX.4.49=40635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41"+ - "78=179=acct1"+ - "539=2"+ - "524=nestedid"+ - "804=2"+ - "545=doublenestedid"+ - "545=doublenestedid2"+ - "524=nestedid2"+ - "804=2"+ - "545=doublenestedid"+ - "545=doublenestedid2"+ - "79=acct2"+ - "539=2"+ - "524=nestedid"+ - "804=2"+ - "545=doublenestedid"+ - "545=doublenestedid2"+ - "524=nestedid2"+ - "804=2"+ - "545=doublenestedid"+ - "545=doublenestedid2"+ - "10=046") + "8=FIX.4.49=40635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41" + + "78=179=acct1" + + "539=2" + + "524=nestedid" + + "804=2" + + "545=doublenestedid" + + "545=doublenestedid2" + + "524=nestedid2" + + "804=2" + + "545=doublenestedid" + + "545=doublenestedid2" + + "79=acct2" + + "539=2" + + "524=nestedid" + + "804=2" + + "545=doublenestedid" + + "545=doublenestedid2" + + "524=nestedid2" + + "804=2" + + "545=doublenestedid" + + "545=doublenestedid2" + + "10=046") // When we parse it into a message s.Nil(ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)) @@ -373,14 +373,14 @@ func (s *MessageSuite) TestRebuildDoubleNestedWithTwoMembersRepeatingGroupWithDi // And then rebuild the message bytes rebuildBytes := s.msg.build() expectedBytes := []byte( - "8=FIX.4.49=40635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST"+ - "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41"+ - "78=179=acct1539=2524=nestedid804=2545=doublenestedid545=doublenestedid2524=nestedid2804=2545=doublenestedid545=doublenestedid2"+ - "79=acct2539=2524=nestedid804=2545=doublenestedid545=doublenestedid2524=nestedid2804=2545=doublenestedid545=doublenestedid2"+ - "10=046") - + "8=FIX.4.49=40635=D34=249=0100150=01001a52=20231231-20:19:4156=TEST" + + "1=acct111=1397621=138=140=244=1254=155=SYMABC59=060=20231231-20:19:41" + + "78=179=acct1539=2524=nestedid804=2545=doublenestedid545=doublenestedid2524=nestedid2804=2545=doublenestedid545=doublenestedid2" + + "79=acct2539=2524=nestedid804=2545=doublenestedid545=doublenestedid2524=nestedid2804=2545=doublenestedid545=doublenestedid2" + + "10=046") + // Then the bytes should have repeating groups properly ordered - s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes,) + s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but got: %s", expectedBytes, rebuildBytes) } func (s *MessageSuite) TestReBuildWithRepeatingGroupForResend() {