Index: src/test/java/quickfix/MessageTest.java =================================================================== --- src/test/java/quickfix/MessageTest.java (revision 740) +++ src/test/java/quickfix/MessageTest.java (working copy) @@ -19,76 +19,22 @@ package quickfix; -import java.math.BigDecimal; -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; - import junit.framework.TestCase; -import quickfix.field.AllocAccount; -import quickfix.field.AllocShares; -import quickfix.field.AvgPx; -import quickfix.field.BeginString; -import quickfix.field.BidType; -import quickfix.field.BodyLength; -import quickfix.field.CheckSum; -import quickfix.field.ClOrdID; -import quickfix.field.CountryOfIssue; -import quickfix.field.CrossID; -import quickfix.field.CrossPrioritization; -import quickfix.field.CrossType; -import quickfix.field.CumQty; -import quickfix.field.EncodedText; -import quickfix.field.EncodedTextLen; -import quickfix.field.EncryptMethod; -import quickfix.field.ExecID; -import quickfix.field.ExecType; -import quickfix.field.HandlInst; -import quickfix.field.Headline; -import quickfix.field.IOIid; -import quickfix.field.LeavesQty; -import quickfix.field.ListID; -import quickfix.field.ListSeqNo; -import quickfix.field.MsgDirection; -import quickfix.field.MsgSeqNum; -import quickfix.field.MsgType; -import quickfix.field.NoOrders; -import quickfix.field.OrdStatus; -import quickfix.field.OrdType; -import quickfix.field.OrderID; -import quickfix.field.OrderQty; -import quickfix.field.PartyID; -import quickfix.field.PartyIDSource; -import quickfix.field.PartyRole; -import quickfix.field.Price; -import quickfix.field.RawData; -import quickfix.field.RawDataLength; -import quickfix.field.RefMsgType; -import quickfix.field.SecureData; -import quickfix.field.SecurityID; -import quickfix.field.SecurityIDSource; -import quickfix.field.SecurityType; -import quickfix.field.SenderCompID; -import quickfix.field.SendingTime; -import quickfix.field.Side; -import quickfix.field.Symbol; -import quickfix.field.TargetCompID; -import quickfix.field.TotNoOrders; -import quickfix.field.TransactTime; -import quickfix.field.UnderlyingCurrency; -import quickfix.field.UnderlyingSymbol; +import quickfix.field.*; import quickfix.fix42.NewOrderSingle; import quickfix.fix43.NewOrderList; -import quickfix.fix44.ExecutionReport; -import quickfix.fix44.IndicationOfInterest; -import quickfix.fix44.Logon; -import quickfix.fix44.NewOrderCross; -import quickfix.fix44.News; +import quickfix.fix44.*; import quickfix.fix44.Logon.NoMsgTypes; import quickfix.fix44.NewOrderSingle.NoPartyIDs; import quickfix.fix44.component.Instrument; import quickfix.fix44.component.Parties; +import quickfix.util.ExpectedTestFailure; +import java.math.BigDecimal; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + public class MessageTest extends TestCase { public void testEmbeddedMessage() throws Exception { @@ -183,6 +129,51 @@ } + public void testDuplicateFieldsPresent() throws Exception { + final String data = "8=FIX.4.2\u00019=193\u000135=8\u000149=OPENFIX\u000156=MRKTC\u000152=20070919-21:28:11\u000134=101"+ + "\u000137=1190237122441-1\u000111=11902371224411\u000120=0\u000155=ORCL\u000154=1\u000138=2000"+ + "\u000140=2\u000144=13\u000117=1190237122441-2\u000132=0\u000131=0\u000114=0\u00016=0\u0001151=2000"+ + "\u000139=0\u0001150=0\u000138=2100\u000110=168\u0001"; + final ExecutionReport executionReport = new ExecutionReport(); + final DataDictionary dictionary = DataDictionaryTest.getDictionary(); + assertNotNull(dictionary); + new ExpectedTestFailure(InvalidMessage.class, OrderQty.FIELD+"") { + protected void execute() throws Throwable { + executionReport.fromString(data, dictionary, true); + } + }.run(); + } + + public void testDuplicateTrailerFieldsPresent() throws Exception { + final String data = "8=FIX.4.2\u00019=193\u000135=8\u000149=OPENFIX\u000156=MRKTC\u000152=20070919-21:28:11\u000134=101"+ + "\u000137=1190237122441-1\u000111=11902371224411\u000120=0\u000155=ORCL\u000154=1\u000138=2000"+ + "\u000140=2\u000144=13\u000117=1190237122441-2\u000132=0\u000131=0\u000114=0\u00016=0\u0001151=2000"+ + "\u000139=0\u0001150=0\u000193=1\u000193=1\u000189=A\u000110=226\u0001"; + final ExecutionReport executionReport = new ExecutionReport(); + final DataDictionary dictionary = DataDictionaryTest.getDictionary(); + assertNotNull(dictionary); + new ExpectedTestFailure(InvalidMessage.class, SignatureLength.FIELD+"") { + protected void execute() throws Throwable { + executionReport.fromString(data, dictionary, true); + } + }.run(); + } + + public void testDuplicateHeaderFieldsPresent() throws Exception { + final String data = "8=FIX.4.2\u00019=193\u000135=8\u000149=OPENFIX\u000156=MRKTC\u000149=OPENFIX\u000152=20070919-21:28:11\u000134=101"+ + "\u000137=1190237122441-1\u000111=11902371224411\u000120=0\u000155=ORCL\u000154=1\u000138=2000"+ + "\u000140=2\u000144=13\u000117=1190237122441-2\u000132=0\u000131=0\u000114=0\u00016=0\u0001151=2000"+ + "\u000139=0\u0001150=0\u000110=0\u0001"; + final ExecutionReport executionReport = new ExecutionReport(); + final DataDictionary dictionary = DataDictionaryTest.getDictionary(); + assertNotNull(dictionary); + new ExpectedTestFailure(InvalidMessage.class, SenderCompID.FIELD+"") { + protected void execute() throws Throwable { + executionReport.fromString(data, dictionary, true); + } + }.run(); + } + public void testValidation() throws Exception { String data = "8=FIX.4.49=30935=849=ASX56=CL1_FIX4434=452=20060324-01:05:58" + "17=X-B-WOW-1494E9A0:58BD3F9D-1109150=D39=011=18427138=200198=1494E9A0:58BD3F9D" Index: src/main/java/quickfix/Message.java =================================================================== --- src/main/java/quickfix/Message.java (revision 740) +++ src/main/java/quickfix/Message.java (working copy) @@ -19,10 +19,10 @@ package quickfix; -import java.io.ByteArrayOutputStream; -import java.text.DecimalFormat; -import java.util.Iterator; -import java.util.List; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import quickfix.field.*; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; @@ -30,41 +30,11 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import java.io.ByteArrayOutputStream; +import java.text.DecimalFormat; +import java.util.Iterator; +import java.util.List; -import org.w3c.dom.CDATASection; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import quickfix.field.BeginString; -import quickfix.field.BodyLength; -import quickfix.field.CheckSum; -import quickfix.field.DeliverToCompID; -import quickfix.field.DeliverToLocationID; -import quickfix.field.DeliverToSubID; -import quickfix.field.LastMsgSeqNumProcessed; -import quickfix.field.MessageEncoding; -import quickfix.field.MsgSeqNum; -import quickfix.field.MsgType; -import quickfix.field.OnBehalfOfCompID; -import quickfix.field.OnBehalfOfLocationID; -import quickfix.field.OnBehalfOfSendingTime; -import quickfix.field.OnBehalfOfSubID; -import quickfix.field.OrigSendingTime; -import quickfix.field.PossDupFlag; -import quickfix.field.PossResend; -import quickfix.field.SecureDataLen; -import quickfix.field.SenderCompID; -import quickfix.field.SenderLocationID; -import quickfix.field.SenderSubID; -import quickfix.field.SendingTime; -import quickfix.field.Signature; -import quickfix.field.SignatureLength; -import quickfix.field.TargetCompID; -import quickfix.field.TargetLocationID; -import quickfix.field.TargetSubID; -import quickfix.field.XmlData; -import quickfix.field.XmlDataLen; - /** * Represents a FIX message. */ @@ -445,8 +415,6 @@ } } catch (FieldNotFound e) { throw new InvalidMessage("Field not found: " + e.field); - } catch (InvalidMessage e) { - throw e; } } @@ -481,7 +449,11 @@ StringField field = extractField(dd, header); while (field != null && isHeaderField(field, dd)) { - header.setField(field); + if(!header.isSetField(field)) { + header.setField(field); + } else { + throw new InvalidMessage("Duplicate header field found: "+field.getField()); + } field = extractField(dd, header); } pushBack(field); @@ -511,7 +483,11 @@ } header.setField(field); } else { - setField(field); + if(!isSetField(field)) { + setField(field); + } else { + throw new InvalidMessage("Duplicate field found: "+field.getField()); + } } // Group case if (dd != null && dd.isGroup(getMsgType(), field.getField())) { @@ -574,7 +550,11 @@ private void parseTrailer(DataDictionary dd) throws InvalidMessage { StringField field = extractField(dd, trailer); while (field != null && isTrailerField(field, dd)) { - trailer.setField(field); + if(!trailer.isSetField(field)) { + trailer.setField(field); + } else { + throw new InvalidMessage("Duplicate trailer field found: "+field.getField()); + } field = extractField(dd, trailer); } }