// 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" "quantex.com/qfixpt/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=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=16710=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) }