TestTimeUnit.cpp (9715B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "TimeUnits.h" 8 #include "gtest/gtest.h" 9 10 using namespace mozilla; 11 using namespace mozilla::media; 12 using TimeUnit = mozilla::media::TimeUnit; 13 14 TEST(TimeUnit, BasicArithmetic) 15 { 16 const TimeUnit a(1000, 44100); 17 { 18 TimeUnit b = a * 10; 19 EXPECT_EQ(b.mBase, 44100); 20 EXPECT_EQ(b.mTicks.value(), a.mTicks.value() * 10); 21 EXPECT_EQ(a * 10, b); 22 } 23 { 24 TimeUnit b = a / 10; 25 EXPECT_EQ(b.mBase, 44100); 26 EXPECT_EQ(b.mTicks.value(), a.mTicks.value() / 10); 27 EXPECT_EQ(a / 10, b); 28 } 29 { 30 TimeUnit b = TimeUnit(10, 44100); 31 b += a; 32 EXPECT_EQ(b.mBase, 44100); 33 EXPECT_EQ(b.mTicks.value(), a.mTicks.value() + 10); 34 EXPECT_EQ(b - a, TimeUnit(10, 44100)); 35 } 36 { 37 TimeUnit b = TimeUnit(1010, 44100); 38 b -= a; // now 10 39 EXPECT_EQ(b.mBase, 44100); 40 EXPECT_EQ(b.mTicks.value(), 10); 41 EXPECT_EQ(a + b, TimeUnit(1010, 44100)); 42 } 43 { 44 TimeUnit b = TimeUnit(4010, 44100); 45 TimeUnit c = b % a; // now 10 46 EXPECT_EQ(c.mBase, 44100); 47 EXPECT_EQ(c.mTicks.value(), 10); 48 } 49 { 50 // Adding 6s in nanoseconds (e.g. coming from script) to a typical number 51 // from an mp4, 9001 in base 90000 52 TimeUnit b = TimeUnit(6000000000, 1000000000); 53 TimeUnit c = TimeUnit(9001, 90000); 54 TimeUnit d = c + b; 55 EXPECT_EQ(d.mBase, 90000); 56 EXPECT_EQ(d.mTicks.value(), 549001); 57 } 58 { 59 // Subtracting 9001 in base 9000 from 6s in nanoseconds (e.g. coming from 60 // script), converting to back to base 9000. 61 TimeUnit b = TimeUnit(6000000000, 1000000000); 62 TimeUnit c = TimeUnit(9001, 90000); 63 TimeUnit d = (b - c).ToBase(90000); 64 EXPECT_EQ(d.mBase, 90000); 65 EXPECT_EQ(d.mTicks.value(), 530999); 66 } 67 } 68 69 TEST(TimeUnit, Base) 70 { 71 { 72 TimeUnit a = TimeUnit::FromSeconds(1); 73 EXPECT_EQ(a.mTicks.value(), 1000000); 74 EXPECT_EQ(a.mBase, 1000000); 75 } 76 { 77 TimeUnit a = TimeUnit::FromMicroseconds(44100000000); 78 EXPECT_EQ(a.mTicks.value(), 44100000000); 79 EXPECT_EQ(a.mBase, 1000000); 80 } 81 { 82 TimeUnit a = TimeUnit::FromSeconds(6.0); 83 EXPECT_EQ(a.mTicks.value(), 6000000); 84 EXPECT_EQ(a.mBase, 1000000); 85 double error; 86 TimeUnit b = a.ToBase(90000, error); 87 EXPECT_EQ(error, 0); 88 EXPECT_EQ(b.mTicks.value(), 540000); 89 EXPECT_EQ(b.mBase, 90000); 90 } 91 } 92 93 TEST(TimeUnit, Rounding) 94 { 95 int64_t usecs = 662617; 96 double seconds = TimeUnit::FromMicroseconds(usecs).ToSeconds(); 97 TimeUnit fromSeconds = TimeUnit::FromSeconds(seconds); 98 EXPECT_EQ(fromSeconds.mTicks.value(), usecs); 99 // TimeUnit base is microseconds if not explicitly passed. 100 EXPECT_EQ(fromSeconds.mBase, 1000000); 101 EXPECT_EQ(fromSeconds.ToMicroseconds(), usecs); 102 103 seconds = 4.169470123; 104 int64_t nsecs = 4169470123; 105 EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToNanoseconds(), nsecs); 106 EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToMicroseconds(), nsecs / 1000); 107 108 seconds = 2312312.16947012; 109 nsecs = 2312312169470120; 110 EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToNanoseconds(), nsecs); 111 EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToMicroseconds(), nsecs / 1000); 112 113 seconds = 2312312.169470123; 114 nsecs = 2312312169470123; 115 // A double doesn't have enough precision to roundtrip this time value 116 // correctly in this base, but the number of microseconds is still correct. 117 // This value is about 142.5 days however. 118 // This particular calculation results in exactly 1ns of difference after 119 // roundtrip. Enable this after remoing the MOZ_CRASH in TimeUnit::FromSeconds 120 // EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToNanoseconds() - nsecs, 1); 121 EXPECT_EQ(TimeUnit::FromSeconds(seconds, 1e9).ToMicroseconds(), nsecs / 1000); 122 } 123 124 TEST(TimeUnit, Comparisons) 125 { 126 TimeUnit a(0, 1e9); 127 TimeUnit b(1, 1e9); 128 TimeUnit c(1, 1e6); 129 130 EXPECT_GE(b, a); 131 EXPECT_GE(c, a); 132 EXPECT_GE(c, b); 133 134 EXPECT_GT(b, a); 135 EXPECT_GT(c, a); 136 EXPECT_GT(c, b); 137 138 EXPECT_LE(a, b); 139 EXPECT_LE(a, c); 140 EXPECT_LE(b, c); 141 142 EXPECT_LT(a, b); 143 EXPECT_LT(a, c); 144 EXPECT_LT(b, c); 145 146 // Equivalence of zero regardless of the base 147 TimeUnit d(0, 1); 148 TimeUnit e(0, 1000); 149 EXPECT_EQ(a, d); 150 EXPECT_EQ(a, e); 151 152 // Equivalence of time accross bases 153 TimeUnit f(1000, 1e9); 154 TimeUnit g(1, 1e6); 155 EXPECT_EQ(f, g); 156 157 // Comparisons with infinity, same base 158 TimeUnit h = TimeUnit::FromInfinity(); 159 TimeUnit i = TimeUnit::Zero(); 160 EXPECT_LE(i, h); 161 EXPECT_LT(i, h); 162 EXPECT_GE(h, i); 163 EXPECT_GT(h, i); 164 165 // Comparisons with infinity, different base 166 TimeUnit j = TimeUnit::FromInfinity(); 167 TimeUnit k = TimeUnit::Zero(1000000); 168 EXPECT_LE(k, j); 169 EXPECT_LT(k, j); 170 EXPECT_GE(j, k); 171 EXPECT_GT(j, k); 172 173 // Comparison of very big numbers, different base that have a gcd that makes 174 // it easy to reduce, to test the fraction reduction code 175 TimeUnit l = TimeUnit(123123120000000, 1000000000); 176 TimeUnit m = TimeUnit(123123120000000, 1000); 177 EXPECT_LE(l, m); 178 EXPECT_LT(l, m); 179 EXPECT_GE(m, l); 180 EXPECT_GT(m, l); 181 182 // Comparison of very big numbers, different base that are co-prime: worst 183 // cast scenario. 184 TimeUnit n = TimeUnit(123123123123123, 1000000000); 185 TimeUnit o = TimeUnit(123123123123123, 1000000001); 186 EXPECT_LE(o, n); 187 EXPECT_LT(o, n); 188 EXPECT_GE(n, o); 189 EXPECT_GT(n, o); 190 // Comparison of very big numbers with different bases 191 TimeUnit p(12312312312312312, 100000000); 192 TimeUnit q(123123123123123119, 1000000000); 193 TimeUnit r(123123123123123120, 1000000000); 194 TimeUnit s(123123123123123121, 1000000000); 195 EXPECT_LE(q, p); 196 EXPECT_LT(q, p); 197 EXPECT_NE(q, p); 198 EXPECT_EQ(p, r); 199 EXPECT_GE(s, p); 200 EXPECT_GT(s, p); 201 EXPECT_NE(s, p); 202 // Comparison of different very big numbers. There is intentionally only 203 // one factor of 3 in numerator or denominator to reproduce bug 1909614. 204 TimeUnit t = TimeUnit(123123123123124, 100000000 * 3); 205 TimeUnit u = TimeUnit(123123123123124 * 3, 100000000); 206 EXPECT_NE(t, u); 207 208 // Values taken from a real website (this is about 53 years, Date.now() in 209 // 2023). 210 TimeUnit leftBound(74332508253360, 44100); 211 TimeUnit rightBound(74332508297392, 44100); 212 TimeUnit fuzz(250000, 1000000); 213 TimeUnit time(1685544404790205, 1000000); 214 215 EXPECT_LT(leftBound - fuzz, time); 216 EXPECT_GT(time, leftBound - fuzz); 217 EXPECT_GE(rightBound + fuzz, time); 218 EXPECT_LT(time, rightBound + fuzz); 219 220 TimeUnit zero = TimeUnit::Zero(); // default base 1e6 221 TimeUnit datenow( 222 151737439364679, 223 90000); // Also from `Date.now()` in a common base for an mp4 224 EXPECT_NE(zero, datenow); 225 } 226 227 TEST(TimeUnit, InfinityMath) 228 { 229 // Operator plus/minus uses floating point behaviour for positive and 230 // negative infinity values, i.e.: 231 // posInf + posInf = inf 232 // posInf + negInf = -nan 233 // posInf + finite = inf 234 // posInf - posInf = -nan 235 // posInf - negInf = inf 236 // posInf - finite = inf 237 // negInf + negInf = -inf 238 // negInf + posInf = -nan 239 // negInf + finite = -inf 240 // negInf - negInf = -nan 241 // negInf - posInf = -inf 242 // negInf - finite = -inf 243 // finite + posInf = inf 244 // finite - posInf = -inf 245 // finite + negInf = -inf 246 // finite - negInf = inf 247 248 const TimeUnit posInf = TimeUnit::FromInfinity(); 249 EXPECT_EQ(TimeUnit::FromSeconds(mozilla::PositiveInfinity<double>()), posInf); 250 251 const TimeUnit negInf = TimeUnit::FromNegativeInfinity(); 252 EXPECT_EQ(TimeUnit::FromSeconds(mozilla::NegativeInfinity<double>()), negInf); 253 254 EXPECT_EQ(posInf + posInf, posInf); 255 EXPECT_FALSE((posInf + negInf).IsValid()); 256 EXPECT_FALSE((posInf - posInf).IsValid()); 257 EXPECT_EQ(posInf - negInf, posInf); 258 EXPECT_EQ(negInf + negInf, negInf); 259 EXPECT_FALSE((negInf + posInf).IsValid()); 260 EXPECT_FALSE((negInf - negInf).IsValid()); 261 EXPECT_EQ(negInf - posInf, negInf); 262 263 const TimeUnit finite = TimeUnit::FromSeconds(42.0); 264 EXPECT_EQ(posInf - finite, posInf); 265 EXPECT_EQ(posInf + finite, posInf); 266 EXPECT_EQ(negInf - finite, negInf); 267 EXPECT_EQ(negInf + finite, negInf); 268 269 EXPECT_EQ(finite + posInf, posInf); 270 EXPECT_EQ(finite - posInf, negInf); 271 EXPECT_EQ(finite + negInf, negInf); 272 EXPECT_EQ(finite - negInf, posInf); 273 } 274 275 TEST(TimeUnit, BaseConversion) 276 { 277 const int64_t packetSize = 1024; // typical for AAC 278 int64_t sampleRates[] = {16000, 44100, 48000, 88200, 96000}; 279 const double hnsPerSeconds = 10000000.; 280 for (auto sampleRate : sampleRates) { 281 int64_t frameCount = 0; 282 TimeUnit pts; 283 do { 284 // Compute a time in hundreds of nanoseconds based of frame count, typical 285 // on Windows platform, checking that it round trips properly. 286 int64_t hns = AssertedCast<int64_t>( 287 std::round(hnsPerSeconds * static_cast<double>(frameCount) / 288 static_cast<double>(sampleRate))); 289 pts = TimeUnit::FromHns(hns, sampleRate); 290 EXPECT_EQ( 291 AssertedCast<int64_t>(std::round(pts.ToSeconds() * hnsPerSeconds)), 292 hns); 293 frameCount += packetSize; 294 } while (pts.ToSeconds() < 36000); 295 } 296 } 297 298 TEST(TimeUnit, MinimumRoundingError) 299 { 300 TimeUnit a(448, 48000); // ≈9333 us 301 TimeUnit b(1, 1000000); // 1 us 302 TimeUnit rv = a - b; // should close to 9332 us as much as possible 303 EXPECT_EQ(rv.mTicks.value(), 448); // ≈9333 us is closer to 9332 us 304 EXPECT_EQ(rv.mBase, 48000); 305 306 TimeUnit c(11, 1000000); // 11 us 307 rv = a - c; // should close to 9322 as much as possible 308 EXPECT_EQ(rv.mTicks.value(), 447); // ≈9312 us is closer to 9322 us 309 EXPECT_EQ(rv.mBase, 48000); 310 }