/** Test. */
@Test
public class FFTOptionModelTest {
  private static final HashSet<Greek> GREEKS = Sets.newHashSet(Greek.FAIR_PRICE);
  private static final double R = 0.005;
  private static final YieldCurve YIELD_CURVE = YieldCurve.from(ConstantDoublesCurve.from(R));
  private static final double BLACK_VOL = 0.34;
  private static final VolatilitySurface VOLATILITY_SURFACE =
      new VolatilitySurface(ConstantDoublesSurface.from(BLACK_VOL));
  private static final double FORWARD = 100;
  private static final double T = 2;
  private static final ZonedDateTime DATE = DateUtils.getUTCDate(2011, 1, 1);
  private static final ZonedDateTime MATURITY = DATE.plusYears((int) T);
  private static final Expiry EXPIRY = new Expiry(MATURITY);
  private static final EuropeanVanillaOptionDefinition ITM_CALL =
      new EuropeanVanillaOptionDefinition(99, EXPIRY, true);
  private static final EuropeanVanillaOptionDefinition OTM_CALL =
      new EuropeanVanillaOptionDefinition(101, EXPIRY, true);
  private static final EuropeanVanillaOptionDefinition ITM_PUT =
      new EuropeanVanillaOptionDefinition(101, EXPIRY, false);
  private static final EuropeanVanillaOptionDefinition OTM_PUT =
      new EuropeanVanillaOptionDefinition(99, EXPIRY, false);
  private static final MartingaleCharacteristicExponent GAUSSIAN =
      new GaussianMartingaleCharacteristicExponent(BLACK_VOL);
  private static final StandardOptionDataBundle BSM_DATA =
      new StandardOptionDataBundle(
          YIELD_CURVE, R, VOLATILITY_SURFACE, Math.exp(-R * T) * FORWARD, DATE);
  private static final BlackOptionDataBundle BLACK_DATA =
      new BlackOptionDataBundle(FORWARD, YIELD_CURVE, VOLATILITY_SURFACE, DATE);
  private static final OptionModel<EuropeanVanillaOptionDefinition, BlackOptionDataBundle>
      FFT_MODEL = new FFTOptionModel(GAUSSIAN);
  private static final OptionModel<OptionDefinition, StandardOptionDataBundle> BSM_MODEL =
      new BlackScholesMertonModel();
  private static final double EPS = 1e-2;

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullCharacteristicExponent1() {
    new FFTOptionModel(null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullCharacteristicExponent2() {
    new FFTOptionModel(null, 100, 10, -0.5, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNegativeNStrikes() {
    new FFTOptionModel(GAUSSIAN, -100, 10, -0.5, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNegativeDelta() {
    new FFTOptionModel(GAUSSIAN, 100, -10, -0.5, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testZeroAlpha() {
    new FFTOptionModel(GAUSSIAN, 100, 10, 0, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testAlpha() {
    new FFTOptionModel(GAUSSIAN, 100, 10, -1, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNegativeTolerance() {
    new FFTOptionModel(GAUSSIAN, 100, 10, -1, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullDefinition() {
    FFT_MODEL.getGreeks(null, BLACK_DATA, GREEKS);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullData() {
    FFT_MODEL.getGreeks(ITM_CALL, null, GREEKS);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullGreeks() {
    FFT_MODEL.getGreeks(ITM_CALL, BLACK_DATA, null);
  }

  @Test(expectedExceptions = UnsupportedOperationException.class)
  public void testWrongGreeks() {
    FFT_MODEL.getGreeks(ITM_CALL, BLACK_DATA, Sets.newHashSet(Greek.DELTA, Greek.GAMMA));
  }

  @Test
  public void testPricing() {
    GreekResultCollection fftPrice = FFT_MODEL.getGreeks(ITM_CALL, BLACK_DATA, GREEKS);
    GreekResultCollection bsmPrice = BSM_MODEL.getGreeks(ITM_CALL, BSM_DATA, GREEKS);
    assertEquals(fftPrice.size(), 1);
    assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS);
    fftPrice = FFT_MODEL.getGreeks(OTM_CALL, BLACK_DATA, GREEKS);
    bsmPrice = BSM_MODEL.getGreeks(OTM_CALL, BSM_DATA, GREEKS);
    assertEquals(fftPrice.size(), 1);
    assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS);
    fftPrice = FFT_MODEL.getGreeks(OTM_PUT, BLACK_DATA, GREEKS);
    bsmPrice = BSM_MODEL.getGreeks(OTM_PUT, BSM_DATA, GREEKS);
    assertEquals(fftPrice.size(), 1);
    assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS);
    fftPrice = FFT_MODEL.getGreeks(ITM_PUT, BLACK_DATA, GREEKS);
    bsmPrice = BSM_MODEL.getGreeks(ITM_PUT, BSM_DATA, GREEKS);
    assertEquals(fftPrice.size(), 1);
    assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS);
  }
}