#include <stdio.h>
#include "limits.h"
#include "types.h"
#include "engine.c"
#define TEST(num, orders, execs) t_order o ## num [] = orders ; t_execution x ## num [] = execs ; correct += test( o ## num , sizeof( o ## num )/sizeof(t_order) , x ## num , sizeof( x ## num )/sizeof(t_execution));
#define TEST_CANCEL(num, orders1, cancels, orders2, execs) t_order o1st ## num [] = orders1 ; t_orderid c ## num [] = cancels ; t_order o2nd ## num [] = orders2 ; t_execution x ## num [] = execs ; correct += test_cancel( o1st ## num , sizeof( o1st ## num )/sizeof(t_order), c ## num , sizeof( c ## num )/sizeof(t_orderid), o2nd ## num , sizeof( o2nd ## num )/sizeof(t_order) , x ## num, sizeof( x ## num )/sizeof(t_execution));
#define X ,
#define MAX_EXECS 100
unsigned correct = 0;
t_orderid orderid;
unsigned totaltests = 0;
t_execution execs_out[MAX_EXECS];
t_execution * execs_out_iter;
unsigned execs_out_len;
int exec_overflow;
t_order oa101x100 = {"JPM", "MAX", 1, 101, 100};
t_order ob101x100 = {"JPM", "MAX", 0, 101, 100};
t_order oa101x50 = {"JPM", "MAX", 1, 101, 50};
t_order ob101x50 = {"JPM", "MAX", 0, 101, 50};
t_order oa101x25 = {"JPM", "MAX", 1, 101, 25};
t_order ob101x25 = {"JPM", "MAX", 0, 101, 25};
t_order ob101x25x = {"JPM", "XAM", 0, 101, 25};
t_execution xa101x100 = {"JPM", "MAX", 1, 101, 100};
t_execution xb101x100 = {"JPM", "MAX", 0, 101, 100};
t_execution xa101x50 = {"JPM", "MAX", 1, 101, 50};
t_execution xb101x50 = {"JPM", "MAX", 0, 101, 50};
t_execution xa101x25 = {"JPM", "MAX", 1, 101, 25};
t_execution xb101x25 = {"JPM", "MAX", 0, 101, 25};
t_execution xb101x25x = {"JPM", "XAM", 0, 101, 25};
int main() {
printf("ECN Matching Engine Autotester Running\n"
"--------------------------------------\n");
TEST(1, {oa101x100}, {});
TEST(2, {ob101x100}, {});
TEST(3, {oa101x100 X ob101x100}, {xa101x100 X xb101x100});
TEST(4, {oa101x100 X ob101x100}, {xb101x100 X xa101x100});
TEST(5, {ob101x100 X oa101x100}, {xa101x100 X xb101x100});
TEST(6, {ob101x100 X oa101x100}, {xb101x100 X xa101x100});
TEST(7, {oa101x100 X ob101x50}, {xa101x50 X xb101x50});
TEST(8, {oa101x50 X ob101x100}, {xa101x50 X xb101x50});
TEST(9, {oa101x100 X ob101x25 X ob101x25 X ob101x25 X ob101x25 X ob101x25}, {xa101x25 X xb101x25 X xa101x25 X xb101x25 X xa101x25 X xb101x25 X xa101x25 X xb101x25});
TEST(10, {ob101x100 X oa101x25 X oa101x25 X oa101x25 X oa101x25 X oa101x25}, {xa101x25 X xb101x25 X xa101x25 X xb101x25 X xa101x25 X xb101x25 X xa101x25 X xb101x25});
TEST(11, {ob101x25x X ob101x25 X oa101x25}, {xa101x25 X xb101x25x});
TEST_CANCEL(12, {ob101x25}, {1}, {oa101x25}, {});
TEST_CANCEL(13, {ob101x25x X ob101x25}, {1}, {oa101x25}, {xa101x25 X xb101x25});
TEST_CANCEL(14, {ob101x100 X ob101x25x X ob101x25x X ob101x50}, {1 X 4 X 3}, {oa101x50}, {xb101x25x X xa101x25});
printf("--------------------------------------\n");
printf("You got %i/%i tests correct.\n", correct, totaltests);
}
void execution(t_execution exec) {
execs_out_len++;
if (exec_overflow || (execs_out_iter == &execs_out[MAX_EXECS])) {
exec_overflow = 1;
}
*execs_out_iter = exec;
execs_out_iter++;
}
void set_globals() {
orderid = 0;
totaltests++;
exec_overflow = 0;
execs_out_iter = execs_out;
execs_out_len = 0;
}
int feed_orders(t_order orders[], unsigned orders_len) {
int id;
unsigned i;
for(i = 0; i < orders_len; i++) {
id = limit(orders[i]);
orderid++;
if (id != orderid) {
printf("orderid returned was %u, should have been %u.\n",
id, i+1);
return 0;
}
}
return 1;
}
int feed_cancels(t_orderid cancels[], unsigned cancels_len) {
unsigned i;
for(i = 0; i < cancels_len; i++) {
cancel(cancels[i]);
}
return 1;
}
int assert_exec_count(unsigned num_execs_expected) {
if (exec_overflow) {
printf("too many executions, test array overflow");
return 0;
}
int correct = execs_out_len == num_execs_expected;
if (!correct) {
printf("execution called %u times, should have been %u.\n",
execs_out_len, num_execs_expected);
}
return correct;
}
int exec_eq(t_execution * e1, t_execution * e2) {
int eq = 1;
int i;
for (i = 0; i < STRINGLEN; i++) {
if (e1->symbol[i] == '\0' && e2->symbol[i] == '\0') break;
eq = eq &&
e1->symbol[i] == e2->symbol[i] &&
e1->trader[i] == e2->trader[i];
}
eq = eq &&
e1->side == e2->side &&
e1->price == e2->price &&
e1->size == e2->size;
return eq;
}
int assert_execs(t_execution execs[], unsigned execs_len) {
unsigned i;
for(i = 0; i < execs_len; i+=2) {
if(!((exec_eq(&execs[i], &execs_out[i]) &&
exec_eq(&execs[i+1], &execs_out[i+1])) ||
(exec_eq(&execs[i], &execs_out[i+1]) &&
exec_eq(&execs[i+1], &execs_out[i])))) {
printf("executions #%u and #%u,\n"
"{symbol=%s, trader=%s, side=%i, price=%u, size=%u},\n"
"{symbol=%s, trader=%s, side=%i, price=%u, size=%u}\n"
"should have been\n"
"{symbol=%s, trader=%s, side=%i, price=%u, size=%u},\n"
"{symbol=%s, trader=%s, side=%i, price=%u, size=%u}.\n"
"Stopped there.\n",
i, i+1,
execs_out[i].symbol, execs_out[i].trader, execs_out[i].side, execs_out[i].price, (unsigned)execs_out[i].size,
execs_out[i+1].symbol, execs_out[i+1].trader, execs_out[i+1].side, execs_out[i+1].price, (unsigned)execs_out[i+1].size,
execs[i].symbol, execs[i].trader, execs[i].side, execs[i].price, (unsigned)execs[i].size,
execs[i+1].symbol, execs[i+1].trader, execs[i+1].side, execs[i+1].price, (unsigned)execs[i+1].size);
return 0;
}
}
return 1;
}
int test(t_order orders[], unsigned orders_len, t_execution execs[], unsigned execs_len) {
int ok = 1;
set_globals();
init();
ok = ok && feed_orders(orders, orders_len);
ok = ok && assert_exec_count(execs_len);
ok = ok && assert_execs(execs, execs_len);
destroy();
if (!ok) printf("test %i failed.\n\n", totaltests);
return ok;
}
int test_cancel(t_order orders1[], unsigned orders1_len, t_orderid cancels[], unsigned cancels_len, t_order orders2[], unsigned orders2_len, t_execution execs[], unsigned execs_len) {
int ok = 1;
set_globals();
init();
ok = ok && feed_orders(orders1, orders1_len);
feed_cancels(cancels, cancels_len);
ok = ok && feed_orders(orders2, orders2_len);
ok = ok && assert_exec_count(execs_len);
ok = ok && assert_execs(execs, execs_len);
destroy();
if (!ok) printf("test %i failed.\n\n", totaltests);
return ok;
}