public void testWithFlagsSemantics() {
    final AdvancedCache<MagicKey, String> cache1 = advancedCache(0, cacheName);
    final AdvancedCache<MagicKey, String> cache2 = advancedCache(1, cacheName);
    assertNotSame("CacheStores", getCacheStore(cache1), getCacheStore(cache2));
    assertLoadsAndReset(cache1, 0, cache2, 0);

    final AdvancedCache<MagicKey, String> cache1LocalOnly = cache1.withFlags(CACHE_MODE_LOCAL);
    MagicKey localKey = new MagicKey("local", cache1);
    cache1LocalOnly.put(localKey, "value1");
    assertLoadsAndReset(cache1, 1, cache2, 0);

    cache2.withFlags(CACHE_MODE_LOCAL).put(localKey, "value2");
    assertLoadsAndReset(cache1, 0, cache2, 1);

    assertCacheValue(cache1, localKey, "value1");
    assertLoadsAndReset(cache1, 0, cache2, 0);

    assertCacheValue(cache2, localKey, "value2");
    assertLoadsAndReset(cache1, 0, cache2, 0);

    MagicKey nonLocalKey = new MagicKey("nonLocal", cache2);
    cache1.put(nonLocalKey, "value");
    // Write skew check needs the previous version on the originator AND on the primary owner
    int cache1Loads = isTxCache() ? 1 : 0;
    assertLoadsAndReset(cache1, cache1Loads, cache2, 1);

    assertCacheValue(cache2, nonLocalKey, "value");
    assertLoadsAndReset(cache1, 0, cache2, 0);

    final AdvancedCache<MagicKey, String> cache1SkipRemoteAndStores =
        cache1LocalOnly.withFlags(SKIP_CACHE_LOAD);
    MagicKey localKey2 = new MagicKey("local2", cache1);
    cache1SkipRemoteAndStores.put(localKey2, "value");
    assertLoadsAndReset(cache1, 0, cache2, 0);

    assertCacheValue(cache1, localKey2, "value");
    // localKey2 isn't in memory, looks into store
    assertCacheValue(cache2, localKey2, null);
    assertLoadsAndReset(cache1, 0, cache2, 1);

    assertCacheValue(cache2, localKey2, null);
    assertLoadsAndReset(cache1, 0, cache2, 1);
    assertCacheValue(cache2.withFlags(SKIP_CACHE_LOAD), localKey2, null);
    assertLoadsAndReset(cache1, 0, cache2, 0);

    // Options on cache1SkipRemoteAndStores did NOT affect this cache
    MagicKey localKey3 = new MagicKey("local3", cache1);
    assertCacheValue(cache1LocalOnly, localKey3, null);
    assertLoadsAndReset(cache1, 1, cache2, 0);
  }
  public void testCompileFunction() {
    final InMemoryFunctionRepository functions = new InMemoryFunctionRepository();
    final MockFunction alwaysValid = new MockFunction("always valid", null, null);
    final MockFunction validUntil = new MockFunction("valid until", null, 30L);
    final MockFunction validFrom = new MockFunction("valid from", 30L, null);
    final MockFunction validWithin = new MockFunction("valid within", 30L, 30L);
    functions.addFunction(alwaysValid);
    functions.addFunction(validUntil);
    functions.addFunction(validFrom);
    functions.addFunction(validWithin);
    final CachingFunctionRepositoryCompiler compiler = new CachingFunctionRepositoryCompiler();
    final CompiledFunctionService context =
        new CompiledFunctionService(functions, compiler, new FunctionCompilationContext());
    final Instant timestamp = Instant.now();

    // Everything compiled once
    final CompiledFunctionRepository compiledFunctionsNow =
        context.compileFunctionRepository(timestamp);
    assertSame(
        alwaysValid,
        compiledFunctionsNow.getDefinition(alwaysValid.getUniqueId()).getFunctionDefinition());
    assertSame(
        validUntil,
        compiledFunctionsNow.getDefinition(validUntil.getUniqueId()).getFunctionDefinition());
    assertSame(
        validFrom,
        compiledFunctionsNow.getDefinition(validFrom.getUniqueId()).getFunctionDefinition());
    assertSame(
        validWithin,
        compiledFunctionsNow.getDefinition(validWithin.getUniqueId()).getFunctionDefinition());
    assertEquals(1, alwaysValid._compileCount.get());
    assertEquals(1, validUntil._compileCount.get());
    assertEquals(1, validFrom._compileCount.get());
    assertEquals(1, validWithin._compileCount.get());

    // All previously compiled ones still valid, so should use the "previous" cache
    final CompiledFunctionRepository compiledFunctionsAheadWithin =
        context.compileFunctionRepository(timestamp.plusMillis(29L));
    assertSame(compiledFunctionsNow, compiledFunctionsAheadWithin);
    assertEquals(1, alwaysValid._compileCount.get());
    assertEquals(1, validUntil._compileCount.get());
    assertEquals(1, validFrom._compileCount.get());
    assertEquals(1, validWithin._compileCount.get());

    // All previously compiled ones still valid, so should use the "previous" cache
    final CompiledFunctionRepository compiledFunctionsAheadLimit =
        context.compileFunctionRepository(timestamp.plusMillis(30L));
    assertSame(compiledFunctionsNow, compiledFunctionsAheadLimit);
    assertEquals(1, alwaysValid._compileCount.get());
    assertEquals(1, validUntil._compileCount.get());
    assertEquals(1, validFrom._compileCount.get());
    assertEquals(1, validWithin._compileCount.get());

    // Some functions to be recompiled, others from the "previous" cache
    final CompiledFunctionRepository compiledFunctionsAheadBeyond =
        context.compileFunctionRepository(timestamp.plusMillis(31L));
    assertNotSame(compiledFunctionsNow, compiledFunctionsAheadBeyond);
    assertSame(
        compiledFunctionsNow.getDefinition(alwaysValid.getUniqueId()),
        compiledFunctionsAheadBeyond.getDefinition(alwaysValid.getUniqueId()));
    assertNotSame(
        compiledFunctionsNow.getDefinition(validUntil.getUniqueId()),
        compiledFunctionsAheadBeyond.getDefinition(validUntil.getUniqueId()));
    assertSame(
        compiledFunctionsNow.getDefinition(validFrom.getUniqueId()),
        compiledFunctionsAheadBeyond.getDefinition(validFrom.getUniqueId()));
    assertNotSame(
        compiledFunctionsNow.getDefinition(validWithin.getUniqueId()),
        compiledFunctionsAheadBeyond.getDefinition(validWithin.getUniqueId()));
    assertEquals(1, alwaysValid._compileCount.get());
    assertEquals(2, validUntil._compileCount.get());
    assertEquals(1, validFrom._compileCount.get());
    assertEquals(2, validWithin._compileCount.get());

    // All previously compiled functions, so should use the "ahead" cache
    final CompiledFunctionRepository compiledFunctionsBeforeWithin =
        context.compileFunctionRepository(timestamp.minusMillis(30L));
    assertSame(compiledFunctionsNow, compiledFunctionsBeforeWithin);
    assertEquals(1, alwaysValid._compileCount.get());
    assertEquals(2, validUntil._compileCount.get());
    assertEquals(1, validFrom._compileCount.get());
    assertEquals(2, validWithin._compileCount.get());

    // Some functions to be recompiled, others from the "ahead" cache
    final CompiledFunctionRepository compiledFunctionsBeforeBeyond =
        context.compileFunctionRepository(timestamp.minusMillis(31L));
    assertNotSame(compiledFunctionsNow, compiledFunctionsBeforeBeyond);
    assertSame(
        compiledFunctionsNow.getDefinition(alwaysValid.getUniqueId()),
        compiledFunctionsBeforeBeyond.getDefinition(alwaysValid.getUniqueId()));
    assertSame(
        compiledFunctionsNow.getDefinition(validUntil.getUniqueId()),
        compiledFunctionsBeforeBeyond.getDefinition(validUntil.getUniqueId()));
    assertNotSame(
        compiledFunctionsNow.getDefinition(validFrom.getUniqueId()),
        compiledFunctionsBeforeBeyond.getDefinition(validFrom.getUniqueId()));
    assertNotSame(
        compiledFunctionsNow.getDefinition(validWithin.getUniqueId()),
        compiledFunctionsBeforeBeyond.getDefinition(validWithin.getUniqueId()));
    assertEquals(1, alwaysValid._compileCount.get());
    assertEquals(2, validUntil._compileCount.get());
    assertEquals(2, validFrom._compileCount.get());
    assertEquals(3, validWithin._compileCount.get());
  }
  @Test
  public void buildCreditCurveTest() {
    final double[] time = new double[] {0.1, 0.3, 0.5, 1., 3.};
    final double[] forward = new double[] {0.06, 0.1, 0.05, 0.08, 0.11};
    final ISDACompliantCreditCurve cv1 =
        ISDACompliantCreditCurve.makeFromForwardRates(time, forward);

    final int num = time.length;
    final double[] rt = new double[num];
    final double[] r = new double[num];
    rt[0] = forward[0] * time[0];
    r[0] = forward[0];
    for (int i = 1; i < num; ++i) {
      rt[i] = rt[i - 1] + forward[i] * (time[i] - time[i - 1]);
      r[i] = rt[i] / time[i];
      assertEquals(r[i], cv1.getHazardRate(time[i]), EPS);
      assertEquals(Math.exp(-rt[i]), cv1.getSurvivalProbability(time[i]), EPS);
    }
    final ISDACompliantCreditCurve cv2 = ISDACompliantCreditCurve.makeFromRT(time, rt);
    final ISDACompliantCreditCurve cv3 = new ISDACompliantCreditCurve(time, r);

    final double base = 0.05;
    final double[] timeMod = new double[num];
    final double[] rMod = new double[num];
    for (int i = 0; i < num; ++i) {
      timeMod[i] = time[i] + base;
      rMod[i] = (rt[i] + r[0] * base) / timeMod[i];
    }
    final ISDACompliantCreditCurve cv4 = (new ISDACompliantCreditCurve(time, rMod)).withRates(r);
    final ISDACompliantCreditCurve cv1Clone = cv1.clone();
    assertNotSame(cv1, cv1Clone);
    assertEquals(cv1, cv1Clone);
    assertEquals(cv1.toString(), cv1Clone.toString());

    for (int i = 0; i < num; ++i) {
      assertEquals(cv1.getKnotTimes()[i], cv2.getKnotTimes()[i], EPS);
      assertEquals(cv1.getKnotTimes()[i], cv3.getKnotTimes()[i], EPS);
      assertEquals(cv1.getKnotTimes()[i], cv4.getKnotTimes()[i], EPS);
      assertEquals(cv1.getRt()[i], cv2.getRt()[i], EPS);
      assertEquals(cv1.getRt()[i], cv3.getRt()[i], EPS);
      assertEquals(cv1.getRt()[i], cv4.getRt()[i], EPS);
    }

    final ISDACompliantCreditCurve cvOnePoint = new ISDACompliantCreditCurve(time[2], r[2]);
    assertEquals(r[2], cvOnePoint.getForwardRate(time[0]));
    assertEquals(r[2], cvOnePoint.getForwardRate(time[4]));

    /*
     * Meta
     */
    final ISDACompliantCreditCurve.Meta meta = cv1.metaBean();
    final BeanBuilder<?> builder = meta.builder();
    builder.set(meta.metaPropertyGet("name"), "");
    builder.set(meta.metaPropertyGet("t"), time);
    builder.set(meta.metaPropertyGet("rt"), rt);
    ISDACompliantCreditCurve builtCurve = (ISDACompliantCreditCurve) builder.build();
    assertEquals(cv1, builtCurve);

    final ISDACompliantCreditCurve.Meta meta1 = ISDACompliantCreditCurve.meta();
    assertEquals(meta, meta1);

    /*
     * Error expected
     */
    try {
      final double[] rtshort = Arrays.copyOf(rt, num - 2);
      ISDACompliantCreditCurve.makeFromRT(time, rtshort);
    } catch (final Exception e) {
      assertTrue(e instanceof IllegalArgumentException);
    }

    /*
     * hashCode and equals
     */
    assertTrue(cv1.equals(cv1));
    assertTrue(!(cv1.equals(null)));

    final ISDACompliantCurve superCv1 = ISDACompliantCurve.makeFromForwardRates(time, forward);
    assertTrue(cv1.hashCode() != superCv1.hashCode());
    assertTrue(!(cv1.equals(superCv1)));
  }
  @Test
  public void buildDateCurveTest() {
    final LocalDate baseDate = LocalDate.of(2012, 8, 8);
    final LocalDate[] dates =
        new LocalDate[] {
          LocalDate.of(2012, 12, 3),
          LocalDate.of(2013, 4, 29),
          LocalDate.of(2013, 11, 12),
          LocalDate.of(2014, 5, 18)
        };
    final double[] rates = new double[] {0.11, 0.22, 0.15, 0.09};
    final DayCount dcc = DayCounts.ACT_365F;
    final int num = dates.length;

    final ISDACompliantDateCreditCurve baseCurve =
        new ISDACompliantDateCreditCurve(baseDate, dates, rates);
    final LocalDate[] clonedDates = baseCurve.getCurveDates();
    assertNotSame(dates, clonedDates);
    final int modPosition = 2;
    final ISDACompliantDateCreditCurve curveWithRate =
        baseCurve.withRate(rates[modPosition] * 1.5, modPosition);
    final ISDACompliantDateCreditCurve clonedCurve = baseCurve.clone();
    assertNotSame(baseCurve, clonedCurve);

    final double[] t = new double[num];
    final double[] rt = new double[num];
    for (int i = 0; i < num; ++i) {
      assertEquals(dates[i], baseCurve.getCurveDate(i));
      assertEquals(dates[i], curveWithRate.getCurveDate(i));
      assertEquals(dates[i], clonedDates[i]);
      assertEquals(clonedCurve.getCurveDate(i), baseCurve.getCurveDate(i));
      if (i == modPosition) {
        assertEquals(rates[i] * 1.5, curveWithRate.getZeroRateAtIndex(i));
      }
      t[i] = dcc.yearFraction(baseDate, dates[i]);
      rt[i] = t[i] * rates[i];
    }

    final LocalDate[] sampleDates =
        new LocalDate[] {baseDate.plusDays(2), LocalDate.of(2013, 7, 5), dates[2]};
    final int nSampleDates = sampleDates.length;
    final double[] sampleRates = new double[nSampleDates];
    final double[] fracs = new double[nSampleDates];
    for (int i = 0; i < nSampleDates; ++i) {
      fracs[i] = dcc.yearFraction(baseDate, sampleDates[i]);
      sampleRates[i] = baseCurve.getZeroRate(sampleDates[i]);
    }
    assertEquals(rates[0], sampleRates[0]);
    assertEquals(
        (rt[2] * (fracs[1] - t[1]) + rt[1] * (t[2] - fracs[1])) / (t[2] - t[1]) / fracs[1],
        sampleRates[1]);
    assertEquals(rates[2], sampleRates[2]);

    assertEquals(baseDate, baseCurve.getBaseDate());

    /*
     * Test meta
     */
    final Property<LocalDate> propBaseDate = baseCurve.baseDate();
    final Property<LocalDate[]> propDates = baseCurve.dates();
    final Property<DayCount> propDcc = baseCurve.dayCount();

    final Meta meta = baseCurve.metaBean();
    final BeanBuilder<?> builder = meta.builder();
    builder.set(propBaseDate.name(), baseDate);
    builder.set(propDates.name(), dates);
    builder.set(propDcc.name(), dcc);
    builder.set(meta.metaPropertyGet("name"), "");
    builder.set(meta.metaPropertyGet("t"), t);
    builder.set(meta.metaPropertyGet("rt"), rt);
    ISDACompliantDateCreditCurve builtCurve = (ISDACompliantDateCreditCurve) builder.build();
    assertEquals(baseCurve, builtCurve);

    final Meta meta1 = ISDACompliantDateCreditCurve.meta();
    assertEquals(meta1, meta);

    /*
     * hash and equals
     */
    assertTrue(!(baseCurve.equals(null)));
    assertTrue(!(baseCurve.equals(new ISDACompliantDateCurve(baseDate, dates, rates))));
    assertTrue(
        !(baseCurve.equals(new ISDACompliantDateCreditCurve(baseDate.minusDays(1), dates, rates))));
    assertTrue(
        !(baseCurve.equals(
            new ISDACompliantDateCreditCurve(
                baseDate,
                new LocalDate[] {
                  LocalDate.of(2012, 12, 3),
                  LocalDate.of(2013, 4, 29),
                  LocalDate.of(2013, 11, 12),
                  LocalDate.of(2014, 5, 19)
                },
                rates))));
    assertTrue(
        !(baseCurve.equals(
            new ISDACompliantDateCreditCurve(baseDate, dates, rates, DayCounts.ACT_365_25))));

    assertTrue(baseCurve.equals(baseCurve));

    assertTrue(baseCurve.hashCode() != curveWithRate.hashCode());
    assertTrue(!(baseCurve.equals(curveWithRate)));

    /*
     * String
     */
    assertEquals(baseCurve.toString(), clonedCurve.toString());
  }