1 /****************************************************************************
2 ** Copyright (c) 2001-2014
3 **
4 ** This file is part of the QuickFIX FIX Engine
5 **
6 ** This file may be distributed under the terms of the quickfixengine.org
7 ** license as defined by quickfixengine.org and appearing in the file
8 ** LICENSE included in the packaging of this file.
9 **
10 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
11 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12 **
13 ** See http://www.quickfixengine.org/LICENSE for licensing information.
14 **
15 ** Contact ask@quickfixengine.org if any conditions of this licensing are
16 ** not clear to you.
17 **
18 ****************************************************************************/
19
20 #ifdef _MSC_VER
21 #pragma warning( disable : 4503 4355 4786 )
22 #include "stdafx.h"
23 #else
24 #include "config.h"
25 #endif
26
27 #include <UnitTest++.h>
28 #include <FieldNumbers.h>
29 #include <Values.h>
30 #include <fix40/TestRequest.h>
31 #include <fix42/TestRequest.h>
32 #include <fix42/NewOrderSingle.h>
33 #include <fix40/NewOrderSingle.h>
34 #include <fix44/NewOrderList.h>
35 #include <fix44/MarketDataRequest.h>
36 #include <fix44/MarketDataSnapshotFullRefresh.h>
37 #include <fstream>
38
39 using namespace FIX;
40
SUITE(DataDictionaryTests)41 SUITE(DataDictionaryTests)
42 {
43
44 USER_DEFINE_STRING( TooHigh, 501 );
45
46 TEST(addMsgType)
47 {
48 DataDictionary object;
49 CHECK( !object.isMsgType( "A" ) );
50 object.addMsgType( "A" );
51 CHECK( object.isMsgType( "A" ) );
52 }
53
54 TEST(addMsgField)
55 {
56 DataDictionary object;
57 CHECK( !object.isMsgField( "A", 10 ) );
58 CHECK( !object.isMsgField( "Z", 50 ) );
59 object.addMsgField( "A", 10 );
60 object.addMsgField( "Z", 50 );
61 CHECK( object.isMsgField( "A", 10 ) );
62 CHECK( object.isMsgField( "Z", 50 ) );
63 CHECK( !object.isMsgField( "A", 50 ) );
64 CHECK( !object.isMsgField( "Z", 10 ) );
65 }
66
67 TEST(addHeaderField)
68 {
69 DataDictionary object;
70 CHECK( !object.isHeaderField( 56 ) );
71 CHECK( !object.isHeaderField( 49 ) );
72 object.addHeaderField( 56, true );
73 object.addHeaderField( 49, true );
74 CHECK( object.isHeaderField( 56 ) );
75 CHECK( object.isHeaderField( 49 ) );
76 }
77
78 TEST(addTrailerField)
79 {
80 DataDictionary object;
81 CHECK( !object.isTrailerField( 10 ) );
82 object.addTrailerField( 10, true );
83 CHECK( object.isTrailerField( 10 ) );
84 }
85
86 TEST(addFieldType)
87 {
88 DataDictionary object;
89 TYPE::Type type;
90 CHECK( !object.getFieldType( 14, type ) );
91 CHECK( !object.getFieldType( 23, type ) );
92
93 object.addFieldType( 14, TYPE::String );
94 object.addFieldType( 23, TYPE::Char );
95
96 CHECK( object.getFieldType( 14, type ) );
97 CHECK_EQUAL( TYPE::String, type );
98 CHECK( object.getFieldType( 23, type ) );
99 CHECK_EQUAL( TYPE::Char, type );
100 }
101
102 TEST(addRequiredField)
103 {
104 DataDictionary object;
105 CHECK( !object.isRequiredField( "A", 10 ) );
106 CHECK( !object.isRequiredField( "Z", 50 ) );
107 object.addRequiredField( "A", 10 );
108 object.addRequiredField( "Z", 50 );
109 CHECK( object.isRequiredField( "A", 10 ) );
110 CHECK( object.isRequiredField( "Z", 50 ) );
111 CHECK( !object.isRequiredField( "A", 50 ) );
112 CHECK( !object.isRequiredField( "Z", 10 ) );
113 }
114
115 TEST(addFieldValue)
116 {
117 DataDictionary object;
118 CHECK( !object.isFieldValue( 12, "f" ) );
119 CHECK( !object.isFieldValue( 12, "g" ) );
120 CHECK( !object.isFieldValue( 15, "1" ) );
121 CHECK( !object.isFieldValue( 18, "2" ) );
122 CHECK( !object.isFieldValue( 167, "FUT" ) );
123
124 object.addFieldValue( 12, "f" );
125 object.addFieldValue( 12, "g" );
126 object.addFieldValue( 15, "1" );
127 object.addFieldValue( 18, "2" );
128 object.addFieldValue( 167, "FUT" );
129
130 CHECK( object.isFieldValue( 12, "f" ) );
131 CHECK( object.isFieldValue( 12, "g" ) );
132 CHECK( object.isFieldValue( 15, "1" ) );
133 CHECK( object.isFieldValue( 18, "2" ) );
134 CHECK( object.isFieldValue( 167, "FUT" ) );
135 }
136
137 TEST(addGroup)
138 {
139 DataDictionary object;
140 object.setVersion( "FIX.4.2" );
141
142 DataDictionary group1;
143 group1.addMsgType( "1" );
144 DataDictionary group2;
145 group2.addMsgType( "2" );
146 DataDictionary group3;
147 group3.addMsgType( "3" );
148
149 object.addGroup( "A", 100, 101, group1 );
150 object.addGroup( "A", 200, 201, group2 );
151 object.addGroup( "A", 300, 301, group3 );
152
153 int delim;
154 const DataDictionary* pDD = 0;
155
156 CHECK( object.getGroup( "A", 100, delim, pDD ) );
157 CHECK_EQUAL( 101, delim );
158 CHECK( pDD->isMsgType( "1" ) );
159
160 CHECK( object.getGroup( "A", 200, delim, pDD ) );
161 CHECK_EQUAL( 201, delim );
162 CHECK( pDD->isMsgType( "2" ) );
163
164 CHECK( object.getGroup( "A", 300, delim, pDD ) );
165 CHECK_EQUAL( 301, delim );
166 CHECK( pDD->isMsgType( "3" ) );
167 }
168
169 TEST(addFieldName)
170 {
171 DataDictionary object;
172 object.setVersion( "FIX.4.2" );
173
174 object.addFieldName( 1, "Account" );
175 object.addFieldName( 11, "ClOrdID" );
176 object.addFieldName( 8, "BeginString" );
177
178 std::string name;
179 int field;
180 CHECK( object.getFieldName( 1, name ) );
181 CHECK_EQUAL( "Account", name );
182 CHECK( object.getFieldTag( name, field ) );
183 CHECK_EQUAL( 1, field );
184 CHECK( object.getFieldName( 11, name ) );
185 CHECK_EQUAL( "ClOrdID", name );
186 CHECK( object.getFieldTag( name, field ) );
187 CHECK_EQUAL( 11, field );
188 CHECK( object.getFieldName( 8, name ) );
189 CHECK_EQUAL( "BeginString", name );
190 CHECK( object.getFieldTag( name, field ) );
191 CHECK_EQUAL( 8, field );
192 }
193
194 TEST(addValueName)
195 {
196 DataDictionary object;
197 object.setVersion( "FIX.4.2" );
198
199 object.addValueName( 12, "0", "VALUE_12_0" );
200 object.addValueName( 12, "B", "VALUE_12_B" );
201 object.addValueName( 23, "BOO", "VALUE_23_BOO" );
202
203 std::string name;
204 CHECK( object.getValueName( 12, "0", name ) );
205 CHECK_EQUAL( "VALUE_12_0", name );
206 CHECK( object.getValueName( 12, "B", name ) );
207 CHECK_EQUAL( "VALUE_12_B", name );
208 CHECK( object.getValueName( 23, "BOO", name ) );
209 CHECK_EQUAL( "VALUE_23_BOO", name );
210 }
211
212 struct checkValidTagNumberFixture
213 {
214 checkValidTagNumberFixture()
215 {
216 object.setVersion( BeginString_FIX40 );
217 object.addField( FIELD::BeginString );
218 object.addField( FIELD::BodyLength );
219 object.addField( FIELD::MsgType );
220 object.addField( FIELD::CheckSum );
221 object.addField( FIELD::TestReqID );
222 object.addMsgType( MsgType_TestRequest );
223 object.addMsgField( MsgType_TestRequest, FIELD::TestReqID );
224 }
225
226 DataDictionary object;
227 };
228
229 TEST_FIXTURE(checkValidTagNumberFixture, checkValidTagNumber)
230 {
231 TestReqID testReqID( "1" );
232 FIX40::TestRequest message( testReqID );
233 message.setField( TooHigh( "value" ) );
234 CHECK_THROW( object.validate( message ), InvalidTagNumber );
235
236 object.allowUnknownMsgFields( true );
237 object.validate( message );
238 object.allowUnknownMsgFields( false );
239
240 object.addField( 501 );
241 object.addMsgField( MsgType_TestRequest, 501 );
242 object.validate( message );
243
244 message.setField( FIELD::UserMin, "value" );
245 CHECK_THROW( object.validate( message ), InvalidTagNumber );
246
247 object.checkUserDefinedFields( false );
248 object.validate( message );
249 }
250
251 TEST(checkHasValue)
252 {
253 DataDictionary object;
254 Message testReqID( "8=FIX.4.2\0019=12\00135=1\001112=\00110=007\001", false );
255 FIX42::TestRequest message( testReqID );
256
257 CHECK_THROW( object.validate( message ), NoTagValue );
258 }
259
260 struct checkIsInMessageFixture
261 {
262 checkIsInMessageFixture()
263 {
264 object.setVersion( BeginString_FIX40 );
265 object.addField( FIELD::BeginString );
266 object.addField( FIELD::BodyLength );
267 object.addField( FIELD::MsgType );
268 object.addField( FIELD::CheckSum );
269 object.addField( FIELD::TestReqID );
270 object.addField( FIELD::Symbol );
271 object.addMsgType( MsgType_TestRequest );
272 object.addMsgField( MsgType_TestRequest, FIELD::TestReqID );
273 }
274
275 DataDictionary object;
276 };
277
278 TEST_FIXTURE(checkIsInMessageFixture, checkIsInMessage)
279 {
280 TestReqID testReqID( "1" );
281
282 FIX40::TestRequest message( testReqID );
283 object.validate( message );
284
285 message.setField( Symbol( "MSFT" ) );
286 CHECK_THROW( object.validate( message ), TagNotDefinedForMessage );
287 }
288
289 struct checkHasRequiredFixture
290 {
291 checkHasRequiredFixture()
292 {
293 object.setVersion( BeginString_FIX40 );
294 object.addField( FIELD::BeginString );
295 object.addField( FIELD::BodyLength );
296 object.addField( FIELD::MsgType );
297 object.addField( FIELD::SenderCompID );
298 object.addField( FIELD::TargetCompID );
299 object.addHeaderField( FIELD::SenderCompID, true );
300 object.addHeaderField( FIELD::TargetCompID, false );
301 object.addField( FIELD::CheckSum );
302 object.addField( FIELD::TestReqID );
303 object.addMsgType( MsgType_TestRequest );
304 object.addMsgField( MsgType_TestRequest, FIELD::TestReqID );
305 object.addRequiredField( MsgType_TestRequest, FIELD::TestReqID );
306 }
307
308 DataDictionary object;
309 };
310
311 TEST_FIXTURE(checkHasRequiredFixture, checkHasRequired)
312 {
313 FIX40::TestRequest message;
314 CHECK_THROW( object.validate( message ), RequiredTagMissing );
315
316 message.getHeader().setField( SenderCompID( "SENDER" ) );
317 CHECK_THROW( object.validate( message ), RequiredTagMissing );
318
319 message.setField( TestReqID( "1" ) );
320 object.validate( message );
321
322 message.getHeader().removeField( FIELD::SenderCompID );
323 message.setField( SenderCompID( "SENDER" ) );
324 CHECK_THROW( object.validate( message ), RequiredTagMissing );
325 }
326
327 struct checkValidFormatFixture
328 {
329 checkValidFormatFixture()
330 {
331 object.setVersion( BeginString_FIX40 );
332 object.addField( FIELD::BeginString );
333 object.addField( FIELD::BodyLength );
334 object.addField( FIELD::MsgType );
335 object.addField( FIELD::CheckSum );
336 object.addField( FIELD::TestReqID );
337 object.addMsgType( MsgType_TestRequest );
338 object.addMsgField( MsgType_TestRequest, FIELD::TestReqID );
339 object.addFieldType( FIELD::TestReqID, TYPE::Int );
340 }
341
342 DataDictionary object;
343 };
344
345 TEST_FIXTURE( checkValidFormatFixture, checkValidFormat )
346 {
347 FIX40::TestRequest message;
348 message.setField( TestReqID( "+200" ) );
349 CHECK_THROW( object.validate( message ), IncorrectDataFormat );
350 }
351
352 struct checkValueFixture
353 {
354 checkValueFixture()
355 {
356 object.setVersion( BeginString_FIX40 );
357 object.addField( FIELD::BeginString );
358 object.addField( FIELD::BodyLength );
359 object.addField( FIELD::MsgType );
360 object.addField( FIELD::CheckSum );
361 object.addField( FIELD::OrdType );
362 object.addField( FIELD::OrderRestrictions );
363 object.addMsgType( MsgType_NewOrderSingle );
364 object.addMsgField( MsgType_NewOrderSingle, FIELD::OrdType );
365 object.addMsgField( MsgType_NewOrderSingle, FIELD::OrderRestrictions );
366 object.addFieldType( FIELD::OrdType, TYPE::Char );
367 object.addFieldValue( FIELD::OrdType, "1" );
368 object.addFieldType( FIELD::OrderRestrictions, TYPE::MultipleValueString );
369 object.addFieldValue( FIELD::OrderRestrictions, "1" );
370 object.addFieldValue( FIELD::OrderRestrictions, "2" );
371 object.addFieldValue( FIELD::OrderRestrictions, "3" );
372 }
373
374 DataDictionary object;
375 };
376
377 TEST_FIXTURE( checkValueFixture, checkValue )
378 {
379 DataDictionary object;
380 FIX40::NewOrderSingle message;
381 message.setField( OrdType( '1' ) );
382 object.validate( message );
383
384 message.setField( OrdType( '2' ) );
385 object.validate( message );
386
387 message.setField( OrdType( '1' ) );
388 message.setField( OrderRestrictions("1 2 3") );
389 object.validate( message );
390
391 message.setField( OrderRestrictions("1 4 3") );
392 object.validate( message );
393 }
394
395 TEST( checkRepeatedTag )
396 {
397 DataDictionary object;
398 FIX40::NewOrderSingle message;
399 message.setField( OrdType('1') );
400 message.setField( OrdType('1'), false );
401 CHECK_THROW( object.validate(message), RepeatedTag );
402 }
403
404 struct checkGroupCountFixture
405 {
406 checkGroupCountFixture()
407 {
408 object.setVersion( BeginString_FIX42 );
409 object.addField( FIELD::BeginString );
410 object.addField( FIELD::BodyLength );
411 object.addField( FIELD::MsgType );
412 object.addField( FIELD::CheckSum );
413 object.addField( FIELD::NoAllocs );
414 DataDictionary groupDD;
415 groupDD.addField( FIELD::AllocAccount );
416 object.addGroup( "D", FIELD::NoAllocs, FIELD::AllocAccount, groupDD );
417 object.addMsgType( MsgType_NewOrderSingle );
418 object.addMsgField( MsgType_NewOrderSingle, FIELD::NoAllocs );
419 }
420
421 DataDictionary object;
422 };
423
424 TEST_FIXTURE( checkGroupCountFixture, checkGroupCount )
425 {
426 FIX42::NewOrderSingle message;
427 FIX42::NewOrderSingle::NoAllocs group;
428 group.setField( AllocAccount("account") );
429 message.addGroup( group );
430 message.set( NoAllocs(2) );
431 CHECK_THROW( object.validate( message ), RepeatingGroupCountMismatch );
432 }
433
434 TEST( checkGroupRequiredFields )
435 {
436 DataDictionary object( "../spec/FIX44.xml" );
437 FIX44::NewOrderList newOrderList;
438 newOrderList.setString("8=FIX.4.49=18635=E49=FIXTEST56=TW128=SS134=252=20050225-16:54:3266=WMListOrID000000362394=368=173=111=SE102354=155=IBM67=163=021=381=060=20050225-16:54:3238=1000040=115=USD10=119", false, &object);
439 object.validate( newOrderList );
440
441 newOrderList.setString("8=FIX.4.49=15835=E49=FIXTEST56=TW128=SS134=252=20050225-16:54:3266=WMListOrID000000362394=368=173=163=021=381=060=20050225-16:54:3238=1000040=115=USD10=036", false, &object);
442 CHECK_THROW( object.validate( newOrderList ), RequiredTagMissing );
443
444 newOrderList.setString("8=FIX.4.49=26935=E49=FIXTEST56=TW128=SS134=252=20050225-16:54:3266=WMListOrID000000362394=368=173=211=SE102354=155=IBM67=163=021=381=060=20050225-16:54:3238=1000040=115=USD11=SE104555=MSFT67=163=021=381=060=20050225-16:54:3238=1000040=115=USD47=A10=109", false, &object);
445 CHECK_THROW( object.validate( newOrderList ), RequiredTagMissing );
446
447 FIX44::MarketDataRequest marketDataRequest(
448 MDReqID("1"),
449 SubscriptionRequestType( SubscriptionRequestType_SNAPSHOT_PLUS_UPDATES ),
450 MarketDepth( 9999 ) );
451
452 marketDataRequest.set( MDUpdateType( MDUpdateType_INCREMENTAL_REFRESH ) );
453 marketDataRequest.set( AggregatedBook( true ) );
454 marketDataRequest.set( MDImplicitDelete( true ) );
455
456 FIX44::MarketDataRequest::NoRelatedSym noRelatedSym;
457
458 noRelatedSym.set( Symbol( "QQQQ" ) );
459 marketDataRequest.addGroup( noRelatedSym );
460
461 FIX44::MarketDataRequest::NoMDEntryTypes noMDEntryTypes;
462
463 noMDEntryTypes.set( MDEntryType( MDEntryType_BID ) );
464 marketDataRequest.addGroup( noMDEntryTypes );
465
466 noMDEntryTypes.set( MDEntryType( MDEntryType_OFFER ) );
467 marketDataRequest.addGroup( noMDEntryTypes );
468
469 noMDEntryTypes.set( MDEntryType( MDEntryType_TRADE ) );
470 marketDataRequest.addGroup( noMDEntryTypes );
471
472 object.validate( marketDataRequest );
473
474 noMDEntryTypes.removeField( FIELD::MDEntryType );
475 marketDataRequest.addGroup( noMDEntryTypes );
476 CHECK_THROW( object.validate( marketDataRequest ), RequiredTagMissing );
477
478 FIX44::MarketDataSnapshotFullRefresh md;
479 md.set( MDReqID("1") );
480 md.set( Symbol("QQQQ") );
481
482 FIX44::MarketDataSnapshotFullRefresh::NoMDEntries entry;
483
484 entry.set( MDEntryType( MDEntryType_OFFER ) );
485 entry.set( MDEntryPx( 41.48 ) );
486 entry.set( MDEntrySize( 500 ) );
487 md.addGroup( entry );
488
489 entry.set( MDEntryType( MDEntryType_BID ) );
490 entry.set( MDEntryPx( 41.2 ) );
491 entry.set( MDEntrySize( 300 ) );
492 md.addGroup( entry );
493
494 Message message( md.toString(), object );
495 object.validate( message );
496 //object.validate( md );
497 }
498
499 TEST( readFromFile )
500 {
501 DataDictionary object( "../spec/FIX43.xml" );
502 CHECK( object.isHeaderField( 56 ) );
503 CHECK( !object.isHeaderField( 38 ) );
504 CHECK( !object.isHeaderField( 10 ) );
505
506 CHECK( object.isTrailerField( 10 ) );
507 CHECK( !object.isTrailerField( 38 ) );
508 CHECK( !object.isTrailerField( 56 ) );
509
510 CHECK( object.isMsgType( "A" ) );
511 CHECK( object.isMsgField( "A", 383 ) );
512
513 TYPE::Type type = TYPE::Unknown;
514 CHECK( object.getFieldType( 383, type ) );
515 CHECK_EQUAL( TYPE::Length, type );
516
517 CHECK( object.isRequiredField( "A", 108 ) );
518 CHECK( !object.isRequiredField( "A", 383 ) );
519 CHECK( object.isRequiredField( "6", 28 ) );
520 CHECK( !object.isRequiredField( "B", 55 ) );
521
522 CHECK( object.isFieldValue( 40, "A" ) );
523 CHECK( !object.isFieldValue( 40, "Z" ) );
524
525 std::string name;
526 CHECK( object.getFieldName( 1, name ) );
527 CHECK_EQUAL( "Account", name );
528 CHECK( object.getFieldName( 11, name ) );
529 CHECK_EQUAL( "ClOrdID", name );
530 CHECK( object.getFieldName( 8, name ) );
531 CHECK_EQUAL( "BeginString", name );
532
533 CHECK( object.getValueName( 18, "1", name ) );
534 CHECK_EQUAL( "NOTHELD", name );
535 CHECK( object.getValueName( 18, "2", name ) );
536 CHECK_EQUAL( "WORK", name );
537 CHECK( object.getValueName( 18, "W", name ) );
538 CHECK_EQUAL( "PEGVWAP", name );
539
540 const DataDictionary* pDD = 0;
541 int delim = 0;
542 CHECK( object.getGroup( "b", 296, delim, pDD ) );
543 CHECK_EQUAL( 302, delim );
544 CHECK( pDD->isField( 295 ) );
545 CHECK( pDD->isField( 310 ) );
546 CHECK( !pDD->isField( 55 ) );
547 CHECK( pDD->getGroup( "b", 295, delim, pDD ) );
548 CHECK_EQUAL( 299, delim );
549 CHECK( pDD->isField( 55 ) );
550 CHECK( !pDD->isField( 310 ) );
551 CHECK( object.getGroup( "8", 453, delim, pDD ) );
552 CHECK_EQUAL( 448, delim );
553 CHECK( object.getGroup( "y", 146, delim, pDD ) );
554 CHECK_EQUAL( 55, delim );
555 }
556
557 TEST( readFromStream )
558 {
559 std::fstream stream( "../spec/FIX43.xml" );
560 DataDictionary object( stream );
561 }
562
563 struct copyFixture
564 {
565 copyFixture()
566 {
567 object.setVersion( BeginString_FIX40 );
568 object.addMsgType( MsgType_NewOrderSingle );
569 object.addMsgField( MsgType_NewOrderSingle, FIELD::OrdType );
570 object.addFieldType( FIELD::OrdType, TYPE::Char );
571 object.addFieldValue( FIELD::OrdType, "1" );
572
573 DataDictionary dataDictionary1;
574 dataDictionary1.addFieldType( FIELD::HeartBtInt, TYPE::String );
575 DataDictionary dataDictionary2;
576 dataDictionary2.addFieldType( FIELD::MsgType, TYPE::Char );
577 dataDictionary1.addGroup( "A", 1, 2, dataDictionary2 );
578 object.addGroup( "A", 10, 20, dataDictionary1 );
579 }
580
581 DataDictionary object;
582 };
583
584 TEST_FIXTURE( copyFixture, copy )
585 {
586 DataDictionary dataDictionary = object;
587 TYPE::Type type;
588 int delim;
589
590 CHECK_EQUAL( BeginString_FIX40, dataDictionary.getVersion() );
591 CHECK( dataDictionary.isMsgType( MsgType_NewOrderSingle ) );
592 CHECK( dataDictionary.isMsgField( MsgType_NewOrderSingle, FIELD::OrdType ) );
593 CHECK( dataDictionary.getFieldType( FIELD::OrdType, type ) );
594 CHECK_EQUAL( TYPE::Char, type );
595 CHECK( dataDictionary.isFieldValue( FIELD::OrdType, "1" ) );
596
597 const DataDictionary* pDD = 0;
598 CHECK( dataDictionary.getGroup( "A", 10, delim, pDD ) );
599 CHECK( pDD->getFieldType( FIELD::HeartBtInt, type ) );
600 CHECK_EQUAL( TYPE::String, type );
601 CHECK_EQUAL( 20, delim );
602
603 CHECK( pDD->getGroup( "A", 1, delim, pDD ) );
604 CHECK( pDD->getFieldType( FIELD::MsgType, type ) );
605 CHECK_EQUAL( TYPE::Char, type );
606 CHECK_EQUAL( 2, delim );
607 }
608
609 }
610
611