units-test.c++ (14753B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #include "units.h" 23 #include <kj/compat/gtest.h> 24 #include <iostream> 25 26 namespace kj { 27 namespace { 28 29 class Bytes; 30 class KiB; 31 class MiB; 32 33 typedef Quantity<int, Bytes> ByteCount; 34 typedef Quantity<int, KiB> KiBCount; 35 typedef Quantity<int, MiB> MiBCount; 36 37 constexpr ByteCount BYTE KJ_UNUSED = unit<ByteCount>(); 38 constexpr KiBCount KIB = unit<KiBCount>(); 39 constexpr MiBCount MIB = unit<MiBCount>(); 40 41 constexpr UnitRatio<int, Bytes, KiB> BYTES_PER_KIB KJ_UNUSED = 1024 * BYTE / KIB; 42 constexpr UnitRatio<int, Bytes, MiB> BYTES_PER_MIB KJ_UNUSED = 1024 * 1024 * BYTE / MIB; 43 constexpr auto KIB_PER_MIB = 1024 * KIB / MIB; 44 45 template <typename T, typename U> 46 kj::String KJ_STRINGIFY(Quantity<T, U> value) { 47 return kj::str(value / unit<Quantity<T, U>>()); 48 } 49 50 TEST(UnitMeasure, Basics) { 51 KiBCount k = 15 * KIB; 52 EXPECT_EQ(15, k / KIB); 53 EXPECT_EQ(16 * KIB, k + KIB); 54 55 k += KIB; 56 k *= 2048; 57 58 EXPECT_EQ(32 * MIB, k / KIB_PER_MIB); 59 60 EXPECT_TRUE(2 * KIB < 4 * KIB); 61 EXPECT_FALSE(8 * KIB < 4 * KIB); 62 } 63 64 template <typename T, typename U> 65 static void assertSameType() { 66 U u; 67 T* t = &u; 68 *t = 0; 69 } 70 71 TEST(UnitMeasure, AtLeastUInt) { 72 assertSameType<uint8_t , AtLeastUInt< 2>>(); 73 assertSameType<uint8_t , AtLeastUInt< 3>>(); 74 assertSameType<uint8_t , AtLeastUInt< 4>>(); 75 assertSameType<uint8_t , AtLeastUInt< 5>>(); 76 assertSameType<uint8_t , AtLeastUInt< 6>>(); 77 assertSameType<uint8_t , AtLeastUInt< 7>>(); 78 assertSameType<uint8_t , AtLeastUInt< 8>>(); 79 assertSameType<uint16_t, AtLeastUInt< 9>>(); 80 assertSameType<uint16_t, AtLeastUInt<10>>(); 81 assertSameType<uint16_t, AtLeastUInt<13>>(); 82 assertSameType<uint16_t, AtLeastUInt<16>>(); 83 assertSameType<uint32_t, AtLeastUInt<17>>(); 84 assertSameType<uint32_t, AtLeastUInt<23>>(); 85 assertSameType<uint32_t, AtLeastUInt<24>>(); 86 assertSameType<uint32_t, AtLeastUInt<25>>(); 87 assertSameType<uint32_t, AtLeastUInt<32>>(); 88 assertSameType<uint64_t, AtLeastUInt<33>>(); 89 assertSameType<uint64_t, AtLeastUInt<40>>(); 90 assertSameType<uint64_t, AtLeastUInt<41>>(); 91 assertSameType<uint64_t, AtLeastUInt<47>>(); 92 assertSameType<uint64_t, AtLeastUInt<48>>(); 93 assertSameType<uint64_t, AtLeastUInt<52>>(); 94 assertSameType<uint64_t, AtLeastUInt<64>>(); 95 96 // COMPILE ERROR: assertSameType<uint64_t, AtLeastUInt<65>>(); 97 } 98 99 TEST(UnitMeasure, BoundedConst) { 100 // TODO(someday): Some script should attempt to compile this test once with each "COMPILE ERROR" 101 // line restored to verify that they actually error out. 102 103 KJ_EXPECT((bounded<456>() + bounded<123>()).unwrap() == 456 + 123); 104 KJ_EXPECT((bounded<456>() - bounded<123>()).unwrap() == 456 - 123); 105 KJ_EXPECT((bounded<456>() * bounded<123>()).unwrap() == 456 * 123); 106 KJ_EXPECT((bounded<456>() / bounded<123>()).unwrap() == 456 / 123); 107 KJ_EXPECT((bounded<456>() % bounded<123>()).unwrap() == 456 % 123); 108 KJ_EXPECT((bounded<456>() << bounded<5>()).unwrap() == 456 << 5); 109 KJ_EXPECT((bounded<456>() >> bounded<2>()).unwrap() == 456 >> 2); 110 111 KJ_EXPECT(bounded<123>() == bounded<123>()); 112 KJ_EXPECT(bounded<123>() != bounded<456>()); 113 KJ_EXPECT(bounded<123>() < bounded<456>()); 114 KJ_EXPECT(bounded<456>() > bounded<123>()); 115 KJ_EXPECT(bounded<123>() <= bounded<456>()); 116 KJ_EXPECT(bounded<456>() >= bounded<123>()); 117 118 KJ_EXPECT(!(bounded<123>() == bounded<456>())); 119 KJ_EXPECT(!(bounded<123>() != bounded<123>())); 120 KJ_EXPECT(!(bounded<456>() < bounded<123>())); 121 KJ_EXPECT(!(bounded<123>() > bounded<456>())); 122 KJ_EXPECT(!(bounded<456>() <= bounded<123>())); 123 KJ_EXPECT(!(bounded<123>() >= bounded<456>())); 124 125 { 126 uint16_t succ = unbound(bounded<12345>()); 127 KJ_EXPECT(succ == 12345); 128 129 // COMPILE ERROR: uint8_t err KJ_UNUSED = unbound(bounded<12345>()); 130 } 131 132 // COMPILE ERROR: auto err1 KJ_UNUSED = bounded<(0xffffffffffffffffull)>() + bounded<1>(); 133 // COMPILE ERROR: auto err2 KJ_UNUSED = bounded<1>() - bounded<2>(); 134 // COMPILE ERROR: auto err3 KJ_UNUSED = bounded<(1ull << 60)>() * bounded<(1ull << 60)>(); 135 // COMPILE ERROR: auto err4 KJ_UNUSED = bounded<1>() / bounded<0>(); 136 // COMPILE ERROR: auto err5 KJ_UNUSED = bounded<1>() % bounded<0>(); 137 // COMPILE ERROR: auto err6 KJ_UNUSED = bounded<1>() << bounded<64>(); 138 // COMPILE ERROR: auto err7 KJ_UNUSED = bounded<(1ull << 60)>() << bounded<4>(); 139 // COMPILE ERROR: auto err8 KJ_UNUSED = bounded<1>() >> bounded<64>(); 140 141 // COMPILE ERROR: boundedAdd<0xffffffffffffffffull, 1>(); 142 // COMPILE ERROR: boundedSub<1, 2>(); 143 // COMPILE ERROR: boundedMul<0x100000000, 0x100000000>(); 144 // COMPILE ERROR: boundedLShift<0x10, 60>(); 145 } 146 147 template <uint value, typename T = uint> 148 constexpr Bounded<value, T> boundedValue(NoInfer<T> runtimeValue = value) { 149 return Bounded<value, T>(runtimeValue, unsafe); 150 } 151 152 TEST(UnitMeasure, Bounded) { 153 // TODO(someday): Some script should attempt to compile this test once with each "COMPILE ERROR" 154 // line restored to verify that they actually error out. 155 156 KJ_EXPECT((boundedValue<456>() + boundedValue<123>()).unwrap() == 456 + 123); 157 KJ_EXPECT(boundedValue<456>().subtractChecked(boundedValue<123>(), [](){}).unwrap() == 456 - 123); 158 KJ_EXPECT((boundedValue<456>() * boundedValue<123>()).unwrap() == 456 * 123); 159 KJ_EXPECT((boundedValue<456>() / boundedValue<123>()).unwrap() == 456 / 123); 160 KJ_EXPECT((boundedValue<456>() % boundedValue<123>()).unwrap() == 456 % 123); 161 162 163 { 164 Bounded<123, uint8_t> succ KJ_UNUSED; 165 // COMPILE ERROR: Bounded<1234, uint8_t> err KJ_UNUSED; 166 // COMPILE ERROR: auto err KJ_UNUSED = boundedValue<0xffffffffull>() + boundedValue<1>(); 167 } 168 169 { 170 Bounded<123, uint8_t> succ1 KJ_UNUSED = boundedValue<123>(); 171 Bounded<123, uint8_t> succ2 KJ_UNUSED = boundedValue<122>(); 172 Bounded<123, uint8_t> succ3 KJ_UNUSED = boundedValue<0>(); 173 // COMPILE ERROR: Bounded<123, uint8_t> err KJ_UNUSED = boundedValue<124>(); 174 // COMPILE ERROR: Bounded<123, uint8_t> err KJ_UNUSED = boundedValue<125>(); 175 // COMPILE ERROR: Bounded<123, uint8_t> err KJ_UNUSED = boundedValue<123456>(); 176 } 177 178 Bounded<123, uint8_t> foo; 179 foo = boundedValue<123>(); 180 foo = boundedValue<122>(); 181 foo = boundedValue<0>(); 182 // COMPILE ERROR: foo = boundedValue<124>(); 183 // COMPILE ERROR: foo = boundedValue<125>(); 184 // COMPILE ERROR: foo = boundedValue<123456>(); 185 186 assertMax<122>(foo, []() {}); 187 // COMPILE ERROR: assertMax<123>(foo, []() {}); 188 // COMPILE ERROR: assertMax<124>(foo, []() {}); 189 190 assertMaxBits<6>(foo, []() {}); 191 // COMPILE ERROR: assertMaxBits<7>(foo, []() {}); 192 // COMPILE ERROR: assertMaxBits<8>(foo, []() {}); 193 194 Bounded<12, uint8_t> bar; 195 // COMPILE ERROR: bar = foo; 196 // COMPILE ERROR: bar = foo.assertMax<13>([]() {}); 197 bool caught = false; 198 foo = boundedValue<13>(); 199 bar = foo.assertMax<12>([&]() { caught = true; }); 200 KJ_EXPECT(caught); 201 202 foo = boundedValue<100>() + boundedValue<23>(); 203 // COMPILE ERROR: foo = boundedValue<100>() + boundedValue<24>(); 204 205 bar = boundedValue<3>() * boundedValue<4>(); 206 // COMPILE ERROR: bar = boundedValue<2>() * boundedValue<7>(); 207 208 foo.subtractChecked(boundedValue<122>(), []() { KJ_FAIL_EXPECT(""); }); 209 foo.subtractChecked(boundedValue<123>(), []() { KJ_FAIL_EXPECT(""); }); 210 caught = false; 211 foo.subtractChecked(boundedValue<124>(), [&]() { caught = true; }); 212 KJ_EXPECT(caught); 213 214 { 215 Bounded<65535, uint16_t> succ1 KJ_UNUSED = bounded((uint16_t)123); 216 // COMPILE ERROR: Bounded<65534, uint16_t> err KJ_UNUSED = bounded((uint16_t)123); 217 } 218 219 uint old = foo.unwrap(); 220 foo = foo * unit<decltype(foo)>(); 221 KJ_EXPECT(foo.unwrap() == old); 222 223 { 224 Bounded<1234, uint16_t> x = bounded<123>(); 225 uint16_t succ = unbound(x); 226 KJ_EXPECT(succ == 123); 227 228 // COMPILE ERROR: uint8_t err KJ_UNUSED = unbound(x); 229 } 230 } 231 232 TEST(UnitMeasure, BoundedVsGuardedConst) { 233 // TODO(someday): Some script should attempt to compile this test once with each "COMPILE ERROR" 234 // line restored to verify that they actually error out. 235 236 KJ_EXPECT((boundedValue<456>() + bounded<123>()).unwrap() == 456 + 123); 237 KJ_EXPECT(boundedValue<456>().subtractChecked(bounded<123>(), [](){}).unwrap() == 456 - 123); 238 KJ_EXPECT((boundedValue<456>() * bounded<123>()).unwrap() == 456 * 123); 239 KJ_EXPECT((boundedValue<456>() / bounded<123>()).unwrap() == 456 / 123); 240 KJ_EXPECT((boundedValue<456>() % bounded<123>()).unwrap() == 456 % 123); 241 242 { 243 Bounded<123, uint8_t> succ1 KJ_UNUSED = bounded<123>(); 244 Bounded<123, uint8_t> succ2 KJ_UNUSED = bounded<122>(); 245 Bounded<123, uint8_t> succ3 KJ_UNUSED = bounded<0>(); 246 // COMPILE ERROR: Bounded<123, uint8_t> err KJ_UNUSED = bounded<124>(); 247 // COMPILE ERROR: Bounded<123, uint8_t> err KJ_UNUSED = bounded<125>(); 248 // COMPILE ERROR: Bounded<123, uint8_t> err KJ_UNUSED = bounded<123456>(); 249 } 250 251 Bounded<123, uint8_t> foo; 252 foo = bounded<123>(); 253 foo = bounded<122>(); 254 foo = bounded<0>(); 255 // COMPILE ERROR: foo = bounded<124>(); 256 // COMPILE ERROR: foo = bounded<125>(); 257 // COMPILE ERROR: foo = bounded<123456>(); 258 259 Bounded<16, uint8_t> bar; 260 // COMPILE ERROR: bar = foo >> bounded<2>(); 261 bar = foo >> bounded<3>(); 262 263 // COMPILE ERROR: foo = bar << bounded<3>(); 264 foo = bar << bounded<2>(); 265 } 266 267 TEST(UnitMeasure, BoundedRange) { 268 uint expected = 0; 269 for (auto i: zeroTo(bounded<10>())) { 270 Bounded<10, uint8_t> value = i; 271 KJ_EXPECT(unbound(value) == expected++); 272 } 273 KJ_EXPECT(expected == 10); 274 275 expected = 0; 276 for (auto i: zeroTo(bounded((uint8_t)10))) { 277 Bounded<255, uint8_t> value = i; 278 KJ_EXPECT(unbound(value) == expected++); 279 } 280 KJ_EXPECT(expected == 10); 281 282 expected = 3; 283 for (auto i: range(bounded((uint8_t)3), bounded((uint8_t)10))) { 284 Bounded<255, uint8_t> value = i; 285 KJ_EXPECT(unbound(value) == expected++); 286 } 287 KJ_EXPECT(expected == 10); 288 } 289 290 TEST(UnitMeasure, BoundedQuantity) { 291 auto BYTES = unit<Quantity<Bounded<12345, uint16_t>, byte>>(); 292 293 uint expected = 0; 294 for (auto i: zeroTo(bounded<10>() * BYTES)) { 295 Quantity<Bounded<10, uint8_t>, byte> value = i; 296 KJ_EXPECT(unbound(value / BYTES) == expected++); 297 } 298 KJ_EXPECT(expected == 10); 299 300 expected = 0; 301 for (auto i: zeroTo(bounded((uint8_t)10) * BYTES)) { 302 Quantity<Bounded<255, uint8_t>, byte> value = i; 303 KJ_EXPECT(unbound(value / BYTES) == expected++); 304 } 305 KJ_EXPECT(expected == 10); 306 307 expected = 3; 308 for (auto i: range(bounded((uint8_t)3) * BYTES, bounded((uint8_t)10) * BYTES)) { 309 Quantity<Bounded<255, uint8_t>, byte> value = i; 310 KJ_EXPECT(unbound(value / BYTES) == expected++); 311 } 312 KJ_EXPECT(expected == 10); 313 } 314 315 template <typename T> 316 void assertTypeAndValue(T a, T b) { KJ_EXPECT(a == b); } 317 318 TEST(UnitMeasure, BoundedMinMax) { 319 assertTypeAndValue(bounded<5>(), kj::max(bounded<4>(), bounded<5>())); 320 assertTypeAndValue(bounded<5>(), kj::max(bounded<5>(), bounded<4>())); 321 assertTypeAndValue(bounded<4>(), kj::max(bounded<4>(), bounded<4>())); 322 323 assertTypeAndValue(bounded<4>(), kj::min(bounded<4>(), bounded<5>())); 324 assertTypeAndValue(bounded<4>(), kj::min(bounded<5>(), bounded<4>())); 325 assertTypeAndValue(bounded<4>(), kj::min(bounded<4>(), bounded<4>())); 326 327 typedef uint8_t t1; 328 typedef uint16_t t2; 329 330 assertTypeAndValue(boundedValue<5,t2>(3), kj::max(boundedValue<4,t2>(3), boundedValue<5,t1>(2))); 331 assertTypeAndValue(boundedValue<5,t2>(3), kj::max(boundedValue<5,t1>(2), boundedValue<4,t2>(3))); 332 assertTypeAndValue(boundedValue<4,t2>(3), kj::max(boundedValue<4,t2>(3), boundedValue<4,t2>(3))); 333 334 assertTypeAndValue(boundedValue<4,t2>(2), kj::min(boundedValue<4,t2>(3), boundedValue<5,t1>(2))); 335 assertTypeAndValue(boundedValue<4,t2>(2), kj::min(boundedValue<5,t1>(2), boundedValue<4,t2>(3))); 336 assertTypeAndValue(boundedValue<4,t2>(3), kj::min(boundedValue<4,t2>(3), boundedValue<4,t2>(3))); 337 338 assertTypeAndValue(boundedValue<5,t1>(4), kj::max(bounded<4>(), boundedValue<5,t1>(2))); 339 assertTypeAndValue(boundedValue<5,t1>(4), kj::max(boundedValue<5,t1>(2), bounded<4>())); 340 341 assertTypeAndValue(boundedValue<4,t1>(2), kj::min(bounded<4>(), boundedValue<5,t1>(2))); 342 assertTypeAndValue(boundedValue<4,t1>(2), kj::min(boundedValue<5,t1>(2), bounded<4>())); 343 344 // These two are degenerate cases. Currently they fail to compile but meybe they shouldn't? 345 // assertTypeAndValue(bounded<5>(), kj::max(boundedValue<4,t2>(3), bounded<5>())); 346 // assertTypeAndValue(bounded<5>(), kj::max(bounded<5>(), boundedValue<4,t2>(3))); 347 348 assertTypeAndValue(boundedValue<4,t2>(3), kj::min(boundedValue<4,t2>(3), bounded<5>())); 349 assertTypeAndValue(boundedValue<4,t2>(3), kj::min(bounded<5>(), boundedValue<4,t2>(3))); 350 } 351 352 #if !_MSC_VER // MSVC barfs on this test and I just don't have time to care. 353 KJ_TEST("compare bounded quantities of different bounds") { 354 auto foo = boundedValue<12345, uint>(123) * unit<Quantity<BoundedConst<1>, byte>>(); 355 auto bar = boundedValue<54321, uint>(123) * unit<Quantity<BoundedConst<1>, byte>>(); 356 auto baz = bounded<123>() * unit<Quantity<BoundedConst<1>, byte>>(); 357 358 KJ_EXPECT(foo == foo); 359 KJ_EXPECT(foo == bar); 360 KJ_EXPECT(foo == baz); 361 KJ_EXPECT(bar == foo); 362 KJ_EXPECT(bar == bar); 363 KJ_EXPECT(bar == baz); 364 KJ_EXPECT(baz == foo); 365 KJ_EXPECT(baz == bar); 366 KJ_EXPECT(baz == baz); 367 368 auto denom = unit<Quantity<BoundedConst<1>, int>>(); 369 370 KJ_EXPECT(foo / denom == foo / denom); 371 KJ_EXPECT(foo / denom == bar / denom); 372 KJ_EXPECT(foo / denom == baz / denom); 373 KJ_EXPECT(bar / denom == foo / denom); 374 KJ_EXPECT(bar / denom == bar / denom); 375 KJ_EXPECT(bar / denom == baz / denom); 376 KJ_EXPECT(baz / denom == foo / denom); 377 KJ_EXPECT(baz / denom == bar / denom); 378 KJ_EXPECT(baz / denom == baz / denom); 379 } 380 #endif 381 382 } // namespace 383 } // namespace kj