package org.marketcetera.event.beans; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.math.BigDecimal; import java.util.Date; import org.junit.Test; import org.marketcetera.event.AskEvent; import org.marketcetera.event.BidEvent; import org.marketcetera.event.EventType; import org.marketcetera.event.QuoteAction; import org.marketcetera.event.impl.QuoteEventBuilder; import org.marketcetera.marketdata.DateUtils; import org.marketcetera.module.ExpectedFailure; import org.marketcetera.options.ExpirationType; import org.marketcetera.trade.Equity; import org.marketcetera.trade.Instrument; import org.marketcetera.trade.Option; import org.marketcetera.trade.OptionType; import org.marketcetera.util.test.EqualityAssert; /* $License$ */ /** * Tests {@link QuoteBean}. * * @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a> * @version $Id: QuoteBeanTest.java 16154 2012-07-14 16:34:05Z colin $ * @since 2.0.0 */ public class QuoteBeanTest extends MarketDataBeanTest { /** * Tests {@link MarketDataBean#copy(MarketDataBean)}. * * @throws Exception if an unexpected error occurs */ @Test public void copy() throws Exception { MarketDataBeanTest.doCopyTest(new QuoteBean()); doCopyTest(new QuoteBean()); } /** * Tests {@link QuoteBean#getQuoteBeanFromEvent(org.marketcetera.event.QuoteEvent, QuoteAction)} and * {@link QuoteBean#getQuoteBeanFromEvent(org.marketcetera.event.QuoteEvent, java.util.Date, java.math.BigDecimal, QuoteAction). * * @throws Exception if an unexpected error occurs */ @Test public void getQuoteBeanFromEvent() throws Exception { Instrument equity = new Equity("METC"); Date timestamp = new Date(); BigDecimal size = BigDecimal.ONE; QuoteAction action = QuoteAction.CHANGE; final QuoteEventBuilder<AskEvent> equityAskBuilder = QuoteEventBuilder.askEvent(equity); equityAskBuilder.withExchange("exchange") .withPrice(BigDecimal.ONE) .withSize(BigDecimal.TEN) .withQuoteDate(DateUtils.dateToString(new Date())); // signature 1 new ExpectedFailure<NullPointerException>(){ @Override protected void run() throws Exception { QuoteBean.getQuoteBeanFromEvent(null, new Date(), BigDecimal.ZERO, QuoteAction.ADD); } }; new ExpectedFailure<NullPointerException>(){ @Override protected void run() throws Exception { AskEvent ask = equityAskBuilder.create(); QuoteBean.getQuoteBeanFromEvent(ask, null, BigDecimal.ZERO, QuoteAction.ADD); } }; new ExpectedFailure<NullPointerException>(){ @Override protected void run() throws Exception { AskEvent ask = equityAskBuilder.create(); QuoteBean.getQuoteBeanFromEvent(ask, new Date(), null, QuoteAction.ADD); } }; new ExpectedFailure<NullPointerException>(){ @Override protected void run() throws Exception { AskEvent ask = equityAskBuilder.create(); QuoteBean.getQuoteBeanFromEvent(ask, new Date(), BigDecimal.ZERO, null); } }; // signature 2 new ExpectedFailure<NullPointerException>(){ @Override protected void run() throws Exception { QuoteBean.getQuoteBeanFromEvent(null, QuoteAction.ADD); } }; new ExpectedFailure<NullPointerException>(){ @Override protected void run() throws Exception { AskEvent ask = equityAskBuilder.create(); QuoteBean.getQuoteBeanFromEvent(ask, null); } }; // valid tests AskEvent ask = equityAskBuilder.create(); // start with null source assertNull(ask.getSource()); verifyQuoteBeanFull(QuoteBean.getQuoteBeanFromEvent(ask, action), ask.getMessageId(), ask.getTimestamp(), ask.getSource(), ask.getExchange(), ask.getExchangeTimestamp(), ask.getInstrument(), ask.getPrice(), ask.getSize(), action, ask.getEventType()); // change to non-null source ask.setSource(this); verifyQuoteBeanFull(QuoteBean.getQuoteBeanFromEvent(ask, action), ask.getMessageId(), ask.getTimestamp(), ask.getSource(), ask.getExchange(), ask.getExchangeTimestamp(), ask.getInstrument(), ask.getPrice(), ask.getSize(), action, ask.getEventType()); // use odd timestamp timestamp = new Date(-1); assertTrue(timestamp.getTime() < 0); verifyQuoteBeanFull(QuoteBean.getQuoteBeanFromEvent(ask, timestamp, size, action), ask.getMessageId(), timestamp, ask.getSource(), ask.getExchange(), ask.getExchangeTimestamp(), ask.getInstrument(), ask.getPrice(), size, action, ask.getEventType()); timestamp = new Date(); // use negative size size = new BigDecimal("-10"); assertTrue(size.intValue() < 0); verifyQuoteBeanFull(QuoteBean.getQuoteBeanFromEvent(ask, timestamp, size, action), ask.getMessageId(), timestamp, ask.getSource(), ask.getExchange(), ask.getExchangeTimestamp(), ask.getInstrument(), ask.getPrice(), size, action, ask.getEventType()); // use zero size size = BigDecimal.ZERO; verifyQuoteBeanFull(QuoteBean.getQuoteBeanFromEvent(ask, timestamp, size, action), ask.getMessageId(), timestamp, ask.getSource(), ask.getExchange(), ask.getExchangeTimestamp(), ask.getInstrument(), ask.getPrice(), size, action, ask.getEventType()); // now try varying the inputs to the event itself // some can't be done (it might look like we're testing the event impl validation here, but // what's really being accomplished is verifying that behavior the quotebean depends on remains // in the event impls. if that behavior changes, this test will fail and the quotebean constructors // will have to be re-evaluated) equityAskBuilder.withMessageId(-1); new ExpectedFailure<IllegalArgumentException>(VALIDATION_INVALID_MESSAGEID.getText(-1)){ @Override protected void run() throws Exception { equityAskBuilder.create(); } }; // this will get a messageId assigned equityAskBuilder.withMessageId(Long.MIN_VALUE); // test the instrument equityAskBuilder.withInstrument(null); new ExpectedFailure<IllegalArgumentException>(){ @Override protected void run() throws Exception { equityAskBuilder.create(); } }; equityAskBuilder.withInstrument(equity); // exchange equityAskBuilder.withExchange(null); new ExpectedFailure<IllegalArgumentException>(VALIDATION_NULL_EXCHANGE.getText()){ @Override protected void run() throws Exception { equityAskBuilder.create(); } }; equityAskBuilder.withExchange(""); new ExpectedFailure<IllegalArgumentException>(VALIDATION_NULL_EXCHANGE.getText()){ @Override protected void run() throws Exception { equityAskBuilder.create(); } }; equityAskBuilder.withExchange("test exchange"); // price equityAskBuilder.withPrice(null); new ExpectedFailure<IllegalArgumentException>(VALIDATION_NULL_PRICE.getText()){ @Override protected void run() throws Exception { equityAskBuilder.create(); } }; equityAskBuilder.withPrice(BigDecimal.ONE); // size equityAskBuilder.withSize(null); new ExpectedFailure<IllegalArgumentException>(VALIDATION_NULL_SIZE.getText()){ @Override protected void run() throws Exception { equityAskBuilder.create(); } }; equityAskBuilder.withSize(BigDecimal.TEN); // exchange timestamp equityAskBuilder.withQuoteDate(null); new ExpectedFailure<IllegalArgumentException>(VALIDATION_NULL_EXCHANGE_TIMESTAMP.getText()){ @Override protected void run() throws Exception { equityAskBuilder.create(); } }; equityAskBuilder.withQuoteDate(""); new ExpectedFailure<IllegalArgumentException>(VALIDATION_NULL_EXCHANGE_TIMESTAMP.getText()){ @Override protected void run() throws Exception { equityAskBuilder.create(); } }; equityAskBuilder.withQuoteDate(DateUtils.dateToString(new Date())); // now test valid cases // event price equityAskBuilder.withPrice(new BigDecimal("-10")); verifyQuoteBeanFull(QuoteBean.getQuoteBeanFromEvent(ask, action), ask.getMessageId(), ask.getTimestamp(), ask.getSource(), ask.getExchange(), ask.getExchangeTimestamp(), ask.getInstrument(), ask.getPrice(), ask.getSize(), action, ask.getEventType()); equityAskBuilder.withPrice(BigDecimal.ZERO); verifyQuoteBeanFull(QuoteBean.getQuoteBeanFromEvent(ask, action), ask.getMessageId(), ask.getTimestamp(), ask.getSource(), ask.getExchange(), ask.getExchangeTimestamp(), ask.getInstrument(), ask.getPrice(), ask.getSize(), action, ask.getEventType()); equityAskBuilder.withPrice(BigDecimal.TEN); // event size equityAskBuilder.withSize(new BigDecimal("-20")); verifyQuoteBeanFull(QuoteBean.getQuoteBeanFromEvent(ask, action), ask.getMessageId(), ask.getTimestamp(), ask.getSource(), ask.getExchange(), ask.getExchangeTimestamp(), ask.getInstrument(), ask.getPrice(), ask.getSize(), action, ask.getEventType()); equityAskBuilder.withSize(BigDecimal.ZERO); verifyQuoteBeanFull(QuoteBean.getQuoteBeanFromEvent(ask, action), ask.getMessageId(), ask.getTimestamp(), ask.getSource(), ask.getExchange(), ask.getExchangeTimestamp(), ask.getInstrument(), ask.getPrice(), ask.getSize(), action, ask.getEventType()); // this seems odd, but it is valid equityAskBuilder.withQuoteDate("this-is-not-a-date"); verifyQuoteBeanFull(QuoteBean.getQuoteBeanFromEvent(ask, action), ask.getMessageId(), ask.getTimestamp(), ask.getSource(), ask.getExchange(), ask.getExchangeTimestamp(), ask.getInstrument(), ask.getPrice(), ask.getSize(), action, ask.getEventType()); // last, show that it doesn't have to be either an ask or an equity Instrument option = new Option("MSFT", "20100319", BigDecimal.ONE, OptionType.Call); final QuoteEventBuilder<BidEvent> optionBidBuilder = QuoteEventBuilder.bidEvent(option); // these values don't need to be as extensively tested because, while necessary to create // an OptionEvent, they don't get transfered to the QuoteEvent optionBidBuilder.withExpirationType(ExpirationType.AMERICAN) .withMultiplier(BigDecimal.ZERO) .withUnderlyingInstrument(equity); // these values will get tested optionBidBuilder.withAction(QuoteAction.DELETE) .withExchange("exchange") .withPrice(BigDecimal.ONE) .withQuoteDate(DateUtils.dateToString(new Date())) .withSize(BigDecimal.TEN); BidEvent bid = optionBidBuilder.create(); verifyQuoteBeanFull(QuoteBean.getQuoteBeanFromEvent(bid, action), bid.getMessageId(), bid.getTimestamp(), bid.getSource(), bid.getExchange(), bid.getExchangeTimestamp(), bid.getInstrument(), bid.getPrice(), bid.getSize(), action, ask.getEventType()); } /** * Tests {@link QuoteBean#getAction()} and {@link QuoteBean#setAction(QuoteAction)}. * * @throws Exception if an unexpected error occurs */ @Test public void action() throws Exception { QuoteBean bean = (QuoteBean)constructBean(); assertNull(bean.getAction()); QuoteAction action = QuoteAction.CHANGE; bean.setAction(action); assertEquals(action, bean.getAction()); } /** * Tests {@link MarketDataBean#hashCode()} and {@link MarketDataBean#equals(Object)}. * * @throws Exception if an unexpected error occurs */ @Test public void hashCodeAndEquals() throws Exception { // test empty bean equality (and inequality with an object of a different class and null) // beans 1 & 2 will always be the same, bean 3 will always be different QuoteBean bean1 = (QuoteBean)constructBean(); QuoteBean bean2 = (QuoteBean)constructBean(); QuoteBean bean3 = (QuoteBean)constructBean(); assertNull(bean1.getAction()); assertNull(bean2.getAction()); EqualityAssert.assertEquality(bean1, bean2, this, null); // test action assertNull(bean1.getAction()); bean3.setAction(QuoteAction.DELETE); EqualityAssert.assertEquality(bean1, bean2, bean3); bean3.setAction(bean1.getAction()); } /* (non-Javadoc) * @see org.marketcetera.event.beans.MarketDataBeanTest#constructBean() */ @Override protected MarketDataBean constructBean() { return new QuoteBean(); } /* (non-Javadoc) * @see org.marketcetera.event.beans.MarketDataBeanTest#doAdditionalValidationTest(org.marketcetera.event.beans.MarketDataBean) */ @Override protected void doAdditionalValidationTest(MarketDataBean inBean) throws Exception { // do MarketDataBean-level validation tests super.doAdditionalValidationTest(inBean); final QuoteBean quote = (QuoteBean)inBean; assertNull(quote.getAction()); new ExpectedFailure<IllegalArgumentException>(VALIDATION_NULL_QUOTE_ACTION.getText()) { @Override protected void run() throws Exception { quote.validate(); } }; quote.setAction(QuoteAction.ADD); } /* (non-Javadoc) * @see org.marketcetera.event.beans.AbstractEventBeanTestBase#doAdditionalSetDefaultsTest(org.marketcetera.event.beans.EventBean) */ @Override protected void doAdditionalSetDefaultsTest(MarketDataBean inBean) throws Exception { // perform MarketDataBean-level defaults test super.doAdditionalSetDefaultsTest(inBean); QuoteBean quote = (QuoteBean)inBean; quote.setAction(null); assertNull(quote.getAction()); quote.setDefaults(); assertEquals(QuoteAction.ADD, quote.getAction()); quote.setAction(QuoteAction.DELETE); quote.setDefaults(); assertEquals(QuoteAction.DELETE, quote.getAction()); } /** * Tests {@link QuoteBean#copy(QuoteBean)}. * * @param inBean a <code>QuoteBean</code> value * @throws Exception if an unexpected error occurs */ static void doCopyTest(QuoteBean inBean) throws Exception { verifyQuoteBean(inBean, null); QuoteBean newBean = QuoteBean.copy(inBean); verifyQuoteBean(newBean, null); QuoteAction action = QuoteAction.CHANGE; inBean.setAction(action); verifyQuoteBean(inBean, action); newBean = QuoteBean.copy(inBean); verifyQuoteBean(newBean, action); } /** * Verifies that the given <code>QuoteBean</code> contains the given attributes. * * @param inBean a <code>QuoteBean</code> value * @param inExpectedAction a <code>QuoteAction</code> value * @throws Exception if an unexpected error occurs */ static void verifyQuoteBean(QuoteBean inBean, QuoteAction inExpectedAction) throws Exception { assertEquals(inExpectedAction, inBean.getAction()); } /** * Verifies that the given <code>QuoteBean</code> contains the given attributes. * * @param inBean a <code>QuoteBean</code> value * @param inExpectedMessageId a <code>long</code> value * @param inExpectedTimestamp a <code>Date</code> value * @param inExpectedSource an <code>Object</code> value * @param inExpectedExchange a <code>String</code> value * @param inExpectedExchangeTimestamp a <code>String</code> value * @param inExpectedInstrument an <code>Instrument</code> value * @param inExpectedPrice a <code>BigDecimal</code> value * @param inExpectedSize a <code>BigDecimal</code> value * @param inExpectedAction a <code>QuoteAction</code> value * @throws Exception if an unexpected error occurs */ static void verifyQuoteBeanFull(QuoteBean inBean, long inExpectedMessageId, Date inExpectedTimestamp, Object inExpectedSource, String inExpectedExchange, String inExpectedExchangeTimestamp, Instrument inExpectedInstrument, BigDecimal inExpectedPrice, BigDecimal inExpectedSize, QuoteAction inExpectedAction, EventType inExpectedMetaType) throws Exception { verifyQuoteBean(inBean, inExpectedAction); verifyMarketDataBean(inBean, inExpectedExchange, inExpectedExchangeTimestamp, inExpectedInstrument, inExpectedPrice, inExpectedSize, inExpectedMetaType); EventBeanTest.verifyEventBean(inBean, inExpectedMessageId, inExpectedTimestamp, inExpectedSource); } }