Add gcov/lcov coverage reporting and new test cases for payoffs, bonds, Heston, and cash flows#8
Add gcov/lcov coverage reporting and new test cases for payoffs, bonds, Heston, and cash flows#8tobydrinkall wants to merge 2 commits into
Conversation
- Add QL_ENABLE_COVERAGE CMake option with gcov/lcov support - Add 'make coverage' custom target for HTML report generation - Add PayoffTests: NullPayoff, PlainVanilla, CashOrNothing, AssetOrNothing, Gap, SuperFund, SuperShare, PercentageStrike, FloatingType payoffs with boundary/edge cases - Add BondFunctionsTests: date inspectors, accrual, duration (Simple/Macaulay/Modified), convexity, bps, basisPointValue, yieldValueBasisPoint, clean/dirty price, yield, ATM rate, z-spread, zero-coupon bond, Duration::Type streaming - Add HestonProcessTests: accessors, size/factors, initial values, drift, drift with negative variance (PartialTruncation, FullTruncation, Reflection), diffusion matrix, apply, evolve with QE/PartialTruncation, multiple discretization schemes - Add CashFlowsMoreTests: NPV with InterestRate/YieldTermStructure, bps, duration types, convexity, basisPointValue, z-spread, ATM rate, yield round-trip, SimpleCashFlow leg, previous/next cash flow iteration, z-spread NPV consistency Local verification: 100% build, 1373 test cases passed, 0 failed Co-Authored-By: Toby Drinkall <toby.drinkall@cognition.ai>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
| BOOST_CHECK_CLOSE(call(100.0), 0.0, 1e-10); | ||
| BOOST_CHECK_CLOSE(call(80.0), 0.0, 1e-10); |
There was a problem hiding this comment.
🟡 BOOST_CHECK_CLOSE used with 0.0 expected value — wrong assertion for zero comparisons
Throughout test-suite/payoffs.cpp, BOOST_CHECK_CLOSE is used 17 times with an expected value of 0.0 (e.g., BOOST_CHECK_CLOSE(call(80.0), 0.0, 1e-10)). BOOST_CHECK_CLOSE performs a relative tolerance comparison, and Boost documentation explicitly states both arguments must be non-zero. While the tests happen to pass when both values are exactly 0.0 (due to safe_fpt_division internals), these assertions cannot properly catch bugs: if the payoff implementation were changed to return a tiny non-zero value (e.g. 1e-20) instead of exact 0.0, BOOST_CHECK_CLOSE would always fail regardless of the tolerance — because the relative difference against 0.0 is infinite. The existing test suite correctly uses BOOST_CHECK_SMALL or BOOST_CHECK_EQUAL for zero comparisons (e.g., test-suite/bondfunctions.cpp:314, test-suite/integrals.cpp:355). These 17 occurrences should use BOOST_CHECK_EQUAL(x, 0.0) (for exact zero) or BOOST_CHECK_SMALL(x, tol) (for approximate zero).
Prompt for agents
In test-suite/payoffs.cpp, all 17 uses of BOOST_CHECK_CLOSE with a 0.0 expected value should be replaced with BOOST_CHECK_EQUAL(x, 0.0) since the payoff results are exact zeros from std::max. The affected lines are: 48, 49, 55, 56, 76, 77, 82, 95, 96, 100, 112, 118, 133, 134, 148, 149, 164. For example, line 48 should change from BOOST_CHECK_CLOSE(call(100.0), 0.0, 1e-10) to BOOST_CHECK_EQUAL(call(100.0), 0.0). Similarly, in test-suite/hestonprocess.cpp line 177, BOOST_CHECK_CLOSE(diff[0][1], 0.0, 1e-10) should become BOOST_CHECK_EQUAL(diff[0][1], 0.0) since the diffusion matrix element is explicitly assigned 0.0.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Fixed in 6b4bd0c — all 17 BOOST_CHECK_CLOSE(x, 0.0, tol) replaced with BOOST_CHECK_EQUAL(x, 0.0) since these payoff results are exact zeros from std::max. All 1373 tests still pass.
|
|
||
| Real vol = std::sqrt(0.04); | ||
| BOOST_CHECK_CLOSE(diff[0][0], vol, 1e-10); | ||
| BOOST_CHECK_CLOSE(diff[0][1], 0.0, 1e-10); |
There was a problem hiding this comment.
🟡 BOOST_CHECK_CLOSE used with 0.0 expected value in diffusion matrix test
Same issue as in payoffs.cpp: BOOST_CHECK_CLOSE(diff[0][1], 0.0, 1e-10) uses relative comparison against zero. The diffusion matrix at ql/processes/hestonprocess.cpp:99 explicitly sets tmp[0][1] = 0.0, so the result is exact zero. BOOST_CHECK_EQUAL should be used instead, consistent with the existing test suite's patterns.
| BOOST_CHECK_CLOSE(diff[0][1], 0.0, 1e-10); | |
| BOOST_CHECK_EQUAL(diff[0][1], 0.0); |
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Fixed in the same commit (6b4bd0c) — changed to BOOST_CHECK_EQUAL(diff[0][1], 0.0) since the diffusion matrix element is explicitly assigned 0.0.
Replace BOOST_CHECK_CLOSE(x, 0.0, tol) with BOOST_CHECK_EQUAL(x, 0.0) for exact-zero payoff/diffusion results. BOOST_CHECK_CLOSE uses relative comparison which is undefined against zero. Co-Authored-By: Toby Drinkall <toby.drinkall@cognition.ai>
Summary
Adds CMake-based gcov/lcov coverage reporting infrastructure and 43 new Boost.Test cases targeting business-critical coverage gaps identified via baseline measurement.
Coverage infrastructure
New CMake option
QL_ENABLE_COVERAGE=ONadds-fprofile-arcs -ftest-coverageflags (GCC/Clang only). Custommake coveragetarget runs:lcov --zerocounters→ctest→lcov --capture→lcov --extract .../ql/*→genhtml.Coverage results (before → after)
Targeted file improvements:
instruments/payoffs.cpppricingengines/bond/bondfunctions.cppcashflows/duration.cppcashflows/cashflows.cppprocesses/hestonprocess.cppNew test files (4 files, 43 test cases)
test-suite/payoffs.cpp—PayoffTests(9 cases):NullPayoff,PlainVanillaPayoff(call/put/boundary),CashOrNothingPayoff,AssetOrNothingPayoff,GapPayoff,SuperFundPayoff,SuperSharePayoff,PercentageStrikePayoff,FloatingTypePayoff. Covers all payoff operator()/accept()/description() paths.test-suite/bondfunctions.cpp—BondFunctionsTests(12 cases): date inspectors (startDate,maturityDate,isTradable), cash flow inspectors (nextCashFlowDate/Amount,previousCouponRate), accrual inspectors,duration(Simple/Macaulay/Modified + relationshipmodified ≈ macaulay/(1+y)),convexity,bps,basisPointValue/yieldValueBasisPoint, clean/dirty price from yield, yield-from-price round-trip,atmRate,zSpread, zero-coupon bond,Duration::Typeoperator<<.test-suite/hestonprocess.cpp—HestonProcessTests(10 cases): accessors,size()/factors()for QE vs Broadie-Kaya,initialValues(),drift()with positive/negative variance across PartialTruncation/FullTruncation/Reflection,diffusion()matrix structure,apply()(log-normal spot + additive variance),evolve()with QE and PartialTruncation, all 5 standard discretization schemes.test-suite/cashflowsmore.cpp—CashFlowsMoreTests(12 cases):CashFlows::npvwithInterestRate(monotonicity in rate),bps,duration(all 3 types),convexity,basisPointValue/yieldValueBasisPoint,zSpreadround-trip,atmRate, yield-from-NPV round-trip,SimpleCashFlowleg, previous/next cash flow iteration, NPV withYieldTermStructureand z-spread consistency.Local verification
No CI on this fork — all verification is local."
Link to Devin session: https://app.devin.ai/sessions/531a528a8c414c328b721bf32799c28b
Requested by: @tobydrinkall
Devin Review