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 }