| 1 | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| 2 | |
| 3 | /* |
| 4 | Copyright (C) 2007, 2014 Ferdinando Ametrano |
| 5 | |
| 6 | This file is part of QuantLib, a free-software/open-source library |
| 7 | for financial quantitative analysts and developers - http://quantlib.org/ |
| 8 | |
| 9 | QuantLib is free software: you can redistribute it and/or modify it |
| 10 | under the terms of the QuantLib license. You should have received a |
| 11 | copy of the license along with this program; if not, please email |
| 12 | <quantlib-dev@lists.sf.net>. The license is also available online at |
| 13 | <http://quantlib.org/license.shtml>. |
| 14 | |
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 17 | FOR A PARTICULAR PURPOSE. See the license for more details. |
| 18 | */ |
| 19 | |
| 20 | #include "period.hpp" |
| 21 | #include "utilities.hpp" |
| 22 | #include "ql/time/period.hpp" |
| 23 | |
| 24 | using namespace QuantLib; |
| 25 | using namespace boost::unit_test_framework; |
| 26 | |
| 27 | void PeriodTest::testYearsMonthsAlgebra() { |
| 28 | |
| 29 | BOOST_TEST_MESSAGE("Testing period algebra on years/months..." ); |
| 30 | |
| 31 | Period OneYear(1, Years); |
| 32 | Period SixMonths(6, Months); |
| 33 | Period ThreeMonths(3, Months); |
| 34 | |
| 35 | Integer n = 4; |
| 36 | if (OneYear/n!=ThreeMonths) |
| 37 | BOOST_ERROR("division error: " << OneYear << "/" << n << |
| 38 | " not equal to " << ThreeMonths); |
| 39 | n = 2; |
| 40 | if (OneYear/n!=SixMonths) |
| 41 | BOOST_ERROR("division error: " << OneYear << "/" << n << |
| 42 | " not equal to " << SixMonths); |
| 43 | |
| 44 | Period sum=ThreeMonths; |
| 45 | sum+=SixMonths; |
| 46 | if (sum!=Period(9, Months)) |
| 47 | BOOST_ERROR("sum error: " << ThreeMonths << |
| 48 | " + " << SixMonths << |
| 49 | " != " << Period(9, Months)); |
| 50 | |
| 51 | sum+=OneYear; |
| 52 | if (sum!=Period(21, Months)) |
| 53 | BOOST_ERROR("sum error: " << ThreeMonths << |
| 54 | " + " << SixMonths << |
| 55 | " + " << OneYear << |
| 56 | " != " << Period(21, Months)); |
| 57 | |
| 58 | Period TwelveMonths(12, Months); |
| 59 | if (TwelveMonths.length()!=12) |
| 60 | BOOST_ERROR("normalization error: TwelveMonths.length()" << |
| 61 | " is " << TwelveMonths.length() << |
| 62 | " instead of 12" ); |
| 63 | if (TwelveMonths.units()!=Months) |
| 64 | BOOST_ERROR("normalization error: TwelveMonths.units()" << |
| 65 | " is " << TwelveMonths.units() << |
| 66 | " instead of " << Months); |
| 67 | |
| 68 | Period NormalizedTwelveMonths(12, Months); |
| 69 | NormalizedTwelveMonths.normalize(); |
| 70 | if (NormalizedTwelveMonths.length()!=1) |
| 71 | BOOST_ERROR("normalization error: NormalizedTwelveMonths.length()" << |
| 72 | " is " << NormalizedTwelveMonths.length() << |
| 73 | " instead of 1" ); |
| 74 | if (NormalizedTwelveMonths.units()!=Years) |
| 75 | BOOST_ERROR("normalization error: NormalizedTwelveMonths.units()" << |
| 76 | " is " << NormalizedTwelveMonths.units() << |
| 77 | " instead of " << Years); |
| 78 | } |
| 79 | |
| 80 | void PeriodTest::testWeeksDaysAlgebra() { |
| 81 | |
| 82 | BOOST_TEST_MESSAGE("Testing period algebra on weeks/days..." ); |
| 83 | |
| 84 | Period TwoWeeks(2, Weeks); |
| 85 | Period OneWeek(1, Weeks); |
| 86 | Period ThreeDays(3, Days); |
| 87 | Period OneDay(1, Days); |
| 88 | |
| 89 | Integer n = 2; |
| 90 | if (TwoWeeks/n!=OneWeek) |
| 91 | BOOST_ERROR("division error: " << TwoWeeks << "/" << n << |
| 92 | " not equal to " << OneWeek); |
| 93 | n = 7; |
| 94 | if (OneWeek/n!=OneDay) |
| 95 | BOOST_ERROR("division error: " << OneWeek << "/" << n << |
| 96 | " not equal to " << OneDay); |
| 97 | |
| 98 | Period sum=ThreeDays; |
| 99 | sum+=OneDay; |
| 100 | if (sum!=Period(4, Days)) |
| 101 | BOOST_ERROR("sum error: " << ThreeDays << |
| 102 | " + " << OneDay << |
| 103 | " != " << Period(4, Days)); |
| 104 | |
| 105 | sum+=OneWeek; |
| 106 | if (sum!=Period(11, Days)) |
| 107 | BOOST_ERROR("sum error: " << ThreeDays << |
| 108 | " + " << OneDay << |
| 109 | " + " << OneWeek << |
| 110 | " != " << Period(11, Days)); |
| 111 | |
| 112 | Period SevenDays(7, Days); |
| 113 | if (SevenDays.length()!=7) |
| 114 | BOOST_ERROR("normalization error: SevenDays.length()" << |
| 115 | " is " << SevenDays.length() << |
| 116 | " instead of 7" ); |
| 117 | if (SevenDays.units()!=Days) |
| 118 | BOOST_ERROR("normalization error: SevenDays.units()" << |
| 119 | " is " << SevenDays.units() << |
| 120 | " instead of " << Days); |
| 121 | } |
| 122 | |
| 123 | void PeriodTest::testNormalization() { |
| 124 | |
| 125 | BOOST_TEST_MESSAGE("Testing period normalization..." ); |
| 126 | |
| 127 | Period test_values[] = { |
| 128 | 0 * Days, |
| 129 | 0 * Weeks, |
| 130 | 0 * Months, |
| 131 | 0 * Years, |
| 132 | 3 * Days, |
| 133 | 7 * Days, |
| 134 | 14 * Days, |
| 135 | 30 * Days, |
| 136 | 60 * Days, |
| 137 | 365 * Days, |
| 138 | 1 * Weeks, |
| 139 | 2 * Weeks, |
| 140 | 4 * Weeks, |
| 141 | 8 * Weeks, |
| 142 | 52 * Weeks, |
| 143 | 1 * Months, |
| 144 | 2 * Months, |
| 145 | 6 * Months, |
| 146 | 12 * Months, |
| 147 | 18 * Months, |
| 148 | 24 * Months, |
| 149 | 1 * Years, |
| 150 | 2 * Years |
| 151 | }; |
| 152 | |
| 153 | for (Period p1 : test_values) { |
| 154 | auto n1 = p1.normalized(); |
| 155 | if (n1 != p1) { |
| 156 | BOOST_ERROR("Normalizing " << p1 << " yields " << n1 << ", which compares different" ); |
| 157 | } |
| 158 | |
| 159 | for (Period p2 : test_values) { |
| 160 | auto n2 = p2.normalized(); |
| 161 | ext::optional<bool> comparison; |
| 162 | try { |
| 163 | comparison = (p1 == p2); |
| 164 | } catch (Error&) { |
| 165 | ; |
| 166 | } |
| 167 | |
| 168 | if (comparison && *comparison) { |
| 169 | // periods which compare equal must normalize to exactly the same period |
| 170 | if (n1.units() != n2.units() || n1.length() != n2.length()) { |
| 171 | BOOST_ERROR(p1 << " and " << p2 << " compare equal, but normalize to " |
| 172 | << n1 << " and " << n2 << " respectively" ); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | if (n1.units() == n2.units() && n1.length() == n2.length()) { |
| 177 | // periods normalizing to exactly the same period must compare equal |
| 178 | if (p1 != p2) { |
| 179 | BOOST_ERROR(p1 << " and " << p2 << " compare different, but normalize to " |
| 180 | << n1 << " and " << n2 << " respectively" ); |
| 181 | } |
| 182 | } |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | } |
| 187 | |
| 188 | test_suite* PeriodTest::suite() { |
| 189 | auto* suite = BOOST_TEST_SUITE("Period tests" ); |
| 190 | suite->add(QUANTLIB_TEST_CASE(&PeriodTest::testYearsMonthsAlgebra)); |
| 191 | suite->add(QUANTLIB_TEST_CASE(&PeriodTest::testWeeksDaysAlgebra)); |
| 192 | suite->add(QUANTLIB_TEST_CASE(&PeriodTest::testNormalization)); |
| 193 | return suite; |
| 194 | } |
| 195 | |
| 196 | |