From 2f73d439d3c3afb3bc867809be4c90c6be31606c Mon Sep 17 00:00:00 2001 From: Jon Freedman Date: Thu, 30 Nov 2017 11:45:25 +0000 Subject: [PATCH 1/8] pass SessionID to MemoryStore on construction --- quickfixj-core/src/main/java/quickfix/MemoryStoreFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/MemoryStoreFactory.java b/quickfixj-core/src/main/java/quickfix/MemoryStoreFactory.java index 8903651661..09b670b738 100644 --- a/quickfixj-core/src/main/java/quickfix/MemoryStoreFactory.java +++ b/quickfixj-core/src/main/java/quickfix/MemoryStoreFactory.java @@ -30,7 +30,7 @@ public class MemoryStoreFactory implements MessageStoreFactory { public MessageStore create(SessionID sessionID) { try { - return new MemoryStore(); + return new MemoryStore(sessionID); } catch (IOException e) { throw new RuntimeError(e); } From ee3101effa58356dc524b592c4bf8c03b7e3e3c5 Mon Sep 17 00:00:00 2001 From: Jon Freedman Date: Thu, 30 Nov 2017 12:00:42 +0000 Subject: [PATCH 2/8] Update MemoryStore.java --- quickfixj-core/src/main/java/quickfix/MemoryStore.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/MemoryStore.java b/quickfixj-core/src/main/java/quickfix/MemoryStore.java index fb3d1e49c3..7102a519fc 100644 --- a/quickfixj-core/src/main/java/quickfix/MemoryStore.java +++ b/quickfixj-core/src/main/java/quickfix/MemoryStore.java @@ -43,8 +43,9 @@ public MemoryStore() throws IOException { reset(); } - public MemoryStore(SessionID sessionID) { + public MemoryStore(SessionID sessionID) throws IOException { this.sessionID = sessionID; + reset(); } public void get(int startSequence, int endSequence, Collection messages) throws IOException { From 67f5dbe450a24a49bba5b2dbb74d0b1c10bfa9b5 Mon Sep 17 00:00:00 2001 From: Jon Freedman Date: Fri, 1 Dec 2017 11:59:06 +0000 Subject: [PATCH 3/8] fix for NPE on session lookup which causes test failures --- quickfixj-core/src/main/java/quickfix/MemoryStore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/MemoryStore.java b/quickfixj-core/src/main/java/quickfix/MemoryStore.java index 7102a519fc..f102056516 100644 --- a/quickfixj-core/src/main/java/quickfix/MemoryStore.java +++ b/quickfixj-core/src/main/java/quickfix/MemoryStore.java @@ -112,8 +112,8 @@ public void setNextTargetMsgSeqNum(int next) throws IOException { public void refresh() throws IOException { // IOException is declared to maintain strict compatibility with QF JNI final String text = "memory store does not support refresh!"; - if (sessionID != null) { - Session session = Session.lookupSession(sessionID); + final Session session = sessionID != null ? Session.lookupSession(sessionID) : null; + if (session != null) { session.getLog().onErrorEvent("ERROR: " + text); } else { LoggerFactory.getLogger(MemoryStore.class).error(text); From 5f45a39079d43a5a0df79ccb069f01eebc5b0aa8 Mon Sep 17 00:00:00 2001 From: jfreedman Date: Wed, 31 Jan 2018 14:08:08 +0000 Subject: [PATCH 4/8] remove any duplicates in nested groupings when generating MessageFactory#create factory method some vendors use the same repeating groups in different parts of a message conditional on the value of other fields e.g. different product types --- .../resources/org/quickfixj/codegenerator/MessageFactory.xsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl index 50a541e2db..6bc1043729 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl @@ -75,7 +75,7 @@ public class MessageFactory implements quickfix.MessageFactory { switch (msgType) { - + case ..MSGTYPE: switch (correspondingFieldID) { @@ -86,7 +86,7 @@ public class MessageFactory implements quickfix.MessageFactory { } break; - + } From 4ea7e2a6a2ce7db7d95ff8fae9d24c50b8a445c8 Mon Sep 17 00:00:00 2001 From: jfreedman Date: Thu, 1 Feb 2018 07:54:35 +0000 Subject: [PATCH 5/8] do not throw IncorrectDataFormat exception if value is empty and ValidateFieldsHaveValues=N --- .../main/java/quickfix/DataDictionary.java | 8 +-- .../java/quickfix/DataDictionaryTest.java | 55 +++++++++---------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/DataDictionary.java b/quickfixj-core/src/main/java/quickfix/DataDictionary.java index d41d9ffbf0..3a0f0b406e 100644 --- a/quickfixj-core/src/main/java/quickfix/DataDictionary.java +++ b/quickfixj-core/src/main/java/quickfix/DataDictionary.java @@ -48,10 +48,7 @@ import java.util.Map; import java.util.Set; -import static quickfix.FileUtil.Location.CLASSLOADER_RESOURCE; -import static quickfix.FileUtil.Location.CONTEXT_RESOURCE; -import static quickfix.FileUtil.Location.FILESYSTEM; -import static quickfix.FileUtil.Location.URL; +import static quickfix.FileUtil.Location.*; /** * Provide the message metadata for various versions of FIX. @@ -697,6 +694,9 @@ private void checkValidFormat(StringField field) throws IncorrectDataFormat { if (fieldType == null) { return; } + if (field.getValue().length() == 0 && !checkFieldsHaveValues) { + return; + } try { switch (fieldType) { case STRING: diff --git a/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java b/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java index 520361d94d..661908bc60 100644 --- a/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java +++ b/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java @@ -22,31 +22,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import quickfix.field.Account; -import quickfix.field.AvgPx; -import quickfix.field.BodyLength; -import quickfix.field.CheckSum; -import quickfix.field.ClOrdID; -import quickfix.field.HandlInst; -import quickfix.field.LastMkt; -import quickfix.field.MsgSeqNum; -import quickfix.field.MsgType; -import quickfix.field.NoHops; -import quickfix.field.NoPartyIDs; -import quickfix.field.NoRelatedSym; -import quickfix.field.OrdType; -import quickfix.field.OrderQty; -import quickfix.field.Price; -import quickfix.field.QuoteReqID; -import quickfix.field.SenderCompID; -import quickfix.field.SenderSubID; -import quickfix.field.SendingTime; -import quickfix.field.SessionRejectReason; -import quickfix.field.Side; -import quickfix.field.Symbol; -import quickfix.field.TargetCompID; -import quickfix.field.TimeInForce; -import quickfix.field.TransactTime; +import quickfix.field.*; import quickfix.fix44.NewOrderSingle; import quickfix.test.util.ExpectedTestFailure; @@ -57,10 +33,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.hasProperty; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; public class DataDictionaryTest { @@ -781,6 +754,30 @@ public void testGroupWithReqdComponentWithReqdFieldValidation() throws Exception dictionary.validate(quoteRequest, true); } + /** + * Field EffectiveTime(168) is defined as UTCTIMESTAMP so an empty string value is invalid but if we allow blank values that should not fail + * validation + * @throws Exception + */ + @Test + public void testAllowingBlankValuesDisablesFieldValidation() throws Exception { + final DataDictionary dictionary = getDictionary(); + dictionary.setCheckFieldsHaveValues(false); + + final quickfix.fix44.NewOrderSingle newSingle = new quickfix.fix44.NewOrderSingle( + new ClOrdID("123"), new Side(Side.BUY), new TransactTime(), new OrdType(OrdType.LIMIT) + ); + newSingle.setField(new OrderQty(42)); + newSingle.setField(new Price(42.37)); + newSingle.setField(new HandlInst()); + newSingle.setField(new Symbol("QFJ")); + newSingle.setField(new HandlInst(HandlInst.MANUAL_ORDER)); + newSingle.setField(new TimeInForce(TimeInForce.DAY)); + newSingle.setField(new Account("testAccount")); + newSingle.setField(new StringField(EffectiveTime.FIELD)); + dictionary.validate(newSingle, true); + } + // // Group Validation Tests in RepeatingGroupTest // From 2a22e79d8cff7db91d98807861dec5ce33f7baea Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Mon, 30 Jul 2018 17:57:01 +0100 Subject: [PATCH 6/8] revert --- .../resources/org/quickfixj/codegenerator/MessageFactory.xsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl index 6bc1043729..50a541e2db 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl @@ -75,7 +75,7 @@ public class MessageFactory implements quickfix.MessageFactory { switch (msgType) { - + case ..MSGTYPE: switch (correspondingFieldID) { @@ -86,7 +86,7 @@ public class MessageFactory implements quickfix.MessageFactory { } break; - + } From 9f39d38531c00eee419d3ab4769202690b33f89b Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Mon, 30 Jul 2018 17:57:25 +0100 Subject: [PATCH 7/8] fix test --- quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java b/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java index 7aa9b9bfe7..7313d279b9 100644 --- a/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java +++ b/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java @@ -1265,7 +1265,7 @@ public void testAllowingBlankValuesDisablesFieldValidation() throws Exception { newSingle.setField(new Price(42.37)); newSingle.setField(new HandlInst()); newSingle.setField(new Symbol("QFJ")); - newSingle.setField(new HandlInst(HandlInst.MANUAL_ORDER)); + newSingle.setField(new HandlInst(HandlInst.MANUAL_ORDER_BEST_EXECUTION)); newSingle.setField(new TimeInForce(TimeInForce.DAY)); newSingle.setField(new Account("testAccount")); newSingle.setField(new StringField(EffectiveTime.FIELD)); From 4f22be07b703ec51d529db159b74a2a071cb88c2 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Mon, 30 Jul 2018 17:57:54 +0100 Subject: [PATCH 8/8] new tests to verify the output of the codegenerator can be compiled --- quickfixj-core/pom.xml | 13 ++ .../org/quickfixj/codegenerator/Compiler.java | 92 ++++++++++ .../MessageCodeGeneratorTest.java | 173 ++++++++++++++++++ quickfixj-core/src/test/resources/basic.xml | 120 ++++++++++++ .../src/test/resources/nested-group.xml | 131 +++++++++++++ 5 files changed, 529 insertions(+) create mode 100644 quickfixj-core/src/test/java/org/quickfixj/codegenerator/Compiler.java create mode 100644 quickfixj-core/src/test/java/org/quickfixj/codegenerator/MessageCodeGeneratorTest.java create mode 100644 quickfixj-core/src/test/resources/basic.xml create mode 100644 quickfixj-core/src/test/resources/nested-group.xml diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index 854485eb7e..f2f7177ac2 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -56,6 +56,19 @@ test + + org.quickfixj + quickfixj-codegenerator + ${project.version} + test + + + org.jooq + joor-java-8 + 0.9.9 + test + + org.apache.mina mina-core diff --git a/quickfixj-core/src/test/java/org/quickfixj/codegenerator/Compiler.java b/quickfixj-core/src/test/java/org/quickfixj/codegenerator/Compiler.java new file mode 100644 index 0000000000..7b73013f7b --- /dev/null +++ b/quickfixj-core/src/test/java/org/quickfixj/codegenerator/Compiler.java @@ -0,0 +1,92 @@ +package org.quickfixj.codegenerator; + +import org.joor.Reflect; + +import javax.tools.*; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.StringWriter; +import java.lang.invoke.MethodHandles; +import java.net.URI; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +class Compiler { + private Compiler() { + } + + static Map compile(final Map classNameToSourceMap) { + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + + final ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(null, null, null)); + + final List files = new ArrayList<>(); + for (final Map.Entry entry : classNameToSourceMap.entrySet()) { + files.add(new CharSequenceJavaFileObject(entry.getKey(), entry.getValue())); + } + + final StringWriter out = new StringWriter(); + compiler.getTask(out, fileManager, null, null, null, files).call(); + + if (!fileManager.output.keySet().containsAll(classNameToSourceMap.keySet())) { + throw new RuntimeException("Compilation error:\n" + out.toString()); + } + + final ClassLoader cl = lookup.lookupClass().getClassLoader(); + final Map instances = new LinkedHashMap<>(); + for (final Map.Entry output : fileManager.output.entrySet()) { + final String className = output.getKey(); + final byte[] b = output.getValue().getBytes(); + final Class clazz = Reflect.on(cl).call("defineClass", className, b, 0, b.length).get(); + instances.put(className, Reflect.on(clazz)); + } + return instances; + } + + private static final class ClassFileManager extends ForwardingJavaFileManager { + private final Map output = new LinkedHashMap<>(); + + ClassFileManager(final StandardJavaFileManager standardManager) { + super(standardManager); + } + + @Override + public JavaFileObject getJavaFileForOutput(final JavaFileManager.Location location, final String className, final JavaFileObject.Kind kind, final FileObject sibling) { + return output.computeIfAbsent(className, (cn) -> new JavaFileObject(cn, kind)); + } + } + + private static final class JavaFileObject extends SimpleJavaFileObject { + private final ByteArrayOutputStream os = new ByteArrayOutputStream(); + + JavaFileObject(final String name, final JavaFileObject.Kind kind) { + super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind); + } + + byte[] getBytes() { + return os.toByteArray(); + } + + @Override + public OutputStream openOutputStream() { + return os; + } + } + + private static final class CharSequenceJavaFileObject extends SimpleJavaFileObject { + private final CharSequence content; + + CharSequenceJavaFileObject(final String className, final CharSequence content) { + super(URI.create("string:///" + className.replace('.', '/') + JavaFileObject.Kind.SOURCE.extension), JavaFileObject.Kind.SOURCE); + this.content = content; + } + + @Override + public CharSequence getCharContent(final boolean ignoreEncodingErrors) { + return content; + } + } +} diff --git a/quickfixj-core/src/test/java/org/quickfixj/codegenerator/MessageCodeGeneratorTest.java b/quickfixj-core/src/test/java/org/quickfixj/codegenerator/MessageCodeGeneratorTest.java new file mode 100644 index 0000000000..b26c27b433 --- /dev/null +++ b/quickfixj-core/src/test/java/org/quickfixj/codegenerator/MessageCodeGeneratorTest.java @@ -0,0 +1,173 @@ +package org.quickfixj.codegenerator; + +import org.joor.Reflect; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import quickfix.*; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.LinkedHashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class MessageCodeGeneratorTest { + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @Test + public void generateFromBasicFixDictionary() throws Exception { + final File schema = new File(MessageCodeGeneratorTest.class.getResource("/org/quickfixj/codegenerator/MessageFactory.xsl").getFile()); + final File spec = new File(MessageCodeGeneratorTest.class.getResource("/basic.xml").getFile()); + + final MessageCodeGenerator.Task task = new MessageCodeGenerator.Task(); + task.setName("basic"); + task.setSpecification(spec); + task.setTransformDirectory(schema.getParentFile()); + task.setMessagePackage("basic"); + task.setOutputBaseDirectory(folder.getRoot()); + task.setFieldPackage("field"); + task.setOverwrite(true); + task.setOrderedFields(true); + task.setDecimalGenerated(false); + final MessageCodeGenerator generator = new MessageCodeGenerator(); + generator.generate(task); + + final File fieldDir = new File(folder.getRoot(), "field"); + final File messageDir = new File(folder.getRoot(), "basic"); + + final Map classNameToSourceMap = new LinkedHashMap<>(); + classNameToSourceMap.put("field.BeginString", getSource(new File(fieldDir, "BeginString.java"))); + classNameToSourceMap.put("field.BodyLength", getSource(new File(fieldDir, "BodyLength.java"))); + classNameToSourceMap.put("field.CheckSum", getSource(new File(fieldDir, "CheckSum.java"))); + classNameToSourceMap.put("field.MsgType", getSource(new File(fieldDir, "MsgType.java"))); + classNameToSourceMap.put("field.Signature", getSource(new File(fieldDir, "Signature.java"))); + classNameToSourceMap.put("field.SignatureLength", getSource(new File(fieldDir, "SignatureLength.java"))); + classNameToSourceMap.put("field.TestReqID", getSource(new File(fieldDir, "TestReqID.java"))); + + classNameToSourceMap.put("basic.Message", getSource(new File(messageDir, "Message.java"))); + classNameToSourceMap.put("basic.TestRequest", getSource(new File(messageDir, "TestRequest.java"))); + classNameToSourceMap.put("basic.MessageCracker", getSource(new File(messageDir, "MessageCracker.java"))); + classNameToSourceMap.put("basic.MessageFactory", getSource(new File(messageDir, "MessageFactory.java"))); + final Map classes = Compiler.compile(classNameToSourceMap); + + final Map fieldDefs = new LinkedHashMap<>(); + fieldDefs.put("BeginString", new FieldDef(8, StringField.class)); + fieldDefs.put("BodyLength", new FieldDef(9, IntField.class)); + fieldDefs.put("CheckSum", new FieldDef(10, StringField.class)); + fieldDefs.put("MsgType", new FieldDef(35, StringField.class)); + fieldDefs.put("Signature", new FieldDef(89, StringField.class)); + fieldDefs.put("SignatureLength", new FieldDef(93, IntField.class)); + fieldDefs.put("TestReqID", new FieldDef(112, StringField.class)); + validateFields(classes, fieldDefs); + + final Map messageDefs = new LinkedHashMap<>(); + messageDefs.put("TestRequest", new MessageDef("1")); + validateMessages(classes, messageDefs); + } + + /** + * This test is based on the FXAll FIX spec post MiFID II which has the same group in different locations within a + * message based on the context of the message. At present this generates Java code which does not compile due to + * duplicate case labels. + */ + @Test(expected = RuntimeException.class) + public void generateFromFixDictionaryWithNestedGroups() throws Exception { + final File schema = new File(MessageCodeGeneratorTest.class.getResource("/org/quickfixj/codegenerator/MessageFactory.xsl").getFile()); + final File spec = new File(MessageCodeGeneratorTest.class.getResource("/nested-group.xml").getFile()); + + final MessageCodeGenerator.Task task = new MessageCodeGenerator.Task(); + task.setName("nested"); + task.setSpecification(spec); + task.setTransformDirectory(schema.getParentFile()); + task.setMessagePackage("nested"); + task.setOutputBaseDirectory(folder.getRoot()); + task.setFieldPackage("field"); + task.setOverwrite(true); + task.setOrderedFields(true); + task.setDecimalGenerated(false); + final MessageCodeGenerator generator = new MessageCodeGenerator(); + generator.generate(task); + + final File fieldDir = new File(folder.getRoot(), "field"); + final File messageDir = new File(folder.getRoot(), "nested"); + + final Map classNameToSourceMap = new LinkedHashMap<>(); + classNameToSourceMap.put("field.BeginString", getSource(new File(fieldDir, "BeginString.java"))); + classNameToSourceMap.put("field.BodyLength", getSource(new File(fieldDir, "BodyLength.java"))); + classNameToSourceMap.put("field.CheckSum", getSource(new File(fieldDir, "CheckSum.java"))); + classNameToSourceMap.put("field.MsgType", getSource(new File(fieldDir, "MsgType.java"))); + classNameToSourceMap.put("field.Signature", getSource(new File(fieldDir, "Signature.java"))); + classNameToSourceMap.put("field.SignatureLength", getSource(new File(fieldDir, "SignatureLength.java"))); + classNameToSourceMap.put("field.TestReqID", getSource(new File(fieldDir, "TestReqID.java"))); + classNameToSourceMap.put("field.NoFoos", getSource(new File(fieldDir, "NoFoos.java"))); + classNameToSourceMap.put("field.NoBars", getSource(new File(fieldDir, "NoBars.java"))); + classNameToSourceMap.put("field.Foo", getSource(new File(fieldDir, "Foo.java"))); + + classNameToSourceMap.put("basic.Message", getSource(new File(messageDir, "Message.java"))); + classNameToSourceMap.put("basic.TestRequest", getSource(new File(messageDir, "TestRequest.java"))); + classNameToSourceMap.put("basic.MessageCracker", getSource(new File(messageDir, "MessageCracker.java"))); + classNameToSourceMap.put("basic.MessageFactory", getSource(new File(messageDir, "MessageFactory.java"))); + final Map classes = Compiler.compile(classNameToSourceMap); + + final Map fieldDefs = new LinkedHashMap<>(); + fieldDefs.put("BeginString", new FieldDef(8, StringField.class)); + fieldDefs.put("BodyLength", new FieldDef(9, IntField.class)); + fieldDefs.put("CheckSum", new FieldDef(10, StringField.class)); + fieldDefs.put("MsgType", new FieldDef(35, StringField.class)); + fieldDefs.put("Signature", new FieldDef(89, StringField.class)); + fieldDefs.put("SignatureLength", new FieldDef(93, IntField.class)); + fieldDefs.put("TestReqID", new FieldDef(112, StringField.class)); + fieldDefs.put("NoFoos", new FieldDef(112, IntField.class)); + fieldDefs.put("NoBars", new FieldDef(112, IntField.class)); + fieldDefs.put("Foo", new FieldDef(112, StringField.class)); + validateFields(classes, fieldDefs); + + final Map messageDefs = new LinkedHashMap<>(); + messageDefs.put("TestRequest", new MessageDef("1")); + validateMessages(classes, messageDefs); + } + + private String getSource(final File file) throws IOException { + return new String(Files.readAllBytes(file.toPath())); + } + + private void validateFields(final Map classes, final Map fieldDefs) { + for (final Map.Entry fieldDef : fieldDefs.entrySet()) { + final String fieldName = fieldDef.getKey(); + final Field fieldInstance = classes.get("field." + fieldName).create().get(); + assertEquals(String.format("Mismatch on field number for %s", fieldName), fieldDef.getValue().fieldNumber, fieldInstance.getField()); + assertTrue(String.format("Expected %s to be an instance of %s", fieldName, fieldDef.getValue().clazz.getSimpleName()), fieldDef.getValue().clazz.isAssignableFrom(fieldInstance.getClass())); + } + } + + private void validateMessages(final Map classes, final Map messageDefs) throws FieldNotFound { + for (final Map.Entry messageDef : messageDefs.entrySet()) { + final String messageName = messageDef.getKey(); + final Message messageInstance = classes.get("basic." + messageName).create().get(); + assertEquals(String.format("Mismatch on message type for %s", messageName), messageDef.getValue().messageType, messageInstance.getHeader().getString(35)); + } + } + + private final class FieldDef { + private final int fieldNumber; + private final Class> clazz; + + FieldDef(final int fieldNumber, final Class> clazz) { + this.fieldNumber = fieldNumber; + this.clazz = clazz; + } + } + + private final class MessageDef { + private final String messageType; + + MessageDef(final String messageType) { + this.messageType = messageType; + } + } +} diff --git a/quickfixj-core/src/test/resources/basic.xml b/quickfixj-core/src/test/resources/basic.xml new file mode 100644 index 0000000000..4482e9b8f7 --- /dev/null +++ b/quickfixj-core/src/test/resources/basic.xml @@ -0,0 +1,120 @@ + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/quickfixj-core/src/test/resources/nested-group.xml b/quickfixj-core/src/test/resources/nested-group.xml new file mode 100644 index 0000000000..720334cbda --- /dev/null +++ b/quickfixj-core/src/test/resources/nested-group.xml @@ -0,0 +1,131 @@ + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +