/src/quantlib/fuzz-test-suite/fuzztimefunctions.cpp
Line | Count | Source |
1 | | /* |
2 | | Copyright (C) 2026 David Korczynski |
3 | | |
4 | | This file is part of QuantLib, a free-software/open-source library |
5 | | for financial quantitative analysts and developers - http://quantlib.org/ |
6 | | |
7 | | QuantLib is free software: you can redistribute it and/or modify it |
8 | | under the terms of the QuantLib license. You should have received a |
9 | | copy of the license along with this program; if not, please email |
10 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
11 | | <https://www.quantlib.org/license.shtml>. |
12 | | |
13 | | This program is distributed in the hope that it will be useful, but WITHOUT |
14 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
15 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
16 | | */ |
17 | | |
18 | | #include <ql/time/asx.hpp> |
19 | | #include <ql/time/calendar.hpp> |
20 | | #include <ql/time/calendars/argentina.hpp> |
21 | | #include <ql/time/calendars/australia.hpp> |
22 | | #include <ql/time/calendars/brazil.hpp> |
23 | | #include <ql/time/calendars/canada.hpp> |
24 | | #include <ql/time/calendars/china.hpp> |
25 | | #include <ql/time/calendars/germany.hpp> |
26 | | #include <ql/time/calendars/india.hpp> |
27 | | #include <ql/time/calendars/japan.hpp> |
28 | | #include <ql/time/calendars/southkorea.hpp> |
29 | | #include <ql/time/calendars/target.hpp> |
30 | | #include <ql/time/calendars/unitedkingdom.hpp> |
31 | | #include <ql/time/calendars/unitedstates.hpp> |
32 | | #include <ql/time/daycounters/actual360.hpp> |
33 | | #include <ql/time/daycounters/actual365fixed.hpp> |
34 | | #include <ql/time/daycounters/actualactual.hpp> |
35 | | #include <ql/time/daycounters/business252.hpp> |
36 | | #include <ql/time/daycounters/thirty360.hpp> |
37 | | #include <ql/time/ecb.hpp> |
38 | | #include <ql/time/imm.hpp> |
39 | | #include <ql/time/schedule.hpp> |
40 | | #include <ql/utilities/dataparsers.hpp> |
41 | | #include <fuzzer/FuzzedDataProvider.h> |
42 | | #include <string> |
43 | | |
44 | | using namespace QuantLib; |
45 | | |
46 | 6.12k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
47 | 6.12k | FuzzedDataProvider fdp(data, size); |
48 | | |
49 | 6.12k | try { |
50 | | // --- Calendar operations with fuzz-selected calendar --- |
51 | 6.12k | Calendar calendars[] = { |
52 | 6.12k | TARGET(), |
53 | 6.12k | UnitedStates(UnitedStates::GovernmentBond), |
54 | 6.12k | UnitedStates(UnitedStates::NYSE), |
55 | 6.12k | UnitedStates(UnitedStates::FederalReserve), |
56 | 6.12k | UnitedKingdom(), |
57 | 6.12k | Germany(Germany::Eurex), |
58 | 6.12k | Germany(Germany::FrankfurtStockExchange), |
59 | 6.12k | Japan(), |
60 | 6.12k | China(China::SSE), |
61 | 6.12k | Canada(), |
62 | 6.12k | Australia(), |
63 | 6.12k | Brazil(), |
64 | 6.12k | India(), |
65 | 6.12k | SouthKorea(SouthKorea::KRX), |
66 | 6.12k | Argentina(), |
67 | 6.12k | }; |
68 | 6.12k | auto calIdx = fdp.ConsumeIntegralInRange<int>(0, 14); |
69 | 6.12k | Calendar cal = calendars[calIdx]; |
70 | | |
71 | | // Build dates from fuzz input |
72 | 6.12k | auto year1 = fdp.ConsumeIntegralInRange<int>(1901, 2199); |
73 | 6.12k | auto month1 = fdp.ConsumeIntegralInRange<int>(1, 12); |
74 | 6.12k | auto day1 = fdp.ConsumeIntegralInRange<int>(1, 28); |
75 | 6.12k | auto year2 = fdp.ConsumeIntegralInRange<int>(1901, 2199); |
76 | 6.12k | auto month2 = fdp.ConsumeIntegralInRange<int>(1, 12); |
77 | 6.12k | auto day2 = fdp.ConsumeIntegralInRange<int>(1, 28); |
78 | | |
79 | 6.12k | Date d1(day1, static_cast<Month>(month1), year1); |
80 | 6.12k | Date d2(day2, static_cast<Month>(month2), year2); |
81 | | |
82 | | // Exercise calendar functions |
83 | 6.12k | (void)cal.isBusinessDay(d1); |
84 | 6.12k | (void)cal.isHoliday(d1); |
85 | 6.12k | (void)cal.isEndOfMonth(d1); |
86 | 6.12k | (void)cal.endOfMonth(d1); |
87 | 6.12k | (void)cal.name(); |
88 | | |
89 | 6.12k | BusinessDayConvention convs[] = { |
90 | 6.12k | Following, ModifiedFollowing, Preceding, |
91 | 6.12k | ModifiedPreceding, Unadjusted, Nearest, |
92 | 6.12k | HalfMonthModifiedFollowing}; |
93 | 6.12k | auto convIdx = fdp.ConsumeIntegralInRange<int>(0, 6); |
94 | 6.12k | BusinessDayConvention conv = convs[convIdx]; |
95 | | |
96 | 6.12k | (void)cal.adjust(d1, conv); |
97 | | |
98 | 6.12k | auto advanceDays = fdp.ConsumeIntegralInRange<int>(-365, 365); |
99 | 6.12k | (void)cal.advance(d1, advanceDays, Days, conv); |
100 | | |
101 | 6.12k | auto advanceMonths = fdp.ConsumeIntegralInRange<int>(-24, 24); |
102 | 6.12k | (void)cal.advance(d1, advanceMonths, Months, conv, true); |
103 | | |
104 | 6.12k | if (d1 < d2) { |
105 | 2.59k | (void)cal.businessDaysBetween(d1, d2); |
106 | 2.59k | (void)cal.holidayList(d1, d2); |
107 | 2.59k | } |
108 | | |
109 | | // --- Day counter operations --- |
110 | 6.12k | DayCounter dayCounters[] = { |
111 | 6.12k | Actual360(), Actual365Fixed(), |
112 | 6.12k | Thirty360(Thirty360::BondBasis), |
113 | 6.12k | Thirty360(Thirty360::EurobondBasis), |
114 | 6.12k | ActualActual(ActualActual::ISMA), |
115 | 6.12k | ActualActual(ActualActual::ISDA), |
116 | 6.12k | ActualActual(ActualActual::AFB), |
117 | 6.12k | Business252(cal)}; |
118 | 6.12k | auto dcIdx = fdp.ConsumeIntegralInRange<int>(0, 7); |
119 | 6.12k | DayCounter dc = dayCounters[dcIdx]; |
120 | | |
121 | 6.12k | if (d1 < d2) { |
122 | 2.59k | (void)dc.dayCount(d1, d2); |
123 | 2.59k | (void)dc.yearFraction(d1, d2); |
124 | 2.59k | } |
125 | | |
126 | | // --- IMM / ASX / ECB date functions --- |
127 | 6.12k | (void)IMM::isIMMdate(d1); |
128 | 6.12k | (void)IMM::nextDate(d1); |
129 | 6.12k | (void)ASX::isASXdate(d1); |
130 | 6.12k | (void)ASX::nextDate(d1); |
131 | 6.12k | (void)ECB::nextDate(d1); |
132 | | |
133 | | // --- Schedule generation --- |
134 | 6.12k | Frequency freqs[] = {Annual, Semiannual, Quarterly, |
135 | 6.12k | Monthly, Weekly, Biweekly}; |
136 | 6.12k | auto freqIdx = fdp.ConsumeIntegralInRange<int>(0, 5); |
137 | 6.12k | Frequency freq = freqs[freqIdx]; |
138 | | |
139 | 6.12k | DateGeneration::Rule rules[] = { |
140 | 6.12k | DateGeneration::Backward, DateGeneration::Forward, |
141 | 6.12k | DateGeneration::Zero, DateGeneration::ThirdWednesday, |
142 | 6.12k | DateGeneration::Twentieth}; |
143 | 6.12k | auto ruleIdx = fdp.ConsumeIntegralInRange<int>(0, 4); |
144 | 6.12k | DateGeneration::Rule rule = rules[ruleIdx]; |
145 | | |
146 | 6.12k | if (d1 < d2) { |
147 | 2.41k | Date start = d1; |
148 | 2.41k | Date end = d2; |
149 | | // Cap the range to avoid extremely long schedules |
150 | 2.41k | if (end - start > 365 * 40) |
151 | 1.42k | end = start + 365 * 40; |
152 | | |
153 | 2.41k | Schedule schedule(start, end, Period(freq), cal, |
154 | 2.41k | conv, conv, rule, false); |
155 | 2.41k | (void)schedule.size(); |
156 | 2.41k | (void)schedule.dates(); |
157 | 2.41k | if (schedule.size() > 0) { |
158 | 2.32k | (void)schedule.startDate(); |
159 | 2.32k | (void)schedule.endDate(); |
160 | 2.32k | } |
161 | 2.41k | } |
162 | | |
163 | | // --- Period parsing from fuzz strings --- |
164 | 6.12k | auto periodStr = fdp.ConsumeRandomLengthString(20); |
165 | 6.12k | (void)PeriodParser::parse(periodStr); |
166 | | |
167 | | // --- Date parsing from fuzz strings --- |
168 | 6.12k | auto dateStr = fdp.ConsumeRandomLengthString(30); |
169 | 6.12k | (void)DateParser::parseISO(dateStr); |
170 | 6.12k | (void)DateParser::parseFormatted(dateStr, "%Y-%m-%d"); |
171 | | |
172 | 6.12k | } catch (const std::exception&) { |
173 | 6.11k | } |
174 | 6.12k | return 0; |
175 | 6.12k | } |