1 module tests.quantity_tests; 2 3 import quantities; 4 import quantities.internal.dimensions; 5 import std.exception; 6 import std.math : approxEqual; 7 8 enum meter = unit!(double, "L"); 9 enum second = unit!(double, "T"); 10 enum radian = unit!(double, null); 11 12 alias Length = typeof(meter); 13 alias Time = typeof(second); 14 alias Angle = typeof(radian); 15 16 @("this()") 17 @safe pure nothrow unittest 18 { 19 auto distance = Length(meter); 20 auto angle = Angle(3.14); 21 auto length = unit!double("L"); 22 assert(length.dimensions == distance.dimensions); 23 assert(!__traits(compiles, Length(2.0))); 24 } 25 26 @("get/alias this for dimensionless values") 27 @safe pure nothrow unittest 28 { 29 double scalar = radian; 30 assert(scalar == 1); 31 } 32 33 @("value(Q)") 34 @safe pure nothrow unittest 35 { 36 auto distance = meter; 37 assert(distance.value(meter) == 1); 38 } 39 40 @("isDimensionless") 41 @safe pure nothrow unittest 42 { 43 assert(!meter.isDimensionless); 44 assert(radian.isDimensionless); 45 } 46 47 @("isConsistentWith") 48 @safe pure nothrow unittest 49 { 50 assert(meter.isConsistentWith(meter)); 51 assert(!meter.isConsistentWith(second)); 52 } 53 54 @("opCast") 55 @safe pure nothrow unittest 56 { 57 auto value = cast(double) radian; 58 assert(!__traits(compiles, cast(double) meter)); 59 } 60 61 @("opAssign Q") 62 @safe pure nothrow unittest 63 { 64 Length l1, l2; 65 l1 = l2 = meter; 66 67 assert(!__traits(compiles, l1 = second)); 68 } 69 70 @("opAssign T") 71 @safe pure nothrow unittest 72 { 73 Angle angle; 74 angle = 1; 75 } 76 77 @("opUnary + -") 78 @safe pure nothrow unittest 79 { 80 auto plus = +meter; 81 assert(plus.value(meter) == 1); 82 auto minus = -meter; 83 assert(minus.value(meter) == -1); 84 } 85 86 @("opUnary ++ --") 87 @safe pure nothrow unittest 88 { 89 auto len = meter; 90 ++len; 91 assert(len.value(meter).approxEqual(2)); 92 assert((len++).value(meter).approxEqual(2)); 93 assert(len.value(meter).approxEqual(3)); 94 --len; 95 assert(len.value(meter).approxEqual(2)); 96 assert((len--).value(meter).approxEqual(2)); 97 assert(len.value(meter).approxEqual(1)); 98 } 99 100 @("opBinary Q+Q Q-Q") 101 @safe pure nothrow unittest 102 { 103 auto plus = meter + meter; 104 assert(plus.value(meter) == 2); 105 auto minus = meter - meter; 106 assert(minus.value(meter) == 0); 107 108 assert(!__traits(compiles, meter + second)); 109 assert(!__traits(compiles, meter - second)); 110 } 111 112 @("opBinary Q+N N+Q Q-N N-Q") 113 @safe pure nothrow unittest 114 { 115 auto a1 = radian + 10; 116 assert(a1.value(radian).approxEqual(11)); 117 auto a2 = radian - 10; 118 assert(a2.value(radian).approxEqual(-9)); 119 120 auto a3 = 10 + radian; 121 assert(a3.value(radian).approxEqual(11)); 122 auto a4 = 10 - radian; 123 assert(a4.value(radian).approxEqual(9)); 124 125 assert(!__traits(compiles, meter + 1)); 126 assert(!__traits(compiles, meter - 1)); 127 assert(!__traits(compiles, 1 + meter)); 128 assert(!__traits(compiles, 1 - meter)); 129 } 130 131 @("opBinary Q*N, N*Q, Q/N, N/Q, Q%N, N%Q") 132 @safe pure nothrow unittest 133 { 134 auto m1 = meter * 10; 135 assert(m1.value(meter).approxEqual(10)); 136 auto m2 = 10 * meter; 137 assert(m2.value(meter).approxEqual(10)); 138 auto m3 = meter / 10; 139 assert(m3.value(meter).approxEqual(0.1)); 140 auto m4 = 10 / meter; 141 assert(m4.dimensions == ~meter.dimensions); 142 assert(m4.value(1 / meter).approxEqual(10)); 143 auto m5 = m1 % 2; 144 assert(m5.value(meter).approxEqual(0)); 145 auto m6 = 10 % (2 * radian); 146 assert(m6.value(radian).approxEqual(0)); 147 } 148 149 @("opBinary Q*Q, Q/Q, Q%Q") 150 @safe pure nothrow unittest 151 { 152 auto surface = (10 * meter) * (10 * meter); 153 assert(surface.value(meter * meter).approxEqual(100)); 154 assert(surface.dimensions == meter.dimensions.pow(2)); 155 156 auto speed = (10 * meter) / (5 * second); 157 assert(speed.value(meter / second).approxEqual(2)); 158 assert(speed.dimensions == meter.dimensions / second.dimensions); 159 160 auto surfaceMod10 = surface % (10 * meter * meter); 161 assert(surfaceMod10.value(meter * meter).approxEqual(0)); 162 assert(surfaceMod10.dimensions == surface.dimensions); 163 164 assert(!__traits(compiles, meter % second)); 165 } 166 167 @("opBinary Q^^I Q^^R") 168 @safe pure nothrow unittest 169 { 170 // Operator ^^ is not available for Quantity 171 } 172 173 @("opOpAssign Q+=Q Q-=Q") 174 @safe pure nothrow unittest 175 { 176 auto time = 10 * second; 177 time += 50 * second; 178 assert(time.value(second).approxEqual(60)); 179 time -= 40 * second; 180 assert(time.value(second).approxEqual(20)); 181 } 182 183 @("opOpAssign Q*=N Q/=N Q%=N") 184 @safe pure nothrow unittest 185 { 186 auto time = 20 * second; 187 time *= 2; 188 assert(time.value(second).approxEqual(40)); 189 time /= 4; 190 assert(time.value(second).approxEqual(10)); 191 192 auto angle = 2 * radian; 193 angle += 4; 194 assert(angle.value(radian).approxEqual(6)); 195 angle -= 1; 196 assert(angle.value(radian).approxEqual(5)); 197 angle %= 2; 198 assert(angle.value(radian).approxEqual(1)); 199 200 assert(!__traits(compiles, time %= 3)); 201 } 202 203 @("opOpAssign Q*=Q Q/=Q Q%=Q") 204 @safe pure nothrow unittest 205 { 206 auto angle = 50 * radian; 207 angle *= 2 * radian; 208 assert(angle.value(radian).approxEqual(100)); 209 angle /= 2 * radian; 210 assert(angle.value(radian).approxEqual(50)); 211 angle %= 5 * radian; 212 assert(angle.value(radian).approxEqual(0)); 213 214 auto time = second; 215 assert(!__traits(compiles, time *= second)); 216 assert(!__traits(compiles, time /= second)); 217 assert(!__traits(compiles, time %= second)); 218 } 219 220 @("opEquals Q==Q Q==N") 221 @safe pure nothrow unittest 222 { 223 auto minute = 60 * second; 224 assert(minute == 60 * second); 225 assert(radian == 1); 226 227 assert(!__traits(compiles, meter == second)); 228 assert(!__traits(compiles, meter == 1)); 229 } 230 231 @("opCmp Q<Q") 232 @safe pure nothrow unittest 233 { 234 auto minute = 60 * second; 235 auto hour = 60 * minute; 236 assert(second < minute); 237 assert(minute <= minute); 238 assert(hour > minute); 239 assert(hour >= hour); 240 241 assert(!__traits(compiles, second < meter)); 242 } 243 244 @("opCmp Q<N") 245 @safe pure nothrow unittest 246 { 247 auto angle = 2 * radian; 248 assert(angle < 4); 249 assert(angle <= 2); 250 assert(angle > 1); 251 assert(angle >= 2); 252 253 assert(!__traits(compiles, meter < 1)); 254 } 255 256 @("toString") 257 unittest 258 { 259 import std.conv : text; 260 261 auto length = 12 * meter; 262 assert(length.text == "12 [L]", length.text); 263 } 264 265 @("immutable") 266 @safe pure nothrow unittest 267 { 268 immutable inch = 0.0254 * meter; 269 immutable minute = 60 * second; 270 immutable speed = inch / minute; 271 } 272 273 @("square/sqrt") 274 @safe nothrow unittest 275 { 276 auto m2 = square(3 * meter); 277 assert(m2.value(meter * meter).approxEqual(9)); 278 auto m = sqrt(m2); 279 assert(m.value(meter).approxEqual(3)); 280 } 281 282 @("cubic/cbrt") 283 @safe nothrow unittest 284 { 285 auto m3 = cubic(2 * meter); 286 assert(m3.value(meter * meter * meter).approxEqual(8)); 287 288 // Doesn't work at compile time 289 auto m = cbrt(m3); 290 assert(m.value(meter).approxEqual(2)); 291 } 292 293 @("pow/nthRoot") 294 @safe nothrow unittest 295 { 296 auto m5 = pow!5(2 * meter); 297 assert(m5.value(meter * meter * meter * meter * meter).approxEqual(2 ^^ 5)); 298 299 auto m = nthRoot!5(m5); 300 assert(m.value(meter).approxEqual(2)); 301 } 302 303 @("abs") 304 @safe nothrow unittest 305 { 306 assert(abs(-meter) == meter); 307 } 308 309 @("parseSI string") 310 unittest 311 { 312 import quantities.si; 313 314 auto resistance = parseSI("1000 m^2 kg s^-3 A^-2"); 315 assert(resistance == 1000 * ohm); 316 } 317 318 @("parseSI wstring") 319 unittest 320 { 321 import quantities.si; 322 323 auto resistance = parseSI("1000 m^2 kg s^-3 A^-2"w); 324 assert(resistance == 1000 * ohm); 325 } 326 327 @("parseSI dstring") 328 unittest 329 { 330 import quantities.si; 331 332 auto resistance = parseSI("1000 m^2 kg s^-3 A^-2"d); 333 assert(resistance == 1000 * ohm); 334 }