public virtual void test_getter()
        {
            assertEquals(VOLS.ValuationDate, VAL_DATE);
            assertEquals(VOLS.Index, GBP_LIBOR_3M);
            assertEquals(VOLS.Surface, SURFACE);
            assertEquals(VOLS.ParameterCount, TIME.size());
            assertEquals(VOLS.findData(CURVE.Name).get(), CURVE);
            assertEquals(VOLS.findData(SURFACE.Name).get(), SURFACE);
            assertFalse(VOLS.findData(CurveName.of("foo")).Present);
            int    nParams  = VOLS.ParameterCount;
            double newValue = 152d;

            for (int i = 0; i < nParams; ++i)
            {
                assertEquals(VOLS.getParameter(i), SURFACE.getParameter(i));
                assertEquals(VOLS.getParameterMetadata(i), SURFACE.getParameterMetadata(i));
                assertEquals(VOLS.withParameter(i, newValue), ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities.of(GBP_LIBOR_3M, VAL_DATE_TIME, SURFACE.withParameter(i, newValue), CURVE));
                assertEquals(VOLS.withPerturbation((n, v, m) => 2d * v), ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities.of(GBP_LIBOR_3M, VAL_DATE_TIME, SURFACE.withPerturbation((n, v, m) => 2d * v), CURVE));
            }
        }
        public virtual void recovery_test_blackSurface_shift()
        {
            SurfaceIborCapletFloorletVolatilityBootstrapDefinition definition = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of(IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, LINEAR, ConstantCurve.of("Black shift", 0.02));
            DoubleArray   strikes = createBlackStrikes();
            RawOptionData data    = RawOptionData.of(createBlackMaturities(), strikes, ValueType.STRIKE, createFullBlackDataMatrix(), ValueType.BLACK_VOLATILITY);
            IborCapletFloorletVolatilityCalibrationResult          res    = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER);
            ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities resVol = (ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities)res.Volatilities;

            for (int i = 0; i < strikes.size(); ++i)
            {
                Pair <IList <ResolvedIborCapFloorLeg>, IList <double> > capsAndVols = getCapsBlackVols(i);
                IList <ResolvedIborCapFloorLeg> caps = capsAndVols.First;
                IList <double> vols  = capsAndVols.Second;
                int            nCaps = caps.Count;
                for (int j = 0; j < nCaps; ++j)
                {
                    ConstantSurface volSurface = ConstantSurface.of(Surfaces.blackVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols[j]);
                    BlackIborCapletFloorletExpiryStrikeVolatilities constVol = BlackIborCapletFloorletExpiryStrikeVolatilities.of(USD_LIBOR_3M, CALIBRATION_TIME, volSurface);
                    double priceOrg   = LEG_PRICER_BLACK.presentValue(caps[j], RATES_PROVIDER, constVol).Amount;
                    double priceCalib = LEG_PRICER_BLACK.presentValue(caps[j], RATES_PROVIDER, resVol).Amount;
                    assertEquals(priceOrg, priceCalib, Math.Max(priceOrg, 1d) * TOL);
                }
            }
            assertEquals(res.ChiSquare, 0d);
            assertEquals(resVol.Index, USD_LIBOR_3M);
            assertEquals(resVol.Name, definition.Name);
            assertEquals(resVol.ValuationDateTime, CALIBRATION_TIME);
            assertEquals(resVol.ShiftCurve, definition.ShiftCurve.get());
            InterpolatedNodalSurface surface = (InterpolatedNodalSurface)resVol.Surface;

            for (int i = 0; i < surface.ParameterCount; ++i)
            {
                GenericVolatilitySurfacePeriodParameterMetadata metadata = (GenericVolatilitySurfacePeriodParameterMetadata)surface.getParameterMetadata(i);
                assertEquals(metadata.Strike.Value + 0.02, surface.YValues.get(i));
            }
        }