adding quickfix library

This commit is contained in:
Ramiro Paz
2026-03-12 12:08:34 -03:00
parent 9e55c5c562
commit c09a1fd21a
1311 changed files with 1887342 additions and 2 deletions

547
quickfix/message_test.go Normal file
View File

@ -0,0 +1,547 @@
// Copyright (c) quickfixengine.org All rights reserved.
//
// This file may be distributed under the terms of the quickfixengine.org
// license as defined by quickfixengine.org and appearing in the file
// LICENSE included in the packaging of this file.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE.
//
// See http://www.quickfixengine.org/LICENSE for licensing information.
//
// Contact ask@quickfixengine.org if any conditions of this licensing
// are not clear to you.
package quickfix
import (
"bytes"
"reflect"
"testing"
"github.com/stretchr/testify/suite"
"github.com/quickfixgo/quickfix/datadictionary"
)
func BenchmarkParseMessage(b *testing.B) {
rawMsg := bytes.NewBufferString("8=FIX.4.29=10435=D34=249=TW52=20140515-19:49:56.65956=ISLD11=10021=140=154=155=TSLA60=00010101-00:00:00.00010=039")
msg := NewMessage()
for i := 0; i < b.N; i++ {
_ = ParseMessage(msg, rawMsg)
}
}
type MessageSuite struct {
QuickFIXSuite
msg *Message
}
func TestMessageSuite(t *testing.T) {
suite.Run(t, new(MessageSuite))
}
func (s *MessageSuite) SetupTest() {
s.msg = NewMessage()
}
func TestXMLNonFIX(t *testing.T) {
rawMsg := bytes.NewBufferString("8=FIX.4.29=37235=n34=25512369=148152=20200522-07:05:33.75649=CME50=G56=OAEAAAN57=TRADE_CAPTURE143=US,IL212=261213=<RTRF>8=FIX.4.29=22535=BZ34=6549369=651852=20200522-07:05:33.74649=CME50=G56=9Q5000N57=DUMMY143=US,IL11=ACP159013113373460=20200522-07:05:33.734533=0893=Y1028=Y1300=991369=99612:325081373=31374=91375=15979=159013113373461769710=167</RTRF>10=245\"")
msg := NewMessage()
_ = ParseMessage(msg, rawMsg)
if !msg.Header.Has(tagXMLData) {
t.Error("Expected xmldata tag")
}
}
func (s *MessageSuite) TestParseMessageEmpty() {
rawMsg := bytes.NewBufferString("")
err := ParseMessage(s.msg, rawMsg)
s.NotNil(err)
}
func (s *MessageSuite) TestParseMessage() {
rawMsg := bytes.NewBufferString("8=FIX.4.29=10435=D34=249=TW52=20140515-19:49:56.65956=ISLD11=10021=140=154=155=TSLA60=00010101-00:00:00.00010=039")
err := ParseMessage(s.msg, rawMsg)
s.Nil(err)
s.True(bytes.Equal(rawMsg.Bytes(), s.msg.rawMessage.Bytes()), "Expected msg bytes to equal raw bytes")
expectedBodyBytes := []byte("11=10021=140=154=155=TSLA60=00010101-00:00:00.000")
s.True(bytes.Equal(s.msg.bodyBytes, expectedBodyBytes), "Incorrect body bytes, got %s", string(s.msg.bodyBytes))
s.Equal(14, len(s.msg.fields))
msgType, err := s.msg.MsgType()
s.Nil(err)
s.Equal("D", msgType)
s.True(s.msg.IsMsgTypeOf("D"))
s.False(s.msg.IsMsgTypeOf("A"))
}
func (s *MessageSuite) TestParseMessageWithDataDictionary() {
dict := new(datadictionary.DataDictionary)
dict.Header = &datadictionary.MessageDef{
Fields: map[int]*datadictionary.FieldDef{
10030: nil,
},
}
dict.Trailer = &datadictionary.MessageDef{
Fields: map[int]*datadictionary.FieldDef{
5050: nil,
},
}
rawMsg := bytes.NewBufferString("8=FIX.4.29=12635=D34=249=TW52=20140515-19:49:56.65956=ISLD10030=CUST11=10021=140=154=155=TSLA60=00010101-00:00:00.0005050=HELLO10=039")
err := ParseMessageWithDataDictionary(s.msg, rawMsg, dict, dict)
s.Nil(err)
s.FieldEquals(Tag(10030), "CUST", s.msg.Header)
s.FieldEquals(Tag(5050), "HELLO", s.msg.Trailer)
}
func (s *MessageSuite) TestParseOutOfOrder() {
// Allow fields out of order, save for validation.
rawMsg := bytes.NewBufferString("8=FIX.4.09=8135=D11=id21=338=10040=154=155=MSFT34=249=TW52=20140521-22:07:0956=ISLD10=250")
s.Nil(ParseMessage(s.msg, rawMsg))
}
func (s *MessageSuite) TestBuild() {
s.msg.Header.SetField(tagBeginString, FIXString(BeginStringFIX44))
s.msg.Header.SetField(tagMsgType, FIXString("A"))
s.msg.Header.SetField(tagSendingTime, FIXString("20140615-19:49:56"))
s.msg.Body.SetField(Tag(553), FIXString("my_user"))
s.msg.Body.SetField(Tag(554), FIXString("secret"))
expectedBytes := []byte("8=FIX.4.49=4935=A52=20140615-19:49:56553=my_user554=secret10=072")
result := s.msg.build()
s.True(bytes.Equal(expectedBytes, result), "Unexpected bytes, got %s", string(result))
}
func (s *MessageSuite) TestReBuild() {
rawMsg := bytes.NewBufferString("8=FIX.4.29=10435=D34=249=TW52=20140515-19:49:56.65956=ISLD11=10021=140=154=155=TSLA60=00010101-00:00:00.00010=039")
s.Nil(ParseMessage(s.msg, rawMsg))
s.msg.Header.SetField(tagOrigSendingTime, FIXString("20140515-19:49:56.659"))
s.msg.Header.SetField(tagSendingTime, FIXString("20140615-19:49:56"))
s.msg.Header.SetField(tagPossDupFlag, FIXBoolean(true))
rebuildBytes := s.msg.build()
expectedBytes := []byte("8=FIX.4.29=13135=D34=243=Y49=TW52=20140615-19:49:5656=ISLD122=20140515-19:49:56.65911=10021=140=154=155=TSLA60=00010101-00:00:00.00010=122")
s.True(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n +%s\n -%s", rebuildBytes, expectedBytes)
expectedBodyBytes := []byte("11=10021=140=154=155=TSLA60=00010101-00:00:00.000")
s.True(bytes.Equal(s.msg.bodyBytes, expectedBodyBytes), "Incorrect body bytes, got %s", string(s.msg.bodyBytes))
}
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 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
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=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)
}
func (s *MessageSuite) TestRebuildOneRepeatingGroupWithTwoMembersWithDictionary() {
dict, dictErr := datadictionary.Parse("spec/FIX44.xml")
s.Nil(dictErr)
// 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")
// 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() {
// Given the following message with a repeating group
origHeader := "8=FIXT.1.19=16135=834=349=ISLD52=20240415-03:43:17.92356=TW"
origBody := "6=1.0011=114=1.0017=131=1.0032=1.0037=138=1.0039=254=155=1150=2151=0.00453=1448=xyzzy447=D452=1"
origTrailer := "10=014"
rawMsg := bytes.NewBufferString(origHeader + origBody + origTrailer)
// When I reparse the message from the store during a resend request
s.Nil(ParseMessage(s.msg, rawMsg))
// And I update the headers for resend
s.msg.Header.SetField(tagOrigSendingTime, FIXString("20240415-03:43:17.923"))
s.msg.Header.SetField(tagSendingTime, FIXString("20240415-14:41:23.456"))
s.msg.Header.SetField(tagPossDupFlag, FIXBoolean(true))
// When I rebuild the message
rebuildBytes := s.msg.build()
// Then the repeating groups will not be in the correct order in the rebuilt message (note tags 447, 448, 452, 453)
expectedBytes := []byte("8=FIXT.1.19=19235=834=343=Y49=ISLD52=20240415-14:41:23.45656=TW122=20240415-03:43:17.9236=1.0011=114=1.0017=131=1.0032=1.0037=138=1.0039=254=155=1150=2151=0.00453=1448=xyzzy447=D452=110=018")
s.False(bytes.Equal(expectedBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but was: %s", expectedBytes, rebuildBytes)
expectedOutOfOrderBytes := []byte("8=FIXT.1.19=19235=834=343=Y49=ISLD52=20240415-14:41:23.45656=TW122=20240415-03:43:17.9236=1.0011=114=1.0017=131=1.0032=1.0037=138=1.0039=254=155=1150=2151=0.00447=D448=xyzzy452=1453=110=018")
s.True(bytes.Equal(expectedOutOfOrderBytes, rebuildBytes), "Unexpected bytes,\n expected: %s\n but was: %s", expectedOutOfOrderBytes, rebuildBytes)
// But the bodyBytes will still be correct
origBodyBytes := []byte(origBody)
s.True(bytes.Equal(origBodyBytes, s.msg.bodyBytes), "Incorrect body bytes, \n expected: %s\n but was: %s", origBodyBytes, s.msg.bodyBytes)
// So when I combine the updated header + the original bodyBytes + the as-is trailer
resendBytes := s.msg.buildWithBodyBytes(s.msg.bodyBytes)
// Then the reparsed, rebuilt message will retain the correct ordering of repeating group tags during resend
s.True(bytes.Equal(expectedBytes, resendBytes), "Unexpected bytes,\n expected: %s\n but was: %s", expectedBytes, resendBytes)
}
func (s *MessageSuite) TestReBuildWithRepeatingGroupMultipleEntriesInGroupForResend() {
// Given the following message with a repeating group that has 2 entries
origHeader := "8=FIXT.1.19=18435=834=349=ISLD52=20240415-03:43:17.92356=TW"
origBody := "6=1.0011=114=1.0017=131=1.0032=1.0037=138=1.0039=254=155=1150=2151=0.00453=2448=xyzzy447=D452=1448=foobar447=D452=3"
origTrailer := "10=152"
rawMsg := bytes.NewBufferString(origHeader + origBody + origTrailer)
// When I reparse the message from the store during a resend request
s.Nil(ParseMessage(s.msg, rawMsg))
// And I update the headers for resend
s.msg.Header.SetField(tagOrigSendingTime, FIXString("20240415-03:43:17.923"))
s.msg.Header.SetField(tagSendingTime, FIXString("20240415-14:41:23.456"))
s.msg.Header.SetField(tagPossDupFlag, FIXBoolean(true))
// The bodyBytes will still be correct
origBodyBytes := []byte(origBody)
s.True(bytes.Equal(origBodyBytes, s.msg.bodyBytes), "Incorrect body bytes, \n expected: %s\n but was: %s", origBodyBytes, s.msg.bodyBytes)
// So when I combine the updated header + the original bodyBytes + the as-is trailer
resendBytes := s.msg.buildWithBodyBytes(origBodyBytes)
// Then the reparsed, rebuilt message will retain the correct ordering of repeating group tags during resend
expectedResendHeader := "8=FIXT.1.19=21535=834=343=Y49=ISLD52=20240415-14:41:23.45656=TW122=20240415-03:43:17.923"
expectedResendBody := "6=1.0011=114=1.0017=131=1.0032=1.0037=138=1.0039=254=155=1150=2151=0.00453=2448=xyzzy447=D452=1448=foobar447=D452=3"
expectedResendTrailer := "10=147"
expectedResendBytes := []byte(expectedResendHeader + expectedResendBody + expectedResendTrailer)
s.True(bytes.Equal(expectedResendBytes, resendBytes), "Unexpected bytes,\n expected: %s\n but was: %s", expectedResendBytes, resendBytes)
}
func (s *MessageSuite) TestReverseRoute() {
s.Nil(ParseMessage(s.msg, bytes.NewBufferString("8=FIX.4.29=17135=D34=249=TW50=KK52=20060102-15:04:0556=ISLD57=AP144=BB115=JCD116=CS128=MG129=CB142=JV143=RY145=BH11=ID21=338=10040=w54=155=INTC60=20060102-15:04:0510=123")))
builder := s.msg.reverseRoute()
var testCases = []struct {
tag Tag
expectedValue string
}{
{tagTargetCompID, "TW"},
{tagTargetSubID, "KK"},
{tagTargetLocationID, "JV"},
{tagSenderCompID, "ISLD"},
{tagSenderSubID, "AP"},
{tagSenderLocationID, "RY"},
{tagDeliverToCompID, "JCD"},
{tagDeliverToSubID, "CS"},
{tagDeliverToLocationID, "BB"},
{tagOnBehalfOfCompID, "MG"},
{tagOnBehalfOfSubID, "CB"},
{tagOnBehalfOfLocationID, "BH"},
}
for _, tc := range testCases {
var field FIXString
s.Nil(builder.Header.GetField(tc.tag, &field))
s.Equal(tc.expectedValue, string(field))
}
}
func (s *MessageSuite) TestReverseRouteIgnoreEmpty() {
s.Nil(ParseMessage(s.msg, bytes.NewBufferString("8=FIX.4.09=12835=D34=249=TW52=20060102-15:04:0556=ISLD115=116=CS128=MG129=CB11=ID21=338=10040=w54=155=INTC60=20060102-15:04:0510=123")))
builder := s.msg.reverseRoute()
s.False(builder.Header.Has(tagDeliverToCompID), "Should not reverse if empty")
}
func (s *MessageSuite) TestReverseRouteFIX40() {
// The onbehalfof/deliverto location id not supported in fix 4.0.
s.Nil(ParseMessage(s.msg, bytes.NewBufferString("8=FIX.4.09=17135=D34=249=TW50=KK52=20060102-15:04:0556=ISLD57=AP144=BB115=JCD116=CS128=MG129=CB142=JV143=RY145=BH11=ID21=338=10040=w54=155=INTC60=20060102-15:04:0510=123")))
builder := s.msg.reverseRoute()
s.False(builder.Header.Has(tagDeliverToLocationID), "delivertolocation id not supported in fix40")
s.False(builder.Header.Has(tagOnBehalfOfLocationID), "onbehalfof location id not supported in fix40")
}
func (s *MessageSuite) TestCopyIntoMessage() {
msgString := "8=FIX.4.29=17135=D34=249=TW50=KK52=20060102-15:04:0556=ISLD57=AP144=BB115=JCD116=CS128=MG129=CB142=JV143=RY145=BH11=ID21=338=10040=w54=155=INTC60=20060102-15:04:0510=123"
msgBuf := bytes.NewBufferString(msgString)
s.Nil(ParseMessage(s.msg, msgBuf))
dest := NewMessage()
s.msg.CopyInto(dest)
checkFieldInt(s, dest.Header.FieldMap, int(tagMsgSeqNum), 2)
checkFieldInt(s, dest.Body.FieldMap, 21, 3)
checkFieldString(s, dest.Body.FieldMap, 11, "ID")
s.Equal(len(dest.bodyBytes), len(s.msg.bodyBytes))
// copying decouples the message from its input buffer, so the raw message will be re-rendered
renderedString := "8=FIX.4.29=17135=D34=249=TW50=KK52=20060102-15:04:0556=ISLD57=AP115=JCD116=CS128=MG129=CB142=JV143=RY144=BB145=BH11=ID21=338=10040=w54=155=INTC60=20060102-15:04:0510=033"
s.Equal(dest.String(), renderedString)
s.True(reflect.DeepEqual(s.msg.bodyBytes, dest.bodyBytes))
s.True(s.msg.IsMsgTypeOf("D"))
s.Equal(s.msg.ReceiveTime, dest.ReceiveTime)
s.True(reflect.DeepEqual(s.msg.fields, dest.fields))
// update the source message to validate the copy is truly deep
newMsgString := "8=FIX.4.49=4935=A52=20140615-19:49:56553=my_user554=secret10=072"
s.Nil(ParseMessage(s.msg, bytes.NewBufferString(newMsgString)))
s.True(s.msg.IsMsgTypeOf("A"))
s.Equal(s.msg.String(), newMsgString)
s.Equal(string(s.msg.Bytes()), newMsgString)
// clear the source buffer also
msgBuf.Reset()
s.True(dest.IsMsgTypeOf("D"))
s.Equal(dest.String(), renderedString)
s.Equal(string(dest.Bytes()), renderedString)
}
func checkFieldInt(s *MessageSuite, fields FieldMap, tag, expected int) {
toCheck, _ := fields.GetInt(Tag(tag))
s.Equal(expected, toCheck)
}
func checkFieldString(s *MessageSuite, fields FieldMap, tag int, expected string) {
toCheck, err := fields.GetString(Tag(tag))
s.NoError(err)
s.Equal(expected, toCheck)
}